Topic: Retrieve list of all models in your app?

I've finally gotten round to experimenting with rake tasks. What i'd like to do in the one i'm hacking up, is retrieve an array of all the models in my application, and then run a particular method on a subset of those (to be precise, i want to run that method for the models who have a corresponding .yml file in the db directory)

This meta-programming territory is quite unfamiliar to me, is there a way to get an array of all application models within a rake task?

Here's the pseudo code i have so far

desc "Synchronise development and test databases with latest data from svn"
task :sync_db => ["db:migrate","load_data_from_ar_dumps","db:test:clone"]

task :load_data_from_ar_dumps => :environment do
  # Get all models in the app and put them in 'models' array
  # models.each |m|
  #  if ... (check if theres a corresponding .yml file in db)
  #    eval("#{m.to_s}.dump_to_file")
  #  end
  # end
end

Last edited by cbit (2006-12-05 07:32:05)

Re: Retrieve list of all models in your app?

This code below will search through the app/models directory of your rails app. When it finds a model it will add the ModelName (in constant form) to the models array. You can then loop through the models array and do your eval thing.

require 'find'

models = []
Find.find("#{RAILS_ROOT}/app/models") do |path|
    if FileTest.directory?(path)
      #skip, this is a folder
      next
    else
      #strip filename to just model_name
      filename = File.basename(path, '.rb')
      models << filename.camelize.constantize
    end
  end
end


caution: code is untested smile

vinnie - rails forum admin

Re: Retrieve list of all models in your app?

Thanks alot, this gave me a great headstart. heres what i ended up with

require 'find'
models=[]
path="#{RAILS_ROOT}/app/models"
Find.find(path) do |p|
  if FileTest.directory?(p) and p!=path
    Find.prune # dont recurse into directories
    next
  end
  if p =~ /.rb$/
     models << File.basename(p,".*").camelize.constantize
  end
end
# puts models.join(", ")

Last edited by cbit (2006-12-05 11:19:56)

Re: Retrieve list of all models in your app?

Aha: the problem with this approach is that it only 'sees' the models that you define in your models directory smile, it doesn't take into account model definitions elsewhere in the system (like in vendor/plugins).

I'm wondering if there's a way to extract knowledge about which models exist from the rails environment somehow..

Re: Retrieve list of all models in your app?

There is a hack to get all subclasses of a given class. You can use this to get all subclasses of ActiveRecord::Base. Not sure how well it works, but worth a try.

Railscasts - Free Ruby on Rails Screencasts

Re: Retrieve list of all models in your app?

thanks ryan. putting that code to extend Object in my environment breaks my tests in wonderful ways though!

Thinking about it another way i realise that it'd be enough to get the names of all my database tables, i'll read some more around it..

For the moment i'm happy that i've got a working rake task that loads any yml file that's in the db directory in to the dev database (using the AR fixtures plugin):

desc "Synchronise development and test databases with latest data from svn"
task :sync_db => ["db:migrate","load_from_ar_dumps","db:test:clone"]

task :load_from_ar_dumps => :environment do
  require 'find'
  models=[]
  path="#{RAILS_ROOT}/db"
  puts "\nSearching for .yml files inside /db .."
  Find.find(path) do |p|
    if FileTest.directory?(p) and p!=path
      Find.prune
      next
    end
    if p =~ /.yml$/
      models << File.basename(p,".*").singularize.camelize.constantize
    end
  end
  puts "Loading model data into development database .."
  models.each do |m|
    oldnumber=eval("#{m}.find(:all).size")
    eval("#{m}.load_from_file")
    newnumber=eval("#{m}.find(:all).size")
    puts "#{oldnumber.to_s} -> #{newnumber.to_s} records : #{m}"
  end
  puts "\n"
end

Last edited by cbit (2006-12-05 13:02:46)