如何通过多态类型获取对象的所有实例?

时间:2011-11-01 22:04:53

标签: ruby-on-rails

我设置了以下型号:

class Sound < ActiveRecord::Base  
  has_many :tenders, :as => :tenderable
  belongs_to :event
end

class Stage < ActiveRecord::Base
  has_many :tenders, :as => :tenderable
  belongs_to :event
end

class Tender < ActiveRecord::Base
  attr_accessible :event_id, :user_id, :estimate, :tenderable_id, :tenderable_type
  belongs_to :tenderable, :polymorphic => :true
end

class Event < ActiveRecord::Base
  attr_accessible :name
  has_one :stage
  has_one :sound

  accepts_nested_attributes_for :stage, :allow_destroy => true
  accepts_nested_attributes_for :sound, :allow_destroy => true
end

每个事件附有各种Tenderable(例如舞台,声音),我可以通过Event.find(id).tenderables访问这些,但我需要弄清楚哪些“机会”可用,无论事件如何他们是附属于。

目前我还没有'机会'的模型,因为我试图让事情变得简单。

我想要做的事情就像Tenderables.all这样会返回所有'声音','阶段'以及我定义为'可投标'的任何其他内容。

实现这一目标的最佳方式是什么?

谢谢;)

3 个答案:

答案 0 :(得分:2)

Tender.select("DISTINCT tendable_type").collect(&:tendable_type).compact

将为您提供至少已使用过一次的所有相关模型的名称。

对于所有已关联为可伸缩的对象

Tender.where("tendable_type IS NOT NULL").collect(&:tendable)

答案 1 :(得分:2)

Afaik所有Tenderables的列表,在可能附加Tender的内容的意义上,无法从数据库或模型结构构建。在数据库中,您可以找到附加了Tenderable的所有Tender,但不是很容易(想想每个tenderable_type的查询联合)。

但是多态关系的主要属性实际上是任何类型的对象都可以附加到它上面,所以你必须自己管理完整的对象列表。

我不完全确定你为什么会这样,但是你必须做Sound.allStage.all的联合,以后任何表都可以投标。

现在写这篇文章的时候,我在想:能够做一个联盟,那些表必须非常相似。如果是这样,在您的情况下,您可能需要引入真实的Tenderable对象,并使用STI。对于你现在想要的,这将是最好的解决方案。

无论Tenderable必须适合单个表格,使用类型(声音,舞台......),然后您就可以获得与Tenderable的正常关系。舞台或声音继承自Tenderable。然后,您可以单独选择所有Tenderables或所有Sounds / Stages。

希望这有帮助。

答案 2 :(得分:0)

接受的答案是正确的,但效率低下。

  1. 选择所有类型:
  2. Tender.distinct.pluck(:tendable_type)

    这在数据库中做了更多工作,并且不需要实例化每个唯一对象以便在其上调用方法。

    1. 选择所有对象:
    2. Tender.where.not(tendable: nil).includes(:tendable).map(&:tendable)

      此eager一次性加载关联数据,而不是每次循环运行。这仍然会将每条记录加载到内存中,但根据您拥有的记录数量,它可能会显着提高性能。接受的答案将在每个投标中打到数据库。