Rails /lib modules and
There are two ways that files get loaded in Rails:
- It is registered in the autoload process, and you reference a constant that corresponds to the file name. For instance, if you have
app/controllers/pages_controller.rb
and reference PagesController,app/controllers/pages_controller.rb
will automatically be loaded. This happens for a preset list of directories in the load path. This is a feature of Rails, and is not part of the normal Ruby load process. - Files are explicitly
require
d. If a file isrequire
d, Ruby looks through the entire list of paths in your load paths, and find the first case where the file yourequire
d is in the load path. You can see the entire load path by inspecting $LOAD_PATH (an alias for $:).
Since lib
is in your load path, you have two options: either name your files with the same names as the constants, so Rails will automatically pick them up when you reference the constant in question, or explicitly require the module.
I also notice that you might be confused about another thing. ApplicationController is not the root object in the system. Observe:
module MyModule
def im_awesome
puts "#{self} is so awesome"
end
end
class ApplicationController < ActionController::Base
include MyModule
end
class AnotherClass
end
AnotherClass.new.im_awesome
# NoMethodError: undefined method `im_awesome' for #<AnotherClass:0x101208ad0>
You will need to include the module into whatever class you want to use it in.
class AnotherClass
include MyModule
end
AnotherClass.new.im_awesome
# AnotherClass is so awesome
Of course, in order to be able to include the module in the first place, you'll need to have it available (using either of the techniques above).
How to properly load lib modules and classes in Rails 5 app
No, you shouldn't resort to using require (if you want to follow Rails conventions). Rails autoloading is based on paths and namespacing, as those two things have to match up. Besides the initial problem with namespacing that was fixed, the way you modify the autoload paths is incorrect. It should be done this way:
config.autoload_paths << "#{Rails.root}/lib"
This is if you want to leave lib/
at the root of your project. As mentioned in the comments, you could move it into your app/
directory.
Accessing modules in Rails lib folder
The simplest way to solve this is by placing your files in app/lib/account_management/email_token.rb
. Rails already autoloads any subdirectory of the app folder*.
/lib
has not been on the autoload paths since Rails 3. If you want to add it to the autoload paths you need to add /lib
not /lib/account_management
to the autoload/eager loading paths. In Zeitwerk terms this adds a root where Zeitwerk will index and resolve constants from.
config.autoload_paths += config.root.join('lib')
config.eager_load_paths += config.root.join('lib')
Note that eager_load_paths is only used when eager loading is turned on. Its turned off by default in development to enable code reloading.
/lib
is added to $LOAD_PATH
so you can also manually require the file with:
require 'account_management/email_token'
See:
- Autoloading and Reloading Constants (Zeitwerk Mode)
- Rails #37835
can't include modules loaded from lib in Rails 5
What you have is a simple misunderstanding of how rails resolves module names. Adding a directory to the autoload path does not cause rails to look recursively through its subdirectories.
In order for rails to properly load the module it would have to be declared as:
# lib/surveyable/surveyable.rb
module Surveyable::Surveyable
extend ActiveSupport::Concern
end
This is because the autoloader deduces the file path based on module nesting.
Or you can move the file to lib/surveyable.rb
.
But since what you are writing seems to be a model concern I would place it in app/models/concerns
which is already added to the load path.
Why do Rails /lib modules prevent gem modules from loading?
If you open up a console (with script/console
) and examine the $LOAD_PATH
variable, you should see something resembling this:
>> $LOAD_PATH
[
# some entries...
[12] "/your/rails/root/app",
[13] "/your/rails/root/app/controllers",
[14] "/your/rails/root/app/models",
[15] "/your/rails/root/app/helpers",
[16] "/your/rails/root/lib",
# more entries...
[27] "/your/ruby/path/lib/ruby/1.8/gems/foo_blaster-0.0.1/lib"
# rest of entries
]
When you require 'foo_blaster'
(which may be done implicitly by Rails, Bundler, or perhaps some other means), Ruby searches the locations in $LOAD_PATH
sequentially until it finds the file foo_blaster.rb, loads that file, and stops. In your case, it finds the file in your application's /lib directory. The file from your gem will never be loaded.
If you want to load both files, all you have to do is give them different names and make sure to require
them both. For instance, you might rename the file in your application to foo_blaster_extensions.rb, then add an initializer to load it:
# config/initializers/extend_foo_blaster.rb
require 'foo_blaster_extensions'
Accessing module in lib directory (Ruby on rails)
In your console/controller:
include Search
zip_code_perimeter_search(zip, radius)
In case it doesn't auto-load in Rails 3, in your config/application.rb file, you can do this:
# Custom directories with classes and modules you want to be autoloadable.
config.autoload_paths += Dir["#{config.root}/lib/**/"]
How to use module in lib from controller with Rails?
I know the reason. It is necessary to add require
in the first line of the controller:
require 'a/b/c'
Rails: Loading custom class from lib folder in controller
Ruby on Rails expects certain naming conventions to support autoloading.
Rails can autoload a file located at lib/services/my_service.rb
if the model/class structure was Services::MyService
.
Change your lib/services/my_service.rb
to:
module Services
class MyService
# ...
end
end
And use that class like this in your controller:
service = Services::MyService.new
Please note that depending on your Ruby on Rails version you might need to add the lib
folder to the list of folders which are queried when looking for a file to autoload:
# add this line to your config/application.rb:
config.autoload_paths << "#{Rails.root}/lib"
Read more about autoloading in the Rails Guides.
Rails lib/module with 'class Class' and custom attr_accessor
Try to define your method attr_accessor_with_onchange_callback directly in ModelHelpers, without class Class. And use extend keyword instead include inside class defenition. Like this:
module ModelHelpers
def attr_accessor_with_onchange_callback(*args, &block)
...
require 'model_helpers'
class MyCLass < ActiveRecord::Base
extend ModelHelpers
Here is my example:
module ModelHelpers
def my_method
puts 'ModelHelpers::my_method called.'
puts "self is #{self}"
end
end
class MyCLass
extend ModelHelpers
my_method
end
And output is:
> ruby custom_method_inside_class.rb
ModelHelpers::my_method called.
self is MyCLass
Related Topics
How to Run a Rake Task from Capistrano
Understanding Ruby'S Load Paths
Aws S3: the Bucket You Are Attempting to Access Must Be Addressed Using the Specified Endpoint
How to Uninstall Ruby on Ubuntu
Open an Io Stream from a Local File or Url
Get List of a Class' Instance Methods
Ruby 2.0 Rails Gem Install Error "Cannot Load Such File - Openssl"
How to Generate a List of N Unique Random Numbers in Ruby
Understanding Private Methods in Ruby
Heroku Upload-Precompiling Assets Failed
Regex to Split Bbcode into Pieces
Unexpected Keyword_End Error, Yet Syntax Seems Fine
How to Check Whether a String Contains a Substring in Ruby
Get Names of All Files from a Folder With Ruby