Rails Polymorphic has_many

时间:2010-07-09 02:03:08

标签: ruby-on-rails associations polymorphic-associations

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

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

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

所以我的Producer表已经有一个“类型”列,对应于某个产品类(例如Bicycle,Popsicle等),但是我怎样才能让Rails让我做类似的事情:

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

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

5 个答案:

答案 0 :(得分:6)

您必须在生产者身上使用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

答案 1 :(得分:2)

请以格式

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 

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

答案 2 :(得分:1)

以下是我目前正在使用的解决方法。它不提供从真正的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

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

答案 3 :(得分:0)

我发现Rails中记录了多态关联。 有一个表继承模式,这是获得最多文档, 但是如果你没有使用单表继承,那么就会有一些缺失的信息。

可以使用:polymorphic =&gt;启用belongs_to关联。真正的选择。但是,除非您使用单表继承,否则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,所以我无法评论是否能让它发挥作用。

答案 4 :(得分:-1)

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