Sapan Diwakar

Software developer

Follow me on Twitter Check out my code on GitHub View some of my designs on Dribbble Take a look at my Linked In profile

Eager Load Rails classes during development

Rails 6 comes with Zeitwerk as the new default loader. For most users, when upgrading from the previous version of Rails, not much would change (except some inflections because of the way zeitwerk infers file names based on the constant).

For people using Single-Table-Inheritance, Rails upgrade guide already provides a drop in script that can be used to eager load STI classes by reading the type column in the DB.

But if you rely on descendants to find out STI classes (e.g. for displaying a selector on the UI), you will notice that descendants doesn't discover all classes during development. One easy workaround is to enable eager_load directly in config/development.rb. This works but will slow down the initial start of the project considerably and you will notice that it still doesn't work with auto-reload. A better way is to use eager_load_paths combined with ActiveSupport::Reloader's to_prepare hook inside development.rb.

config.eager_load_paths += Dir["app/models/stimodel/**/*.rb"]  
ActiveSupport::Reloader.to_prepare do  
  Dir["app/models/stimodel/**/*.rb"].each { |f| require_dependency("#{Dir.pwd}/#{f}") }
end  

Adding your paths to eager_load_paths make sure that Rails loads them when it starts up. To make sure that Rails reloads our models if we do any changes or add new files, we also need to hook into the Reloader's to_prepare hook and manually require the dependency there.

Don't get tripped with the require_dependency because Rails 6 changelog mentioned that all known use cases of require_dependency were eliminated. Of course, with the default lazy loading approach that Rails provides, we don't need require_dependency in our code anymore. But this is an advanced usage where we are asking it manually to eager load that dependency so it is still required here.