How can I get a model class from a string?
I have a Model called Todo.rb
which has an attribute called "asset
" which is a string. The string contains the names of Models such as Call
, Email
, etc.
They also contain an asset_id
, which is a specific record of the Asset in ActiveRecord.
How, from a Todo record, can I assign to asset
from that actual ActiveRecord class?
=> #<Todo id: 165, created_at: "2010-11-04 00:49:45", updated_at: "2010-11-04 00:49:45", contact_id: 49, user_id: 1, asset: "Call", asset_id: 2, original_date: "2010-11-1开发者_如何学JAVA8", current_date: "2010-11-18", done_date: nil>
From this, I would like asset
to be the equivalent of:
asset = Call.find(2)
I understand conceptually this could be a case of single table inheritance, but I wasn't clear how and I wanted to build it up from the use-case.
I understand what you're trying to do here, and there's a much simpler way to do it. It's called polymorphism. You want todo's to be able to belong to more than one type of thing - sometimes a call, sometimes email, and so on. The good news is, you're pretty close already. Here's how you set it up.
In your migration, rename the "asset" field to "asset_type":
rename_column :todos, :asset, :asset_type
Now add this to your models:
class Todo < ActiveRecord::Base
belongs_to :asset, :polymorphic => true
end
class Call < ActiveRecord::Base
has_many :todos, :as => :asset
end
class Email < ActiveRecord::Base
has_many :todos, :as => :asset
end
In the class that is going to belong_to many different types of objects, you have an asset_type string column, and an asset_id integer column. And you specify that it belongs to the polymorphic association, as shown above. Then, in all the models that can have_many todo's, you add the :as => :asset
part to tell it Rails how to find the associated todo's.
This is very easy, and now it works just like any other has_many. I hope this helps!
UPDATE: This is an article I wrote that illustrates polymorphism not just at the model level, but also throughout your site's forms:
http://kconrails.com/2010/10/19/common-addresses-using-polymorphism-and-nested-attributes-in-rails/
Rails has a built-in called constantize which should do the trick:
asset = "Call".constantize.find(2)
You can also use Kernel.const_get("Call")
or eval("Call")
but I would avoid eval if at all possible.
asset = todo.asset.capitalize.constantize.find(todo.asset_id)
精彩评论