Is there a way to get a collection of all the Models in your Rails app? Is there a way to get a collection of all the Models in your Rails app? ruby-on-rails ruby-on-rails

Is there a way to get a collection of all the Models in your Rails app?


The whole answer for Rails 3, 4 and 5 is:

If cache_classes is off (by default it's off in development, but on in production):

Rails.application.eager_load!

Then:

ActiveRecord::Base.descendants

This makes sure all models in your application, regardless of where they are, are loaded, and any gems you are using which provide models are also loaded.

This should also work on classes that inherit from ActiveRecord::Base, like ApplicationRecord in Rails 5, and return only that subtree of descendants:

ApplicationRecord.descendants

If you'd like to know more about how this is done, check out ActiveSupport::DescendantsTracker.


Just in case anyone stumbles on this one, I've got another solution, not relying on dir reading or extending the Class class...

ActiveRecord::Base.send :subclasses

This will return an array of classes. So you can then do

ActiveRecord::Base.send(:subclasses).map(&:name)


EDIT: Look at the comments and other answers. There are smarter answers than this one! Or try to improve this one as community wiki.

Models do not register themselves to a master object, so no, Rails does not have the list of models.

But you could still look in the content of the models directory of your application...

Dir.foreach("#{RAILS_ROOT}/app/models") do |model_path|  # ...end

EDIT: Another (wild) idea would be to use Ruby reflection to search for every classes that extends ActiveRecord::Base. Don't know how you can list all the classes though...

EDIT: Just for fun, I found a way to list all classes

Module.constants.select { |c| (eval c).is_a? Class }

EDIT: Finally succeeded in listing all models without looking at directories

Module.constants.select do |constant_name|  constant = eval constant_name  if not constant.nil? and constant.is_a? Class and constant.superclass == ActiveRecord::Base    constant  endend

If you want to handle derived class too, then you will need to test the whole superclass chain. I did it by adding a method to the Class class:

class Class  def extend?(klass)    not superclass.nil? and ( superclass == klass or superclass.extend? klass )  endenddef models   Module.constants.select do |constant_name|    constant = eval constant_name    if not constant.nil? and constant.is_a? Class and constant.extend? ActiveRecord::Base    constant    end  endend