jeremywoertink
jeremywoertink

Reputation: 2341

Loading class descendants in rails development

I need to be able to see all of the class descendants from a controller when I go into the rails console locally. I have this Api::BaseController which all my Api controller inherit from. The issue I have is when I hop in to the rails console to check which Api controller are in the descendants, it comes up empty until I call them. This probably has something to do with how the classes in development aren't eager loaded, and they're not cached locally.

sample_app$ rails c
Loading development environment (Rails 4.2.0)
2.1.5 :001 > Api::BaseController.descendants
 => []
2.1.5 :002 > Api::V1::FoosController
 => Api::V1::FoosController
2.1.5 :003 > Api::BaseController.descendants
 => [Api::V1::FoosController]

From this example, you can see when I call descendants on the Api::BaseController the first time, it's an empty array. After calling one of the controllers that class will be then loaded and will show up as a descendant. In this case, there could be an any number of controllers in V1 as well as V2, V3, etc...

As a stupid ugly hack, I could do

Dir.glob("#{Rails.root.join('app', 'controllers', 'api', 'v1')}/**/*.rb").each(&method(:require_dependency))

but I don't want to have to write that each time I enter the console. I'm also working on a gem, and definitely don't want to put this sort of code in my gem.

The other option is caching classes in development, but that causes a huge issues on it's own. Anyone have any ideas?

Edit Another option would be to call Rails.application.eager_load!. This option would work fine if I could specify only controllers in my API folder. Then I wouldn't have to eager load the entire app, but just a small subset of controllers that I need.

Upvotes: 10

Views: 5554

Answers (2)

Matt
Matt

Reputation: 6330

Works in Rails 5 & Rails 6:

In environments/development.rb:

Rails.application.reloader.to_prepare do
  Dir["#{Rails.root}/app/models/my_models/*.rb"].each { |file| require_dependency file }
end

This builds on u/Aguardientico's answer above.

  • If requiring files not in config.eager_load_paths you may need to add yours as described above.
  • ActionDispatch::Reloader is replaced with Rails.application.reloader (thanks to u/jean-baptiste's comment).
  • #{Rails.root} was necessary as part of my argument to Dir for this to work.

Upvotes: 3

Aguardientico
Aguardientico

Reputation: 7779

I found the following post: http://avinmathew.com/using-rails-descendants-method-in-development/

In short it says the following:

In enviroments/development.rb add the following:

config.eager_load_paths += Dir['path/to/files/*.rb']
ActionDispatch::Reloader.to_prepare do
  Dir['path/to/files/*.rb'].each {|file| require_dependency file}
end

The first line adds the path that should be loaded when you start your app (or console) and the rest tells rails to reload the classes on each request.

Upvotes: 11

Related Questions