When a Rails application involving multiple gems, engines etc. are built then it’s important to know how constants are looked up and resolved.
Consider a brand new Rails app with model
User.model_method in rails console. It runs as expected.
Now add file
Reload rails console and try executing
You will notice that
User.model_method gets executed and
User.lib_method doesn’t. Why is that?
In Rails we do not import files
If you have worked in other programming languages like Python or Java then in your file you must have statements to import other files. The code might look like this.
In Rails we do not do that. That’s because DHH does not like the idea of opening a file and seeing the top of the file littered with import statements. He likes to see his files beautiful.
Since we do not import file then how does it work?
In Rails console when user types
User then rails detects that
constant is not loaded yet.
So it needs to load
However in order to do that it has to load a file.
What should be the
name of the file. Here is what Rails does.
Since the constant name is
User Rails says that I’m going to look for file
So now we know that we are looking for
user.rb file. But the
question is where to look for that file. Rails has
the name suggests this is a list of paths from where files are
automatically loaded. Rails will search for
user.rb in this list of
Open Rails console and give it a try.
As you can see in the result one of the folders is
Rails looks for file
app/models then Rails will find it
and it will load that file.
That’s how Rails loads
User in Rails console.
Adding lib to the autoload path
Let’s try to load
config/application.rb and add following code in the
Now exit rails console and restart it. And now lets try to execute the same command.
Here you can see that
lib directory has been added at the very top.
Rails goes from top to bottom while looking for
user.rb file. In this
case Rails will find
lib and Rails will stop looking for
user.rb. So the end result is that
would not even get loaded as if it never existed.
Enhancing a model
Here we are trying to add an extra method to
User model. If we stick
our file in
lib then our
user.rb is never loaded because Rails will
never look for anything in
lib by default. If we ask Rails to look in
lib then Rails will not load file from
app/models because the file
is already loaded. So how do we enhance a model without sticking code in
Introducing initializer to load files from model and lib directories
We need some way to load
User from both models and lib directories.
This can be done by adding an
initializer to config/initializers directory with following code snippet
User.lib_method get executed as expected.
In the above case when first time
user.rb is loaded then constant
User gets defined. Second time ruby understands that constant is
already defined so it does not bother defining it again. However it adds
lib_method to the constant.
In that above case if we replace
load file with
require file then
User.lib_method will not work. That is because
require will not load
a file if a constant is already defined. Read
to learn about how
Using ‘require_relative’ in model
Another approach of solving this issue is by using
require_relative inside model.
require_relative loads the file
present in the path that is relative to the file where the statement is called in. The desired file to be loaded is given
as an argument to
In our example, to have
User.lib_method successfully executed, we need to load the
lib/user.rb. Adding the following code
in the beginning of the model file
user.rb should solve the problem. This is how
app/models/user.rb will now look like.
require_relative upon getting executed will first initialize the constant
User from lib directory.
What follows next is opening of the same class
User that has been initialized already and addition of
model_method to it.
Handling priorities between Engine and App
In one of the projects we are using engines.
SaleEngine has a model
Sale doesn’t get resolved as
path for engine is neither present in
config.autoload_paths nor in
The initialization of engine happens in
engine.rb file present inside
lib directory of the engine.
Let’s add a line to load
In Rails console if we try to see autoload path then we will see that
lib/sale_engine is present there. That means we can now use
Now any file we add in
sale_engine directory would be loaded. However
if we add
user.rb here then the
user.rb mentioned in
would be loaded first because the application directories have
precedence. The precedence order can be changed by following statements.
:main_app refers to the application where the server comes up. After adding the above code, you will see that
the output of
ActiveSupport::Dependencies now shows the directories of engines first (in the order in which they have been
given) and then those of the application. Hence for any class which is common between your app and engine, the one from
engine will now start getting resolved. You can experiment by adding multiple engines and changing the
Loading of constants is a big topic and Xavier Noria from Rails core team has made some excellent presentations. Here are some of them
- Constant Autoloading in Ruby on Rails Baruco 2013
- Constants in Ruby RuLu 2012
- Class Reloading in Ruby on Rails RailsConf 2014
We have also made a video on How autoloading works in Rails.