The Ruby on Rails framework has a lot of magic in it that automatically takes care of tedious tasks so that the developer no longer has to worry about it.

One piece of magic is the Rails autoloader. Rails will automatically load dependencies for you when you reference them. Ruby also has an autoload feature, but it must be configured by hand. In contrast, the Rails autoloader works automatically using its conventions to find the right code to load.

While preparing an earlier post, I wanted to better understand how the Rails autoloader worked. Along the way, I discovered some handy tricks that are worth sharing separately.

For a good overview of how the autoloader works, see urbanautomaton’s excellent blog post, Rails autoloading — how it works, and when it doesn’t.

The autoloader is found in the ActiveSupport::Dependencies module. This module is mostly undocumented and therefore internal and subject to change, so these debugging tools and tricks may change in the future.

There are a number of methods defined on the Dependencies module. Here’s a few that I found helpful and interesting:

  • loaded: All of the files that are currently loaded.

  • history: All files that have ever been loaded.

  • autoloaded_constants: All constant names that have been loaded. These constants will also be unloaded the next time the dependencies are cleared.

  • logger: Specify a logger to which autoloading activity should be logged. This is compatible with Ruby’s built-in Logger as well as Log4r.

  • log_activity: Turn autoloader logging on or off.

Using these methods, here’s a sample debugging session:

Sample Debugging Session
# Using a very short local variable name to save typing; not required
[1] pry(main)> d = ActiveSupport::Dependencies
=> ActiveSupport::Dependencies
[2] pry(main)> d.autoloaded_constants.include?("ApplicationController")
=> false
[3] pry(main)> d.logger =
=> #<Logger:0x00000005f9ebd8
# ...snipped...
[4] pry(main)> d.log_activity = true
=> true
# Now reference the constant I'm interested in
[5] pry(main)> ApplicationController
Dependencies: called load_missing_constant(Object, :ApplicationController)
Dependencies: called require_or_load("/vagrant/app/controllers/application_controller.rb", nil)
Dependencies: loading /vagrant/app/controllers/application_controller
Dependencies: called load_file("/vagrant/app/controllers/application_controller.rb", ["ApplicationController"])
#...lots more output snipped...
=> ApplicationController
[6] pry(main)> d.autoloaded_constants.include?("ApplicationController")
=> true

The next time you run into strange autoload behavior, give these methods a try.