14

使用 Ruby on Rails,如何实现多态has_many关系,其中所有者始终是已知的,但关联中的项目将是某种多态(但同质)类型,由所有者中的列指定?例如,假设产品Producerhas_many但生产者实例实际上可能有许多自行车、冰棒或鞋带。我可以很容易地让每个产品类(自行车、冰棒等)与生产者有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 表已经有一个“类型”列,它对应于某些产品类别(例如自行车、冰棒等),但我怎样才能让 Rails 让我做类似的事情:

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

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

4

5 回答 5

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
于 2012-09-27T22:12:01.233 回答
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 

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

于 2010-07-10T17:28:43.313 回答
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

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

于 2010-07-11T06:15:30.187 回答
0

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

可以使用 :polymorphic => true 选项启用 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,您应该使用 producer.products.derived_products 获取产品。

我还没有通过使用 has_many 来压缩与 producer.derived_products 的关联,所以我无法评论让它发挥作用。

于 2012-02-15T14:43:46.013 回答
-2
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
于 2010-07-09T12:15:23.087 回答