Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I iterate through all of the Models in my rails app?

I would like to be able to iterate over and inspect all the models in my rails app. In pseudo-code it would look something like:

rails_env.models.each do |model|  
  associations = model.reflect_on_all_associations(:has_many)  
  ... do some stuff  
end

My question is how do I inspect my rails app to get a collection of the models (rails_env.models) ?

like image 529
James Avatar asked May 01 '10 23:05

James


5 Answers

If you are looking at ApplicationRecord models only in a modern Rails application, you can just use

ApplicationRecord.descendants

Here you can have a look at it : http://apidock.com/rails/Class/descendants

like image 197
giglemad Avatar answered Nov 05 '22 07:11

giglemad


Similar to nathanvda's response, use camelize rather than capitalize to support model files with underscores, and use String#constantize rather than Kernel.const_get.

Additionally, if you keep non-activerecord models in your models folder (e.g. a search class for consolidating search logic), you'll want to check the class is an active record model.

Dir[Rails.root.join('app/models/*.rb').to_s].each do |filename|
  klass = File.basename(filename, '.rb').camelize.constantize
  next unless klass.ancestors.include?(ActiveRecord::Base)
  next if klass.abstract_class?
  # do something with klass
end
like image 40
Kieran Pilkington Avatar answered Nov 05 '22 08:11

Kieran Pilkington


I tried implementing the above solutions under Rails 5 and they didn't quite work. Here's a solution which finds all models which starts with "page_" (or any other prefix; just specify that):

def self.page_models(prefix = "page")
    models = []
    folder = File.join(Rails.root, "app", "models")
    Dir[File.join(folder, "*")].each do |filename|
     if filename =~ /models\/#{prefix}/
       klass = File.basename(filename, '.rb').camelize.constantize
       models << klass
     end
    end
    return models
end
like image 38
fuzzygroup Avatar answered Nov 05 '22 06:11

fuzzygroup


Iterate over all files in `$RAILS_ROOT\app\models' ?

For instance

def find_all_models
  # iterate over all files in folder
  folder = File.join(RAILS_ROOT, "app", "models")      
  Dir[File.join(folder, "*")].each do |filename|
    # remove .rb
    model_name = File.basename(filename).sub(/.rb$/, '').capitalize
    model = Kernel.const_get(model_name)
    # .. do something with your model :)
  end
end

Does this help?

like image 2
nathanvda Avatar answered Nov 05 '22 08:11

nathanvda


Rails Admin uses this code (see https://github.com/sferik/rails_admin/blob/master/lib/rails_admin/config.rb, method viable_models):

([Rails.application] + Rails::Engine.subclasses.collect(&:instance)).flat_map do |app|
          (app.paths['app/models'].to_a + app.config.autoload_paths).collect do |load_path|
            Dir.glob(app.root.join(load_path)).collect do |load_dir|
              Dir.glob(load_dir + '/**/*.rb').collect do |filename|
                # app/models/module/class.rb => module/class.rb => module/class => Module::Class
                lchomp(filename, "#{app.root.join(load_dir)}/").chomp('.rb').camelize
              end
            end
          end
        end.flatten.reject { |m| m.starts_with?('Concerns::') }

The advantage being that it loads models in associated engines, not just in your current app.

like image 1
Daniel Avatar answered Nov 05 '22 08:11

Daniel