Rails Polymorphic has_many

mae*_*ics 13 ruby-on-rails associations polymorphic-associations

使用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
Run Code Online (Sandbox Code Playgroud)

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

>> bike_producer.products
#=> [Bicycle@123, Bicycle@456, ...]
>> popsicle_producer.products
#=> [Popsicle@321, Popsicle@654, ...]
Run Code Online (Sandbox Code Playgroud)

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

rew*_*ten 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
Run Code Online (Sandbox Code Playgroud)


mae*_*ics 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
Run Code Online (Sandbox Code Playgroud)

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