how to set rails app globally available constant - ruby-on-rails-4

I'm trying to define a global constant that I can access from anywhere in the application. For this I have created a file in initializer with this content:
APP_CONFIG = YAML.load_file(Rails.root + "config/app_config.yml").with_indifferent_access
And on a haml view I'm doing this
- if APP_CONFIG[:param]
%b HOLA MUNDO
but it says APP_CONFIG is not defined,
I tried using in both places:
##APP_CONFIG
#APP_CONFIG
$APP_CONFIG
Nothing works, I also tried with:
module MyApp
class Application
APP_CONFIG = .....
end
end
And from view:
MyApp::Application::APP_CONFIG[:param]
Also an error
uninitialized constant MyApp::Application::APP_CONFIG

You would be a lot better wrapping that up in a module. Something like this:
require 'yaml'
module AppConfig
class << self
def settings
#settings ||= hash.with_indifferent_access
end
def path
File.join(Rails.root, 'config' , 'app_config.yml')
end
def hash
YAML.load_file(path)
end
end
end
With that in place, you'll then be able to do this:
puts AppConfig.settings['foo']
With the Module you can gathering the data in a number of steps and easily test each step. It will also be easier to extend the behaviour.
And I'd put that in something like app/tools/app_config.rb

Related

Persian text in url Django

I have some links that include Persian texts, such as:
http://sample.com/fields/طب%20نظامی
And in the view function I want to access to Persian part, so:
url = request.path_info
key = re.findall('/fields/(.+)', url)[0]
But I get the following error:
IndexError at /fields/
list index out of range
Actually, the problem is with the index zero because it can not see anything there! It should be noted that it is a Django project on IIS Server and I have successfully tested it with other servers and the local server. I think it has some thing related to IIS. Moreover I have tried to slugify the url without success. I can encode urls successfully, but I think it is not the actual answer to this question.
Based on the comments:
I checked the request.path too and the same problem. It contains:
/fields/
I implemented a sample django project in local server and here is my views:
def test(request):
t = request.path
return HttpResponse(t)
The results:
http://127.0.0.1:8000/تست/
/تست/
Without any problem.
Based on the #sytech comment, I have created a middlware.py in my app directory:
from django.core.handlers.wsgi import WSGIHandler
class SimpleMiddleware(WSGIHandler):
def __call__(self, environ, start_response):
print(environ['UNENCODED_URL'])
return super().__call__(environ, start_response)
and in settings.py:
MIDDLEWARE = [
...
'apps.middleware.SimpleMiddleware',
]
But I am getting the following error:
__call__() missing 1 required positional argument: 'start_response'
Assuming you don't have another problem in your rewrite configuration, on IIS, depending on your rewrite configuration, you may need to access this through the UNENCODED_URL variable which will contain the unencoded value.
This can be demonstrated in a simple WSGI middleware:
from django.core.handlers.wsgi import WSGIHandler
class MyHandler(WSGIHandler):
def __call__(self, environ, start_response):
print(environ['UNENCODED_URL'])
return super().__call__(environ, start_response)
You would see the unencoded URL and the path part that's in Persian would be passed %D8%B7%D8%A8%2520%D9%86%D8%B8%D8%A7%D9%85%DB%8C. Which you can then decode with urllib.parse.unquote
urllib.parse.unquote('%D8%B7%D8%A8%2520%D9%86%D8%B8%D8%A7%D9%85%DB%8C')
# طب%20نظامی
If you wanted, you could use a middleware to set this as an attribute on the request object or even override the request.path_info.
You must be using URL rewrite v7.1.1980 or higher for this to work.
You could also use the UNENCODED_URL directly in the rewrite rule, but that may result in headaches with routing.
I can encode urls successfully, but I think it is not the actual answer to this question.
Yeah, that is another option, but may result in other issues like this: IIS10 URL Rewrite 2.1 double encoding issue
You can do this by using python split() method
url = "http://sample.com/fields/طب%20نظامی"
url_key = url.split(sep="/", maxsplit=4)
url_key[-1]
output : 'طب%20نظامی'
in this url is splited by / which occurs 4 time in string so it will return a list like this
['http:', '', 'sample.com', 'fields', 'طب%20نظامی']
then extract result like this url_key[-1] from url_key
you can Split the URL by :
string = http://sample.com/fields/طب%20نظامی
last_part = string. Split("/")[-1]
print(last_part)
output :< طب%20نظامی >
slugify(last_part)
or
slugify(last_part, allow_unicode=True)
I guess This Will Help You :)

How to implement DelayedJob custom job for Prawn PDF rendering?

