---
title: "How constant lookup and resolution works in Ruby on Rails"
description:
  "Rails has its own way of maintaining constants and looking for it when it is
  not found. This blog discusses all that and much more."
canonical_url: "https://www.bigbinary.com/blog/how-constant-lookup-happens-in-rails"
markdown_url: "https://www.bigbinary.com/blog/how-constant-lookup-happens-in-rails.md"
---

# How constant lookup and resolution works in Ruby on Rails

Rails has its own way of maintaining constants and looking for it when it is not
found. This blog discusses all that and much more.

- Author: Mohit Natoo
- Published: November 5, 2015
- Categories: Rails

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

```ruby
class User
  def self.model_method
    'I am in models directory'
  end
end
```

Run `User.model_method` in rails console. It runs as expected.

Now add file `user.rb` in `lib` directory.

```ruby
class User
  def self.lib_method
    'I am in lib directory'
  end
end
```

Reload rails console and try executing `User.model_method` and
`User.lib_method`. 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.

```plaintext
import static com.googlecode.javacv.jna.highgui.cvCreateCameraCapture;
import static com.googlecode.javacv.jna.highgui.cvGrabFrame;
import static com.googlecode.javacv.jna.highgui.cvReleaseCapture;
```

In Rails we do not do that. That's because [DHH](https://twitter.com/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 `User` constant
is not loaded yet. So it needs to load `User` constant. 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 `user.rb`.

So now we know that we are looking for `user.rb` file. But the question is where
to look for that file. Rails has `autoload_path`. As 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 directories.

Open Rails console and give it a try.

```plaintext
$ rails console
Loading development environment (Rails 4.2.1)
irb(main):001:0> ActiveSupport::Dependencies.autoload_paths
=> ["/Users/nsingh/code/bigbinary-projects/wheel/app/assets",
"/Users/nsingh/code/bigbinary-projects/wheel/app/controllers",
"/Users/nsingh/code/bigbinary-projects/wheel/app/models",
"/Users/nsingh/code/bigbinary-projects/wheel/app/helpers"
.............
```

As you can see in the result one of the folders is `app/models`. When Rails
looks for file `user.rb` in `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 `User` from `lib` directory. Open `config/application.rb` and
add following code in the initialization part.

```plaintext
config.autoload_paths += ["#{Rails.root}/lib"]
```

Now exit rails console and restart it. And now lets try to execute the same
command.

```plaintext
$ rails console
Loading development environment (Rails 4.2.1)
irb(main):001:0> ActiveSupport::Dependencies.autoload_paths
=> ["/Users/nsingh/code/bigbinary-projects/wheel/app/lib",
"/Users/nsingh/code/bigbinary-projects/wheel/app/assets",
"/Users/nsingh/code/bigbinary-projects/wheel/app/controllers",
"/Users/nsingh/code/bigbinary-projects/wheel/app/models",
"/Users/nsingh/code/bigbinary-projects/wheel/app/helpers"
.............
```

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 `user.rb` in `lib` and Rails will stop looking for `user.rb`. So the end
result is that `user.rb` in `app/models` directory 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 `app/models/user.rb` file.

## 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

```ruby
%w(app/models lib).each do |directory|
  Dir.glob("#{Rails.root}/#{directory}/user.rb").each {|file| load file}
end
```

Now both `User.model_method` and `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 additional method
`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
[here](http://stackoverflow.com/questions/3170638/how-does-load-differ-from-require-in-ruby)
and [here](https://practicingruby.com/articles/ways-to-load-code) to learn about
how `load` and `require` differ.

## 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 `require_relative`

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.

```ruby
require_relative '../../lib/user'

class User
  def self.model_method
    'I am in models directory'
  end
end
```

Here `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](http://guides.rubyonrails.org/engines.html). `SaleEngine` has a model
`Sale`. However `Sale` doesn't get resolved as path for engine is neither
present in `config.autoload_paths` nor in
`ActiveSupport::Dependencies.autoload_paths`. The initialization of engine
happens in `engine.rb` file present inside `lib` directory of the engine. Let's
add a line to load `engine.rb` inside `application.rb` file.

```ruby
require_relative "../sale_engine/lib/sale_engine/engine.rb"
```

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
`SaleEngine::Engine`.

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 `app/models` would be loaded
first because the application directories have precedence. The precedence order
can be changed by following statements.

```ruby
engines = [SaleEngine::Engine] # in case there are multiple engines
config.railties_order = engines + [:main_app]
```

The symbol `: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 `railties_order`.

## Further reading

Loading of constants is a big topic and [Xavier Noria](https://twitter.com/fxn)
from Rails core team has made some excellent presentations. Here are some of
them

- [Constant Autoloading in Ruby on Rails](https://www.youtube.com/watch?v=8lYR9WxIRH0)
  Baruco 2013
- [Constants in Ruby](https://www.youtube.com/watch?v=wCyTRdtKm98) RuLu 2012
- [Class Reloading in Ruby on Rails](https://www.youtube.com/watch?v=4sIU8PxJEEk)
  RailsConf 2014

We have also made a video on
[How autoloading works in Rails](https://bigbinary.com/videos/learn-ruby-on-rails/how-autoloading-works-in-rails).

## Links

- [Human page](https://www.bigbinary.com/blog/how-constant-lookup-happens-in-rails)
