237

Is there a way that you can get a collection of all of the Models in your Rails app?

Basically, can I do the likes of: -

Models.each do |model|
  puts model.class.name
end
tronerta
  • 432
  • 6
  • 12
mr_urf
  • 3,303
  • 4
  • 26
  • 29
  • 1
    If you need to collect all models including models of Rails engines/railties, see the answer by [@jaime](http://stackoverflow.com/questions/516579/is-there-a-way-to-get-a-collection-of-all-the-models-in-your-rails-app/4598129#4598129) – Andrei Feb 18 '11 at 11:21
  • Doesn't work on rails 5.1 – aks Mar 02 '18 at 15:06

29 Answers29

440

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.

sj26
  • 6,725
  • 2
  • 27
  • 24
  • 34
    Awesome! This should be the accepted answer. For anybody using this in a rake task: Make your task depend on `:environment` for the `eager_load!` to work. – Jo Liss Aug 17 '12 at 21:06
  • 1
    Or, as a slightly faster alternative to `Rails.application.eager_load!`, you can just load the models: `Dir.glob(Rails.root.join('app/models/*')).each do |x| require x end` – Ajedi32 Aug 29 '12 at 18:54
  • I agree with Jo Liss: this should be the top answer! 2 lines instead of 14 is 7 times more awesome. – Joe Goggins Sep 20 '12 at 15:18
  • 5
    @Ajedi32 that is not complete, models can be defined outside those directories, especially when using engines with models. Slightly better, at least glob all `Rails.paths["app/models"].existent` directories. Eager loading the whole application is a more complete answer and will make sure there is absolutely nowhere left for models to be defined. – sj26 Nov 30 '12 at 03:46
  • Definitely the Rails 3 answer :] Great job. – rcd Mar 14 '13 at 03:24
  • Added another answer to a similar, but what feels like a better targeted question at which may actually get accepted: http://stackoverflow.com/q/5236932/15585 – deterb Mar 14 '13 at 18:39
  • 2
    I got what sj26 means but maybe there is a little mistake: as far as I know in development environment cache_classes is off (false) that's why you need to manually eager load the application to access all models. [explained here](http://guides.rubyonrails.org/v3.2.13/configuring.html) – masciugo Oct 17 '13 at 09:04
  • 3
    @Ajedi32 again, not the complete answer. If you want to eager load only models then try: `Rails.application.paths["app/models"].eager_load!` – sj26 Oct 29 '13 at 06:19
  • @sj26 Is absolutely right. For large apps, "edge cases" and guessing become major headaches and wrong answers. –  Mar 09 '14 at 00:05
  • I agree this should be the answer. Here's the one liner I used for my purposes: `(Rails.application.eager_load!) && (ActiveRecord::Base.descendants.map {|klass| [klass.name, klass.count]})` – ianstarz Dec 03 '14 at 18:32
  • 1
    ActiveRecord::Base.descendants.map(&:name) this has helped me get the named spaced Model Names – User128848244 Jan 30 '15 at 20:19
  • config.eager_load = true – shadowbq Feb 09 '16 at 21:03
  • What about in Rails 5 where all models will inherit from ApplicationRecord? – Marklar Nov 23 '16 at 10:23
  • 1
    `ApplicationRecord` still inherits `ActiveRecord::Base` so `ActiveRecord::Base.descendants` still works, but you can also use `ApplicationRecord.descendants` for only descendants of `ApplicationRecord`, too. – sj26 Nov 28 '16 at 22:42
  • It shouldn't depend on the environment but on the cache_classes flag: `Rails.application.eager_load! unless Rails.application.config.cache_classes` – gtournie Mar 14 '17 at 23:53
  • That's what the answer says? "**If cache_classes is off** (by default it's off in development, but on in production)" (the environment is just a hint). – sj26 Mar 16 '17 at 01:32
  • I tried this but one of the models is missing from result... (even it extends ApplicationRecord) – ypresto Jul 18 '17 at 13:58
  • Be careful though, this may also return ActiveRecord::SchemaMigration when it exists. It also doesn't seem to be loaded by eager_load. – Ibrahim Tencer Jul 08 '19 at 18:52
  • 2
    @IbrahimTencer to ignore the schema migrations model and only return your application's models then you might like to use `ApplicationRecord.descendants` :-) – sj26 Jul 10 '19 at 05:20
  • Should be recommended answer – pixelpax Nov 09 '22 at 18:27