Im trying to use DelayedJob to render Prawn PDFs. Following the custom job code in the docs, I've come up with this:
/lib/jobs/pdf_handling.rb
RenderPdf = Struct.new( :id, :view_context ) do
def perform
user = User(id)
pdf = UserFolder.new( id, view_context )
name = "user_folder_report.pdf"
send_data pdf.render, filename: name, type: "application/pdf"
end
end
PagesController.rb
def user_folder
respond_to do |format|
format.pdf do
Delayed::Job.enqueue RenderPdf.new(#user, view_context)
end
end
end
this results in the error:
uninitialized constant PagesController::RenderPdf
Adding required RenderPdf at the top of the PagesController doesn't help.
What am I missing? How can I implement this so PDF generation occurs via DelayedJob? Thanks.
updates
When /jobs is moved under /apps the error changes to:
can't dump anonymous module: #<Module:0x007fca7a3ae638>
/application.rb
config.autoload_paths += Dir["#{config.root}/lib/assets/"]
updates
I changed
class RenderFolder < Struct.new( :type, :rating_id, :dis, :view_context )
def perform
to
class RenderFolder < ActiveJob::Base
def perform(...)
Then, using ActiveJob, you can do
RenderFolder.perform_later(...)
This seems to be working...Im still implementing.
the lib folder is no longer loaded by default in rails. you can either add it to the autoload_path or (what i would do) just have it in some app/xxx folder. typically, i have app/support or something for arbitrary utility classes.

Rails: testing custom classes with RSpec

Yea, I know that this question is silly, newbee and simple, but I still can't figure it out.
I've created a class (in app/minions/ directory) to parse auth hashes from 3rd-party services (like google, twitter, etc.). It looks like this.
class AuthHash
def initialize(hash)
#hash = hash
#provider = hash[:provider]
#uid = hash[:uid]
create_user_hash
end
def create_user_hash
#user_hash = send("parse_hash_from_" << #hash[:provider], #hash)
end
def credentials
{provider: #provider, uid: #uid}
end
def user_hash
#user_hash
end
private
# parse_hash_from_* methods here
end
I've added that directory to the autoload path, so I can use it in my controllers. Now I want to write some tests for it.
I'm using RSpec with FactoryGirl for testing. So I started by adding a factory to spec/factories/ called auth_hashes.rb but I can't define a hash as a field in a factory.
So I moved the declaration to the spec/minions/auth_hash_spec.rb.
require 'spec_helper'
describe AuthHash do
before_each do
auth_hash = AuthHash.new({:provider=>"google_oauth2",:uid=>"123456789",:info=>{:name=>"JohnDoe",:email=>"john#company_name.com",:first_name=>"John",:last_name=>"Doe",:image=>"https://lh3.googleusercontent.com/url/photo.jpg"},:credentials=>{:token=>"token",:refresh_token=>"another_token",:expires_at=>1354920555,:expires=>true},:extra=>{:raw_info=>{:id=>"123456789",:email=>"user#domain.example.com",:verified_email=>true,:name=>"JohnDoe",:given_name=>"John",:family_name=>"Doe",:link=>"https://plus.google.com/123456789",:picture=>"https://lh3.googleusercontent.com/url/photo.jpg",:gender=>"male",:birthday=>"0000-06-25",:locale=>"en",:hd=>"company_name.com"}}})
end
end
But still it does not seem to work.
I know this should be alot simpler then I'm trying to do, but I can't figure it out.
Add something like this to that new spec (spec/minions/auth_hash_spec.rb) file at the top:
require Rails.root.to_s + '/app/minions/myhash.rb'
And then write your tests.

Minitest - test class in Rails 4

I am trying to use Minitest in a fresh Rails 4 install. My understanding is that if I have a class that doesn't inherit from ActiveRecord then I should be able to use Minitest itself, without Rails integration:
#test/models/blog.rb
require "minitest/autorun"
class Blog < Minitest::Unit::TestCase
def setup
#b = Blog.new
end
def test_entries
assert_empty "message", #b.entries
end
#app/models/blog.rb
class Blog
attr_reader :entries
def initialize
#entries = []
end
I run the test with ruby test/models/blog.rb.
My problem comes with the setup method. If I don't include an entry for my blog, the tests fails with the message that there are the wrong number of arguments in setup. If I include an entry in my setup message #b = Blog.new entries: "Twilight", my test fails in the test_entries method because entries is an undefined method.
You have a couple problems. First, you are not requiring "test_helper", which means that rails isn't getting loaded when you run this test, which means that the mechanism rails uses to resolve missing constants isn't loaded. You will either need to require the helper or require the blog file directly. Second, you are overwriting the constant you want to test with the test, which is why you are getting confusing messages. Name the test class BlogTest instead to avoid this.
This is what I think you are trying to do:
require "minitest/autorun"
require "models/blog" # Assuming "app" is in your load path when running the test
#require "test_helper" # Or require this instead if you need to use DB
class BlogTest < Minitest::Unit::TestCase
def setup
#b = Blog.new
end
def test_entries
assert_empty #b.entries, "Blog entries should be empty"
end
end

path apps in django

I wanna get absolute path all installed_apps in "setting.py" .
app_list = [ app for app in Myproject.settings.INSTALLED_APPS ]
I list of application but how i can get absolute path all of them.
Thank you.
It's not really possible to do what you want. I mean you can get almost there, but there's no real functionality for this, and in particular, Python doesn't distinguish between classes, methods, and variables. They all count as attributes of the module.
First, INSTALLED_APPS is a tuple of strings. So, in order to get any useful information, you're going to have load them as modules:
for app in settings.INSTALLED_APPS:
module = __import__(app)
Then, once you have the actual module, you can call dir on it to get a list of its attributes:
for app in settings.INSTALLED_APPS:
module = __import__(app)
print dir(module)
And, that's about as far as you can go. It's going to output everything set in the module, not just classes. From here, about the only recourse I can think of to weed out everything but classes is to assume that naming conventions were followed and look for items that start with a capital letter. That's not exactly scientific, but that's all you got.
Today I solved my problem. I write this code and its just working. For limited name class I find name of class that inherent from "models.Model" . you can change it and enjoy that.also this code find files in depth 1 of modules. it can change.
app_list = [app for app in training.settings.INSTALLED_APPS if "task" in app]
for module in app_list:
module1 = __import__(module)
temp = module1.__path__
files_path = [temp[0] + os.sep + files_name for files_name in os.listdir(temp[0]) if
os.path.splitext(files_name)[1] == ".py"]
p = re.compile(r'class\s*\w*\s*\(models.Model\):')
for file in files_path:
infile = open(file)
text = infile.read()
all_class = p.findall(text)
print [class_name[6:][:-15] for class_name in all_class]