Using Ruby on Rails, how can I achieve a polymorphic has_many
relationship where the owner is always of a known but the items in the association will be of some polymorphic (but homogenous) type, specified by a column in the owner? For example, suppose the Producer
class has_many
products but producer instances might actually have many Bicycles, or Popsicles, or Shoelaces. I can easily have each product class (Bicycle, Popsicle, etc.) have a belongs_to
relationship to a Producer but given a producer instance how can I get the collection of products if they are of varying types (per producer instance)?
Rails polymorphic associations allow producers to belong to many products, but I need the relationship to be the other way around. For example:
class Bicycle < ActiveRecord::Base
belongs_to :producer
end
class Popsicle < ActiveRecord::Base
belongs_to :producer
end
class Producer < ActiveRecord::Base
has_many :products, :polymorphic_column => :type # last part is made-up...
end
So my Producer table already has a "type" column which corresponds to some product class (e.g. Bicycle, Popsicle, etc.) but how can I get Rails to let me do something like:
>> bike_producer.products
#=> [Bicycle@123, Bicycle@456, ...]
>> popsicle_producer.products
#=> [Popsicle@321, Popsicle@654, ...]
Sorry if this is obvious or a common repeat; I'm having surprising difficulty achieving it easily.
You have to use STI on the producers, not on the products. This way you have different behavior for each type of producer, but in a single
producers
table.(almost) No polymorphism at all!
I find that polymorphic associations is under documented in Rails. There is a single table inheritance schema, which is what gets the most documentation, but if you are not using single table inheritance, then there is some missing information.
The belongs_to association can be enabled using the :polymorphic => true option. However, unless you are using single table inheritance, the has_many association does not work, because it would need to know the set of tables that could have a foreign key.
(From what I found), I think the clean solution is to have a table and model for the base class, and have the foreign key in the base table.
Then, for a Production object, producer, you should get the products with producer.products.derived_products.
I have not yet played with has_many through to condense the association to producer.derived_products, so I cannot comment on getting that to work.
please take it on format
Use this code. If you have any problem with it, please leave a comment.
Here is the workaround I'm currently using. It doesn't provide any of the convenience methods (collection operations) that you get from real ActiveRecord::Associations, but it does provide a way to get the list of products for a given producer:
Another downside is that I must maintain the mapping of type strings to type classes but that could be automated. However, this solution will suffice for my purposes.