123

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)
boulder_ruby
  • 38,457
  • 9
  • 79
  • 100
kikito
  • 51,734
  • 32
  • 149
  • 189
  • 9
    why don't you use `ActiveRecord::Base.subclasses` but have to use `send`? Also, it seems like you have to "touch" the model before it will show up, for example `c = Category.new` and it will show up. Otherwise, it won't. – nonopolarity Sep 06 '10 at 15:12
  • I don't remember why I used send anymore, but probably there was a reason. Maybe on the rails version I was using at the time subclasses was private. You were right about the "having to touch" part. – kikito Feb 10 '11 at 00:17
  • 53
    In Rails 3, this has been changed to `ActiveRecord::Base.descendants` – Tobias Cohen Feb 16 '11 at 04:19
  • 3
    You have to use "send" because the :subclasses member is protected. – Kevin Rood Apr 01 '11 at 18:53
  • Thank you so much! That saved my bacon that tip. – Chris Jun 23 '11 at 03:35
  • 11
    Thanks for the Rails 3 tip. For anyone else who comes along, you still need to "touch" the models before `ActiveRecord::Base.descendants` will list them. – nfm Jul 03 '11 at 01:18
  • For rails 2.3.x, this seems a reliable approach over the list of tables. list of tables returns schame_migrations tables as well, which is not a model, and also it does not include STI models. – so_mv Dec 11 '11 at 21:02
  • 3
    Technically in Rails 3 you have subclasses *and* descendants, they mean different things. – sj26 May 17 '12 at 05:03
104

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
  end
end

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 )
  end
end

def 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
  end
end
Vincent Robert
  • 35,564
  • 14
  • 82
  • 119
  • Funnily enough, I went the other way round on this! I started looking at reflections but couldn't figure out how to get the list of classes either! Just after I posted I had a headslap moment and went off to look at Dir. Thanks for the answer. Much appreciated. – mr_urf Feb 05 '09 at 16:24
  • Wow! Kudos earned and then some! Thanks for this, I went with the Dir suggestion and ended up having to scan, strip and capitalize! the resulting file name. However I think that your solution is much more elegant so I'll use this instead. If I could vote you up again, I would! :) – mr_urf Feb 06 '09 at 09:53
  • 6
    FYI, I timed both methods just for fun. Looking up the directories is an order of magnitude faster than searching though the classes. That was probably obvious, but now you know :) – Edward Anderson Jun 12 '10 at 14:25
  • 9
    Also, it's important to note that searching for models via the constants methods will not include anything that hasn't been referenced since the app started, since it only loads the models on demand. – Edward Anderson Jun 12 '10 at 14:27
  • I think there has got to be a better way than to use the filenames in a directory. When we use a model, Rails know it is valid or not, so the info must be kept some where. – nonopolarity Sep 06 '10 at 15:21
  • 4
    I prefer 'Kernel.const_get constant_name' to 'eval constant_name'. – Jeremy Weathers Nov 27 '10 at 18:48
  • There is build in `kind_of?` method that does exactly what your `extend?` does. – artemave Mar 16 '11 at 10:28
  • 4
    `RAILS_ROOT` is no longer available in Rails 3. Instead, use `Dir.glob(Rails.root.join('app/models/*'))` – fanaugen May 16 '12 at 10:50
  • 1
    Actually, the models do register themselves as descendants of `ActiveRecord::Base` now, so if you eager load all models then you can iterate them easily—see my answer below. – sj26 Aug 20 '12 at 09:52
  • Not quite, @artemave - only _instances_ of the class will be a `kind_of` the superclass. – PJSCopeland Dec 22 '14 at 22:10
  • `and` `not` are terrible choice for logical operators. They sound like they are logical operators but they are not. Please don't use them in boolean operations. use rather `&&`, `!` http://stackoverflow.com/questions/1426826/difference-between-and-and-in-ruby – equivalent8 May 28 '15 at 13:51
  • in case of `class MyConstant < ActiveRecord::Base` don't compare `MyConstant.superclass == ActiveRecord::Base` as that is just checking direct ancestor. So For example in case of STI `MyAnother < MyConstant` the sperclass is `MyConstant` therefore you will miss this model to avoid this check rather entire ancestor tree `MyConstant.ancestors.include?(ActiveRecord::Base)` – equivalent8 May 28 '15 at 14:14
  • the first one is the best for me because I have namespaced models. – Yakob Ubaidi Jan 23 '18 at 15:06
