Rails 3 class available to view, controller and model - ruby-on-rails

I am thinking about creating a new class that does URL shortening that can be called from the view, controller or model. Where should I put this class?

Such library should live in lib and you need to require it in file you use it or globaly in config/application.rb.

You can always dump it in config/initializers unless you'd want to package it up as an independent gem.

If you place the class in /lib don't forget to make sure that it is autoloaded. In application.rb make sure you have a line like the following:
# Custom directories with classes and modules you want to be autoloadable.
config.autoload_paths += Dir["#{config.root}/lib/**/"]

Related

Load a module from app/*/*/some_module.rb directly into the global namespace

Rails loads files from app/models/concerns and app/controllers/concerns directly into the global namespace instead of the Concerns namespace.
So if you define a module SomeConcern at app/models/concerns/some_concern.rb, instead of Concerns::SomeConcern, you have just SomeConcern available.
I would like to add a concerns folder in another subdirectory of app that behaves the same way. More specifically: I want to define SomeSerializerConcern at app/serializers/concerns/some_serializer_concern.rb, but currently it's only working if I define the module as Concerns::SomeSerializerConcern.
I have this line in config/application.rb:
config.paths.add "app/serializers/concerns", eager_load: true
This excellent post on autoload and eager_load led me to believe that this is how Rails itself accomplishes what I want to do, but it doesn't seem to work in this scenario. I'm using Rails 4.2.6. Any ideas?
Turns out this gist provides the answer.
All I needed to do was add the path directly to eager_load_paths in config/application.rb:
config.eager_load_paths += [Rails.root.join('lib'),
Rails.root.join('app', 'serializers', 'concerns')]

How can I add non-existing class to a exiting module in gem in rails

I understand that I can overwrite or to add on to a class that's already existed but I want to add additional class to an existing module(in a gem) so I can keep in constant when I call it. Cuz I though that when rails load up the lib. They should recognize it.
See following example. I would like to add the NotAcceptableHttpResponseError to the same HttpService module
Example
module HttpService (in a gem) only have a decent amounts of exceptions class and I would like to add some custom one for others
config/application.rb
config.autoload_paths += %W(#{config.root}/lib)
In the gem/exceptions.rb
module HttpService
class BadHttpResponseError
xxx
xxx
end
In lib/http_service/exceptions.rb
module HttpService
class NotAcceptableHttpResponseError
xxx
xxx
end
end
The Error
NameError(uninitialized constant HttpServices::NotAcceptableHttpResponseError)
Rails 3 does not autoload lib file
1) add this in config/application.rb:
config.autoload_paths += Dir["#{config.root}/lib/**/"]
2) Name of the folder should be the same as the module name and the name of the file should be same as the name of the class(rails naming convention should be followed)
Rename exceptions.rb to name of the class i.e., not_acceptable_http_response_error.rb
or
add in config/initializers/require.rb
require "#{Rails.root}/lib/http_service/exceptions"
Figured out the Answer. It's actually not ideal to modify module that's in the gem. since you will have to fork the project in the gem file and maintain the version if they are updated

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).

How do you include a class from /lib into your code in app/controllers

I have a class sitting in /lib folder.
It's in a file called mailing.rb
And I would like to use this class in codes from app/controller.
How do i do this?
Rails 3 no longer automatically loads the files from lib.
In your application.rb file, you can add lib to your autoload_paths:
config.autoload_paths += Dir["#{Rails.root}/lib"]
This way, your mailer.rb and all other files in lib will be available to the rest of your application.
I believe you need to add an initializer file with the require statement in it, for example if your lib file is /lib/some_module.rb you would need to create an initialiser file in /config/initializers/require_libs.rb...
# /config/initializers/require_libs.rb
require 'some_module'

Adding lib to 'config.autoload_paths' in Rails 3 does not autoload my module

I place a file name g.rb in side Rails.root/lib folder
The file content is like this:
module Google
end
Then I add
config.autoload_paths += %W(#{config.root}/lib #{Rails.root}/app/delayed_jobs)
to my Rails.root/config/application.rb
However, when I try to invoke Google from rails console, an exception is thrown. The exception goes away only if I execute require 'google'.
Why? Shouldn't my file is autoloaded and shouldn't I access the module without any extra require statement?
Hmm, I discovered an interesting thing. In order for Rails to auto load my class, the class name should be compliant to the file name and the folder structure.
For example, if I want to have Google module autoloaded, I must placed it inside google.rb, directly under /lib (incase I specify autoload from /lib).
If I want to auto load Google::Docs, then I either place it inside google.rb or google/docs.rb
I had a similar problem with getting my module to run on Heroku. In addition to the autoload naming convention stated by Stephen C, I found out that the module code must be require'd due to a threadsafe assumption made by the Rails' production environment on Heroku (even though threadsafe was commented out in my production.rb configuration file.) As soon as I require'd the module file before calling include on the module, everything started to work.
require 'mymodule'
include Mymodule
Please take a look at this excellent article on the subject of getting Modules to load correctly in Heroku (production).
That's because the point of autoload is not to 'require' everything up front (startup penalty). Classes are loaded as they are needed/referenced. In order to do this, you need some way to know where to look for the class. Otherwise, you would have to load every file in the autoload directory in advance to see what classes are declared. It's a tradeoff, but requiring everything in advance (as marbaq suggests) is not autoloading.
You can use the autoload command as provided by Ruby, which takes two arguments, the module to load (symbolized, i.e. :Google in your case), and the second argument is the filename, which would be g.rb if lib is in your load path ($:). See the Ruby docs for autoload.
Change config.autoload_paths to config.eager_load_paths
(based on Rails issue #6850 and Force reload! from lib directory in rails 3.2 console)
I faced the same problem just now, and my "solution" (or rather workaround) was to manually require every needed file from Rails.root/lib in my application.rb.
require 'lib/message'
require 'lib/store'
require 'lib/vault/vault.rb'
require 'lib/custom_loggers'
module MyApplication
class Application < Rails::Application
My next step would be to categorize the files in module folders as you mention.
i found this solution recently
config/application.rb
module AppName
class Application < Rails::Application
# Custom directories with classes and modules you want to be autoloadable.
config.autoload_paths += Dir[Rails.root.join('app', 'models', '{**}')]
config.autoload_paths += Dir[Rails.root.join('app', 'lib', 'extensions')]
end
end
the first config call induces rails to auto-load all sub-directories of the app/models directory
so now i can have /app/models/sub_directory/model.rb auto-loaded
(handy for organising an app with a large code base)
the second config call induces rails to autoload the lib/extensions directory
hope this helps
note: i believe this is rails 3 specific

Resources