2
votes

I want to create an ActiveRecord model at run time.

In my system I'm generating some reports and all of them bind with a database table/ views. So the only difference will be the table name.

So what I want to do is have an active record common class (preferably generated at runtime) and assign the table name at runtime. and i should be able to assign a a scope to select a date range. And I'm thinking of getting the column names at runtime to display data.

  • can anyone help me out on how to create ActiveRecord model at runtime
  • assign scope method

and I'm on rails3

thanks in advance

cheers

sameera

2
So, you haven't written any code and want us to write it for you?the Tin Man
Hi @TinMan, I have come across with following resources snippets.dzone.com/posts/show/2390, workingwithrails.com/forums/4-ask-a-rails-expert/topics/… and seems like i should use 'create_class' method in ruby. But I'm not sure where to start. thats why I posted it in the forum. So any resource, article is welcome thankssameera207

2 Answers

3
votes

Borrowing create_class from the article you linked, how about something like this:

TABLE_NAMES = %w[customers products purchases]

def create_class(class_name, superclass, &block)
  klass = Class.new superclass, &block
  Object.const_set class_name, klass
end

def create_model_class(table_name)
  create_class(table_name.classify, ActiveRecord::Base) do
    scope :in_date_range, lambda {|start_date, end_date| where("start_date >= ?", start_date).where("end_date <= ?", end_date) }
  end
end

TABLE_NAMES.each {|table_name| create_model_class(table_name) }

If you wanted to use all tables in the database, you could do this:

TABLE_NAMES = ActiveRecord::Base.connection.tables

But unless you're treating all tables identically, I'm guessing you wouldn't want to do that.

Once you've created your model classes, you should now be able to print objects from each table with their respective columns:

def print_attributes(model_obj)
  puts model_obj.attributes.map {|k,v| "#{k}=#{v.inspect}" }.join(', ')
end

Customer.in_date_range(Date.today, Date.today + 1.day).each {|c| print_attributes(c) }
Product.in_date_range(Date.yesterday, Date.today + 2.days).each {|c| print_attributes(c) 
Purchase.in_date_range(Date.yesterday, Date.today + 3.days).each {|c| print_attributes(c) }
0
votes

The easiest way to do this assuming the view names are static is to create one module with the common functionality and then include it into your base models..

module ModuleA ... end

class A extends ActiveRecord::Base include ModuleA end

Class B extends ActiveRecord::Base include ModuleA end