views:

110

answers:

3

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.

A: 
class Note < ActiveRecord::Base

 belongs_to :note_obj, :polymorphic => true
 belongs_to :user


end


class Contact < ActiveRecord::Base

 belongs_to :contact_obj, :polymorphic => true
 belongs_to :phone_type 

end



class CarrierHq < ActiveRecord::Base


 has_many :contacts, :as => :contact_obj
 has_many :notes, :as => :note_obj


end
Can you explain your answer a little, perhaps even modify it to use the producer/product terminology from the question?
maerics
class Bicycle < ActiveRecord::Base belongs_to :bicycle_obj,:polymorphic => true end class Popsicle < ActiveRecord::Base belongs_to :popsicle_obj , :polymorphic => true end class Producer < ActiveRecord::Base has_many :bicycles , :as=>:bicycle_obj has_many :popsicle , :as=>:popsicle_obj end Use this code if you have any problem with using on object, then please leave comment on this with code .
A: 

please take it on format

class Bicycle < ActiveRecord::Base 

belongs_to :bicycle_obj,:polymorphic => true 

end 

class Popsicle < ActiveRecord::Base

belongs_to :popsicle_obj , :polymorphic => true 

end 

class Producer < ActiveRecord::Base 

has_many :bicycles , :as=>:bicycle_obj 

has_many :popsicle , :as=>:popsicle_obj 

end 

"Use this code if you have any problem with using on object, then please leave comment on this with code . –"

Wait - why did you post two answers?
Jamie Wong
my commented answer was not in proper format thats why i give a seprate answer .
Thanks @Jamie Wong: for revisionsactually i am the new guy of stackoverflow and i dont know about formatting text
If you need a lot of space to respond to a comment, edit your original answer and note that it's in response to a comment.
Jamie Wong
This strategy isn't quite what I'm looking for since when I have a Producer I need to know what kind of products it will have in order to decide whether to call `p.bicycles` or `p.popsicles`, I'd like to have a single method that returns the products (e.g. `p.products`).
maerics
A: 

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:

class Bicycle < ActiveRecord::Base
  belongs_to :producer
end

class Popsicle < ActiveRecord::Base
  belongs_to :producer
end

class Producer < ActiveRecord::Base
  PRODUCT_TYPE_MAPPING = {
    'bicycle' => Bicycle,
    'popsicle' => Popsicle
  }.freeze
  def products
    klass = PRODUCT_TYPE_MAPPING[self.type]
    klass ? klass.find_all_by_producer_id(self.id) : []
  end
end

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.

maerics