Forum: Ruby Defining an ActiveRecord class within a method of another class

Announcement (2017-05-07): www.ruby-forum.com is now read-only since I unfortunately do not have the time to support and maintain the forum any more. Please see rubyonrails.org/community and ruby-lang.org/en/community for other Rails- und Ruby-related community platforms.
Glenn (Guest)
on 2009-01-28 16:06
(Received via mailing list)
Hi,

I want to create a class and define a subclass of ActiveRecord within
that class, like this:

class Results
  def initialize(db)
    class db < ActiveRecord::Base
    end
  end
end

r1 = Results.new('DM')
r2 = Results.new('AE')

Then I want to put that class definition into an object and use it in
the instance methods of the Results class. (The instance methods of the
Results class will do stuff with database tables, but I want to pick
which table when I create the instances of the Results class.)

I am sure that the syntax above is wrong -- probably in many ways -- but
am unsure how to fix it.  Ruby does not seem to want to allow class
definitions within methods, but if I can't do that, I do not know of
another way to do this.

Thanks for your help.
Tsunami S. (Guest)
on 2009-01-28 16:27
I'm guessing this would do the trick :

irb(main):042:0> class Res
irb(main):043:1>   def self.get(cls)
irb(main):044:2>     eval("class #{cls};end")
irb(main):045:2>     return eval("#{cls}.new")
irb(main):046:2>   end
irb(main):047:1> end
irb(main):042:0> class Res
irb(main):043:1>   def self.get(cls)
irb(main):044:2>     eval("class #{cls};end")
irb(main):045:2>     return eval("#{cls}.new")
irb(main):046:2>   end
irb(main):047:1> end

You can modify what's being evaled .
Tsunami S. (Guest)
on 2009-01-28 16:28
Sorry , I pasted the same thing twice

 irb(main):042:0> class Res
 irb(main):043:1>   def self.get(cls)
 irb(main):044:2>     eval("class #{cls};end")
 irb(main):045:2>     return eval("#{cls}.new")
 irb(main):046:2>   end
 irb(main):047:1> end
 => nil
 irb(main):048:0> x = Res.get("G")
 => #<Res::G:0xb7c05d5c>
 irb(main):049:0> x.class
 => Res::G
Jesús Gabriel y Galán (Guest)
on 2009-01-28 17:53
(Received via mailing list)
On Wed, Jan 28, 2009 at 2:22 PM, Glenn <removed_email_address@domain.invalid> 
wrote:
>
> r1 = Results.new('DM')
> r2 = Results.new('AE')
>
> Then I want to put that class definition into an object and use it in the instance 
methods of the Results class. (The instance methods of the Results class will do stuff 
with database tables, but I want to pick which table when I create the instances of the 
Results class.)
>
> I am sure that the syntax above is wrong -- probably in many ways -- but am unsure how 
to fix it.  Ruby does not seem to want to allow class definitions within methods, but if I 
can't do that, I do not know of another way to do this.

Maybe this helps: I created a table named A, with id and description.
Then (you have require active_record and establish the connection):

irb(main):081:0> class Result
irb(main):082:1> def initialize table
irb(main):083:2> @db = Class.new(ActiveRecord::Base) do
irb(main):084:3* set_table_name table
irb(main):085:3> end
irb(main):086:2> end
irb(main):087:1> attr_reader :db
irb(main):088:1> end
=> nil
irb(main):089:0> a = Result.new("A")
=> #<Result:0xb7478bc0 @db=#<Class:0xb7478b98>(id: integer,
description: string)>
irb(main):090:0> a.db.find(:all)
=> [#<#<Class:0xb7478b98> id: 1, description: "test">,
#<#<Class:0xb7478b98> id: 2, description: "test 2">]

I did the set_table_name because I think you want to choose the table
name to be the parameter passed to the Result initialize method, and
skip ActiveRecord's pluralization stuff. I store the generated class
in an instance variable. Through this variable you get access to the
ActiveRecord class.

Jesus.
Brian C. (Guest)
on 2009-01-28 21:09
Glenn wrote:
> Hi,
>
> I want to create a class and define a subclass of ActiveRecord within
> that class, like this:
>
> class Results
>   def initialize(db)
>     class db < ActiveRecord::Base
>     end
>   end
> end
>
> r1 = Results.new('DM')
> r2 = Results.new('AE')

Class.new(superclass) should do what you need without need to eval
anything. This gives you an anonymous class, which you can then assign
to a constant to give it a proper class name. Something like (untested):

class Results
  def initialize(name)
    @klass = Results.const_set(name, Class.new(ActiveRecord::Base))
  end
  def query
    @klass.find(...)
  end
end

r1 = Results.new('DM')
Results::DM.find(...)
This topic is locked and can not be replied to.