我设置了以下型号:
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这样会返回所有'声音','阶段'以及我定义为'可投标'的任何其他内容。
实现这一目标的最佳方式是什么?
谢谢;)
答案 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.all
和Stage.all
的联合,以后任何表都可以投标。
现在写这篇文章的时候,我在想:能够做一个联盟,那些表必须非常相似。如果是这样,在您的情况下,您可能需要引入真实的Tenderable
对象,并使用STI。对于你现在想要的,这将是最好的解决方案。
无论Tenderable
必须适合单个表格,使用类型(声音,舞台......),然后您就可以获得与Tenderable的正常关系。舞台或声音继承自Tenderable。然后,您可以单独选择所有Tenderables或所有Sounds / Stages。
希望这有帮助。
答案 2 :(得分:0)
接受的答案是正确的,但效率低下。
Tender.distinct.pluck(:tendable_type)
这在数据库中做了更多工作,并且不需要实例化每个唯一对象以便在其上调用方法。
Tender.where.not(tendable: nil).includes(:tendable).map(&:tendable)
此eager一次性加载关联数据,而不是每次循环运行。这仍然会将每条记录加载到内存中,但根据您拥有的记录数量,它可能会显着提高性能。接受的答案将在每个投标中打到数据库。