Rails: Where to define constants with Classes? - ruby-on-rails

I have a constant that is based on classes I define in lib:
ALL_DEMOGRAPHICS = [Demographic::Gender,
Demographic::Age]
I tried putting them in config/initializers, but they would get cached and not update even when I saved a new version of the class/file.
Where should I put this constant?

I tried putting them in config/initializers, but they would get cached and not update even when I saved a new version of the class/file.
You could define them in a module. Create a file called global_constants.rb in your models directory and add constants there:
app/models/global_constants.rb
module GlobalConstants
ALL_DEMOGRAPHICS = [Demographic::Gender, Demographic::Age]
end
Then you can use the constants like so:
GlobalConstants::ALL_DEMOGRAPHICS
If you keep the module in lib folder, then make sure you have added lib to autoload:
config/application.rb
config.autoload_paths << Rails.root.join('lib')

Related

How required my class to Rails

I have my class which is in file.rb I want to require this class in my project, I put this file into project/lib but when I call create new object, rails raises an error. You class absent. May be I not right assigned my file?
In config/application.rb around line 14 you have something like
# Custom directories with classes and modules you want to be autoloadable.
# config.autoload_paths += %W(#{config.root}/lib)
uncomment and eventually edit the second of those lines.
files in your lib folder are not auto-required. You have to put the requirement into an initializer (just check some of the existing initializers to see how to do it).

Rails Module/Folder Naming Convention

I'm having a problem with a module name and the folder structure.
I have a model defined as
module API
module RESTv2
class User
end
end
end
The folder structure looks like
models/api/restv2/user.rb
When trying to access the class, I get an uninitialized constant error. However, if I change the module name to REST and the folder to /rest, I don't get the error.
I assume the problem has to do with the naming of the folder, and I've tried all different combos of /rest_v_2, /rest_v2, /restv_2, etc.
Any suggestions?
Rails uses the 'underscore' method on a module or class name to try and figure out what file to load when it comes across a constant it doesn't know yet. When you run your module through this method, it doesn't seem to give the most intuitive result:
"RESTv2".underscore
# => "res_tv2"
I'm not sure why underscore makes this choice, but I bet renaming your module dir to the above would fix your issue (though I think I'd prefer just renaming it to "RestV2 or RESTV2 so the directory name is sane).
You'll need to configure Rails to autoload in the subdirectories of the app/model directory. Put this in your config/application.rb:
config.autoload_paths += Dir["#{config.root}/app/models/**/"]
Then you should be able to autoload those files.
Also, your likely filename will have to be app/model/api/res_tv2/user.rb, as Rails uses String.underscore to determine the filename. I'd just call it API::V2::User to avoid headaches, unless you have more than one type of API.

How to instantiate a class from a different folder structure (Rails)

Using Rails 3.2 and ruby 1.9.3p0
I am trying out the gem delayed_job. I have created a file lib/mailing_job.rb in which I have class MailingJob.
In a controller under app/controllers/requests_controller.rb I am calling
job = MailingJob.new(#request)
but this is returning the error
uninitialized constant RequestsController::MailingJob
I think it is because I need a proper way of referencing a class under a different folder structure.
Any idea how I can isntantiate class MailingJob from a different file (class) in a different folder?
Rails 3 does not include the lib folder within the load path so your application does not know how to find the class.
You can modify config/application.rb and add a line to instruct rails to also look in the lib folder like so
config.autoload_paths += %W(#{config.root}/lib)
In an initializer (e.g. config/initializers/delayed_job.rb), do this (doesnt matter where)
require 'mailing_job'

Rails load path questions

Say I have some custom classes that don't belong in models, controllers etc, I should put this in /lib correct?
In rails < 3 I would add this directory to my loadpath and in rails 3+ I would add this to my autoload_path. Is this correct?
Now say I have some classes that extends already defined classes. Where should I put this so its run on startup. Forexample say I want to add the method 'foo' on String.
class String
def foo
'foo;
end
end
Where should I put this class so it's defined on startup?
Another weird bug I have is when I try to namespace classes in lib.
module MyProject
class Foo
end
end
Now in a console:
ruby-1.9.2-p136 :004 > MyProject::Foo
LoadError: Expected /Users/me/workspace/my_project/lib/foo.rb to define Foo
from /Users/rob/.rvm/gems/ruby-1.9.2-p136/gems/activesupport-3.0.3/lib/active_support/dependencies.rb:492:in `load_missing_constant'
from /Users/rob/.rvm/gems/ruby-1.9.2-p136/gems/activesupport-3.0.3/lib/active_support/dependencies.rb:183:in `block in const_missing'
I keep getting this error. How can I load this file?
In rails 3, the autoload path is disabled in the config/application.rb
#config.autoload_paths += %W(#{config.root}/extras)
You have to de-comment this line if you want to load code from lib dir.
You can generally put the class files wherever you want, for example you could put them in app/others and add the directory to your load_path in Rails 2 or autoload_path in Rails 3.
To extend already defined classes you'll probably want to put the files in your config/initializers directory.
To fix the bug you mention you should probably define the Foo class in your foo.rb file, and make sure that the module names match up (Bags and MyProject).
The reason the name was changed to autoload is that the classes in autoload_paths are actually getting autoloaded, not simply loaded. This is the difference between using 'autoload' and 'require' in Ruby.

Where is the best place to extend the functionality of built in classes in Rails?

I have a few methods I am adding to Ruby's Array class for my Rails application. Where is the best place to put them?
Right now I have them in config/environment.rb.
config/environment.rb isn't really the best place, since you can run into serious load ordering-problems if try to extend classes that haven't been resolved at the time environment.rb is executed.
Better to put a file into config/initializers. Any script placed there will be executed after the rails runtime is loaded.
What you could do is to create a file lib/my_extensions.rb
module MyExtensions
end
then in lib/my_extensions/array.rb :
module MyExtensions::Array
def join_with_commas
join(", ")
end
end
and in config/initializers/load_my_extensions.rb
class Array
include MyExtensions::Array
end
This will cause MyExtensions::Array to be auto-reloaded each time you invoke a request in development mode. This is nicer than restarting your application everytime you make a change to your code.
It would probably be cleaner to add a lib/ directory with all your extensions. Then add a line in config/environment.rb that loads the file:
require File.join(RAILS_ROOT, 'lib', 'array.rb')

Resources