Rails Polymorphic has_many

使用Ruby on Rails,我如何实现多态has_many关系,其中所有者始终是已知的,但关联中的项将是某些多态(但同质)类型,由所有者中的列指定? 例如,假设Producerhas_many产品,但生产者实例可能实际上有许多Bicycles,或Popsicles或Shoelaces。 我可以轻松地让每个产品类(Bicycle,Popsicle等)与Producer有一个belongs_to关系,但是给定一个生产者实例,如果它们的类型不同(每个生产者实例),我如何获得产品集合?

Rails多态关联允许生产者属于许多产品,但我需要这种关系是另一种方式。 例如:

 class Bicycle < ActiveRecord::Base belongs_to :producer end class Popsicle < ActiveRecord::Base belongs_to :producer end class Producer  :type # last part is made-up... end 

所以我的Producer表已经有一个“类型”列,它对应于某个产品类(例如Bicycle,Popsicle等)但是我如何让Rails让我做一些像:

 >> bike_producer.products #=> [Bicycle@123, Bicycle@456, ...] >> popsicle_producer.products #=> [Popsicle@321, Popsicle@654, ...] 

对不起,如果这是显而易见的或常见的重复; 我很难轻易实现它。

你必须在生产者身上使用STI,而不是在产品上使用。 这样,每种类型的生产者都有不同的行为,但在单个producers表中。

(几乎)没有多态性!

 class Product < ActiveRecord::Base # does not have a 'type' column, so there is no STI here, # it is like an abstract superclass. belongs_to :producer end class Bicycle < Product end class Popsicle < Product end class Producer < ActiveRecord::Base # it has a 'type' column so we have STI here!! end class BicycleProducer < Producer has_many :products, :class_name => "Bicycle", :inverse_of => :producer end class PopsicleProducer < Producer has_many :products, :class_name => "Popsicle", :inverse_of => :producer end 

这是我目前正在使用的解决方法。 它不提供从真正的ActiveRecord :: Associations获得的任何便利方法(收集操作),但它确实提供了获取给定生产者的产品列表的方法:

 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 

另一个缺点是我必须维护类型字符串到类型类的映射,但这可以自动化。 但是,这个解决方案足以满足我的目的。

请把它放在格式上

 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 

使用此代码。 如果您有任何问题,请发表评论。

我发现Rails中记录了多态关联。 有一个表inheritance模式,它是获取最多文档的内容,但如果您不使用单表inheritance,则会有一些缺少的信息。

可以使用:polymorphic => true选项启用belongs_to关联。 但是,除非您使用单表inheritance,否则has_many关联不起作用,因为它需要知道可以具有外键的表集。

(根据我的发现),我认为干净的解决方案是拥有基类的表和模型,并在基表中使用外键。

 create_table "products", :force => true do |table| table.integer "derived_product_id" table.string "derived_product_type" table.integer "producer_id" end class Product < ActiveRecord::Base belongs_to :producer end class Producer < ActiveRecord::Base has_many :products end 

然后,对于Production对象,生产者,您应该使用producer.products.derived_products获取产品。

我还没有使用has_many来浓缩关联到producer.derived_products,所以我无法评论让它工作。

 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