76
ActiveRecord::Base.connection.tables.map do |model|
  model.capitalize.singularize.camelize
end

will return

["Article", "MenuItem", "Post", "ZebraStripePerson"]

Additional information If you want to call a method on the object name without model:string unknown method or variable errors use this

model.classify.constantize.attribute_names
Conor
  • 494
  • 6
  • 15
lightyrs
  • 2,809
  • 2
  • 29
  • 32
  • 8
    This will get you all the tables though, not just the models, since some tables don't always have associated models. – courtsimas Mar 29 '12 at 21:25
  • This answer should be considered incorrect as it is feasible (and common in legacy setups) to configure the name of the table to be something other than pluralized name of the model. [This answer](http://stackoverflow.com/a/36277614/476712) gives the correct answer even when the setup deviates from the default configuration. – lorefnon May 22 '16 at 11:18
  • in some cases this works better than `ActiveRecord::Base.send :subclasses` - looking for the table names is a good idea. Automatically generating the model names might be problematic as lorefnon mentioned. – Tilo Apr 13 '17 at 15:02
  • 1
    `.capitalize.singularize.camelize` can be replaced to `.classify`. – Maxim Apr 23 '17 at 18:46
41

For Rails5 models are now subclasses of ApplicationRecord so to get list of all models in your app you do:

ApplicationRecord.descendants.collect { |type| type.name }

Or shorter:

ApplicationRecord.descendants.collect(&:name)

If you are in dev mode, you will need to eager load models before:

Rails.application.eager_load!
Nimir
  • 5,727
  • 1
  • 26
  • 34
  • 1
    I take it that this would require that classes are already loaded and would give incomplete results in development environment with autoloading enabled. I will not downvote but perhaps this should be mentioned in the answer. – lorefnon May 22 '16 at 11:14
  • fare enough, updating – Nimir May 22 '16 at 11:22
  • 1
    I'm on Rails 6.0.2 and the eager_load! didn't make the descendants method to return anything but an empty array. – jgomo3 Feb 17 '20 at 12:16
  • Great, this work with mongodb as well as those activerecord. – PKul Jan 28 '22 at 11:31
34

I looked for ways to do this and ended up choosing this way:

in the controller:
    @data_tables = ActiveRecord::Base.connection.tables

in the view:
  <% @data_tables.each do |dt|  %>
  <br>
  <%= dt %>
  <% end %>
  <br>

source: http://portfo.li/rails/348561-how-can-one-list-all-database-tables-from-one-project

jaime
  • 927
  • 8
  • 13
  • 1
    This is the only way I can get ALL models, including models of Rails engines used in the app. Thanks for the tip! – Andrei Feb 18 '11 at 11:18
  • 2
    A few useful methods: `ActiveRecord::Base.connection.tables.each{|t| begin puts "%s: %d" % [t.humanize, t.classify.constantize.count] rescue nil end}` Some of the models may be not activated therefore you need to rescue it. – Andrei Feb 18 '11 at 11:47
  • 2
    Adapting @Andrei's a bit: `model_classes = ActiveRecord::Base.connection.tables.collect{|t| t.classify.constantize rescue nil }.compact` – Max Williams Jun 17 '11 at 09:59
23

I think @hnovick's solution is a cool one if you dont have table-less models. This solution would work in development mode as well

My approach is subtly different though -

ActiveRecord::Base.connection.tables.map{|x|x.classify.safe_constantize}.compact

classify is well supposed to give you the name of the class from a string properly. safe_constantize ensures that you can turn it into a class safely without throwing an exception. This is needed in case you have database tables which are not models. compact so that any nils in the enumeration are removed.

Aditya Sanghi
  • 13,370
  • 2
  • 44
  • 50
22

With Rails 6, Zetiwerk became the default code loader.

For eager loading, try:

Zeitwerk::Loader.eager_load_all

Then

ApplicationRecord.descendants
demir
  • 4,591
  • 2
  • 22
  • 30
21

If you want just the Class names:

ActiveRecord::Base.descendants.map {|f| puts f}

Just run it in Rails console, nothing more. Good luck!

EDIT: @sj26 is right, you need to run this first before you can call descendants:

Rails.application.eager_load!
17

This seems to work for me:

  Dir.glob(RAILS_ROOT + '/app/models/*.rb').each { |file| require file }
  @models = Object.subclasses_of(ActiveRecord::Base)

Rails only loads models when they are used, so the Dir.glob line "requires" all the files in the models directory.

Once you have the models in an array, you can do what you were thinking (e.g. in view code):

<% @models.each do |v| %>
  <li><%= h v.to_s %></li>
<% end %>
bhousel
  • 351
  • 1
  • 6
  • Thanks bhousel. I originally went with this style of approach but ended up using the solution that Vincent posted above as it meant that I didn't have to "Modelize" the file name as well (i.e. strip out any _, capitalize! each word and then join them again). – mr_urf Feb 07 '09 at 14:03
  • with subdirectories: `...'/app/models/**/*.rb'` – artemave Mar 16 '11 at 10:30
  • [Object.subclasses_of](http://apidock.com/rails/Object/subclasses_of) is deprecated after v2.3.8. – David J. Jul 25 '12 at 15:55
11

ActiveRecord::Base.connection.tables

zishe
  • 10,665
  • 12
  • 64
  • 103
Mark Locklear
  • 5,044
  • 1
  • 51
  • 81
  • Also a nice followup is .column_names to list all columns in the table. So for your user table you would execute User.column_names – Mark Locklear Aug 13 '12 at 12:35
  • This will get you all the tables though, not just the models, since some tables don't always have associated models. – courtsimas Apr 15 '13 at 23:20
11

On one line: Dir['app/models/\*.rb'].map {|f| File.basename(f, '.*').camelize.constantize }

user229044
  • 232,980
  • 40
  • 330
  • 338
vjt
  • 486
  • 4
  • 9
  • 7
    This one is nice since, in Rails 3, your models aren't auto-loaded by default, so many of the above methods won't return all possible models. My permutation also captures models in plugins and subdirectories: `Dir['**/models/**/*.rb'].map {|f| File.basename(f, '.*').camelize.constantize } ` – wbharding Feb 25 '11 at 19:12
  • 2
    @wbharding That's pretty nice, but it errors out when it tries to constantize the names of my rspec model tests. ;-) – Ajedi32 Aug 29 '12 at 19:11
  • @wbharding nice solution but it breaks when you have namespaced models – Marcus Mansur Oct 04 '13 at 17:50
9

Yes there are many ways you can find all model names but what I did in my gem model_info is , it will give you all the models even included in the gems.

array=[], @model_array=[]
Rails.application.eager_load!
array=ActiveRecord::Base.descendants.collect{|x| x.to_s if x.table_exists?}.compact
array.each do |x|
  if  x.split('::').last.split('_').first != "HABTM"
    @model_array.push(x)
  end
  @model_array.delete('ActiveRecord::SchemaMigration')
end

then simply print this

@model_array
nitanshu verma
  • 261
  • 3
  • 8
7

In just one line:

 ActiveRecord::Base.subclasses.map(&:name)
Adrian
  • 9,102
  • 4
  • 40
  • 35
7

I can't comment yet, but I think sj26 answer should be the top answer. Just a hint:

Rails.application.eager_load! unless Rails.configuration.cache_classes
ActiveRecord::Base.descendants
Community
  • 1
  • 1
panteo
  • 720
  • 8
  • 12
4

To avoid pre-load all Rails, you can do this:

Dir.glob("#{Rails.root}/app/models/**/*.rb").each {|f| require_dependency(f) }

require_dependency(f) is the same that Rails.application.eager_load! uses. This should avoid already required file errors.

Then you can use all kind of solutions to list AR models, like ActiveRecord::Base.descendants

John Owen Chile
  • 501
  • 1
  • 4
  • 8
3

This works for Rails 3.2.18

Rails.application.eager_load!

def all_models
  models = Dir["#{Rails.root}/app/models/**/*.rb"].map do |m|
    m.chomp('.rb').camelize.split("::").last
  end
end
ryan0
  • 1,482
  • 16
  • 21
2
Dir.foreach("#{Rails.root.to_s}/app/models") do |model_path|
  next unless model_path.match(/.rb$/)
  model_class = model_path.gsub(/.rb$/, '').classify.constantize
  puts model_class
end

This will give to you all the model classes you have on your project.

Victor
  • 1,904
  • 18
  • 18
2
Module.constants.select { |c| (eval c).is_a?(Class) && (eval c) < ActiveRecord::Base }
Naveed
  • 11,057
  • 2
  • 44
  • 63
1

Here's a solution that has been vetted with a complex Rails app (the one powering Square)

def all_models
  # must eager load all the classes...
  Dir.glob("#{RAILS_ROOT}/app/models/**/*.rb") do |model_path|
    begin
      require model_path
    rescue
      # ignore
    end
  end
  # simply return them
  ActiveRecord::Base.send(:subclasses)
end

It takes the best parts of the answers in this thread and combines them in the simplest and most thorough solution. This handle cases where your models are in subdirectories, use set_table_name etc.

1

Just came across this one, as I need to print all models with their attributes(built on @Aditya Sanghi's comment):

ActiveRecord::Base.connection.tables.map{|x|x.classify.safe_constantize}.compact.each{ |model| print "\n\n"+model.name; model.new.attributes.each{|a,b| print "\n#{a}"}}
gouravtiwari21
  • 369
  • 3
  • 10
1

This worked for me. Special thanks to all the posts above. This should return a collection of all your models.

models = []

Dir.glob("#{Rails.root}/app/models/**/*.rb") do |model_path|
  temp = model_path.split(/\/models\//)
  models.push temp.last.gsub(/\.rb$/, '').camelize.constantize rescue nil
end
Kevin
  • 241
  • 2
  • 9
1

I've tried so many of these answers unsuccessfully in Rails 4 (wow they changed a thing or two for god sakes) I decided to add my own. The ones that called ActiveRecord::Base.connection and pulled the table names worked but didn't get the result I wanted because I've hidden some models (in a folder inside of app/models/) that I didn't want to delete:

def list_models
  Dir.glob("#{Rails.root}/app/models/*.rb").map{|x| x.split("/").last.split(".").first.camelize}
end

I put that in an initializer and can call it from anywhere. Prevents unnecessary mouse-usage.

boulder_ruby
  • 38,457
  • 9
  • 79
  • 100
1

The Rails implements the method descendants, but models not necessarily ever inherits from ActiveRecord::Base, for example, the class that includes the module ActiveModel::Model will have the same behavior as a model, just doesn't will be linked to a table.

So complementing what says the colleagues above, the slightest effort would do this:

Monkey Patch of class Class of the Ruby:

class Class
  def extends? constant
    ancestors.include?(constant) if constant != self
  end
end

and the method models, including ancestors, as this:

The method Module.constants returns (superficially) a collection of symbols, instead of constants, so, the method Array#select can be substituted like this monkey patch of the Module:

class Module

  def demodulize
    splitted_trail = self.to_s.split("::")
    constant = splitted_trail.last

    const_get(constant) if defines?(constant)
  end
  private :demodulize

  def defines? constant, verbose=false
    splitted_trail = constant.split("::")
    trail_name = splitted_trail.first

    begin
      trail = const_get(trail_name) if Object.send(:const_defined?, trail_name)
      splitted_trail.slice(1, splitted_trail.length - 1).each do |constant_name|
        trail = trail.send(:const_defined?, constant_name) ? trail.const_get(constant_name) : nil
      end
      true if trail
    rescue Exception => e
      $stderr.puts "Exception recovered when trying to check if the constant \"#{constant}\" is defined: #{e}" if verbose
    end unless constant.empty?
  end

  def has_constants?
    true if constants.any?
  end

  def nestings counted=[], &block
    trail = self.to_s
    collected = []
    recursivityQueue = []

    constants.each do |const_name|
      const_name = const_name.to_s
      const_for_try = "#{trail}::#{const_name}"
      constant = const_for_try.constantize

      begin
        constant_sym = constant.to_s.to_sym
        if constant && !counted.include?(constant_sym)
          counted << constant_sym
          if (constant.is_a?(Module) || constant.is_a?(Class))
            value = block_given? ? block.call(constant) : constant
            collected << value if value

            recursivityQueue.push({
              constant: constant,
              counted: counted,
              block: block
            }) if constant.has_constants?
          end
        end
      rescue Exception
      end

    end

    recursivityQueue.each do |data|
      collected.concat data[:constant].nestings(data[:counted], &data[:block])
    end

    collected
  end

end

Monkey patch of String.

class String
  def constantize
    if Module.defines?(self)
      Module.const_get self
    else
      demodulized = self.split("::").last
      Module.const_get(demodulized) if Module.defines?(demodulized)
    end
  end
end

And, finally, the models method

def models
  # preload only models
  application.config.eager_load_paths = model_eager_load_paths
  application.eager_load!

  models = Module.nestings do |const|
    const if const.is_a?(Class) && const != ActiveRecord::SchemaMigration && (const.extends?(ActiveRecord::Base) || const.include?(ActiveModel::Model))
  end
end

private

  def application
    ::Rails.application
  end

  def model_eager_load_paths
    eager_load_paths = application.config.eager_load_paths.collect do |eager_load_path|
      model_paths = application.config.paths["app/models"].collect do |model_path|
        eager_load_path if Regexp.new("(#{model_path})$").match(eager_load_path)
      end
    end.flatten.compact
  end
rplaurindo
  • 1,277
  • 14
  • 23
1

Make sure to eager load your app before calling descendants so that all the classes are loaded:

Rails.application.eager_load! unless Rails.application.config.eager_load

ApplicationRecord.descendants.each do |clazz|
  # do something with clazz, e.g. User, Event, Attendance, etc.
end
Dorian
  • 7,749
  • 4
  • 38
  • 57
0

can check this

@models = ActiveRecord::Base.connection.tables.collect{|t| t.underscore.singularize.camelize}
zishe
  • 10,665
  • 12
  • 64
  • 103
Arvind
  • 2,671
  • 1
  • 18
  • 32
0
def load_models_in_development
  if Rails.env == "development"
    load_models_for(Rails.root)
    Rails.application.railties.engines.each do |r|
      load_models_for(r.root)
    end
  end
end

def load_models_for(root)
  Dir.glob("#{root}/app/models/**/*.rb") do |model_path|
    begin
      require model_path
    rescue
      # ignore
    end
  end
end
Abdul
  • 1
0

Assuming all models are in app/models and you have grep & awk on your server (majority of the cases),

# extract lines that match specific string, and print 2nd word of each line
results = `grep -r "< ActiveRecord::Base" app/models/ | awk '{print $2}'`
model_names = results.split("\n")

It it faster than Rails.application.eager_load! or looping through each file with Dir.

EDIT:

The disadvantage of this method is that it misses models that indirectly inherit from ActiveRecord (e.g. FictionalBook < Book). The surest way is Rails.application.eager_load!; ActiveRecord::Base.descendants.map(&:name), even though it's kinda slow.

konyak
  • 10,818
  • 4
  • 59
  • 65
0

I'm just throwing this example here if anyone finds it useful. Solution is based on this answer https://stackoverflow.com/a/10712838/473040.

Let say you have a column public_uid that is used as a primary ID to outside world (you can findjreasons why you would want to do that here)

Now let say you've introduced this field on bunch of existing Models and now you want to regenerate all the records that are not yet set. You can do that like this

# lib/tasks/data_integirity.rake
namespace :di do
  namespace :public_uids do
    desc "Data Integrity: genereate public_uid for any model record that doesn't have value of public_uid"
    task generate: :environment do
      Rails.application.eager_load!
      ActiveRecord::Base
        .descendants
        .select {|f| f.attribute_names.include?("public_uid") }
        .each do |m| 
          m.where(public_uid: nil).each { |mi| puts "Generating public_uid for #{m}#id #{mi.id}"; mi.generate_public_uid; mi.save }
      end 
    end 
  end 
end

you can now run rake di:public_uids:generate

Community
  • 1
  • 1
equivalent8
  • 13,754
  • 8
  • 81
  • 109