假设我们有这些模型
class Message
belongs_to :messageable, polymorphic: true
end
class Ticket
has_many :messages, as: :messageable
has_many :comments
end
class User
has_many :messages, as: :messageable
has_many :ratings
end
class Rating
belongs_to :user
end
class Comment
belongs_to :ticket
end
现在我要加载所有邮件(已关联tickets
或users
),并根据类的类型加载急切加载,comments
为tickets
和ratings
users
当然Message.includes(:messageable).order("created_at desc")
只包含直接关联的对象,但问题是如何包含从每种模型类型派生的不同关联类型(即在此示例中,如何预先加载{{1} }和comments for tickets
)?
这只是一个简单的例子,但是更复杂的情况呢,我想为ratings for users
包含其他内容,另一个关联,以及如果该关联需要更多包括什么?
答案 0 :(得分:2)
我能想到的唯一方法是使用通用名称复制每个模型上的关联:
class Ticket
has_many :messages, as: :messageable
has_many :comments
has_many :messageable_includes, class_name: "Comment"
end
class User
has_many :messages, as: :messageable
has_many :ratings
has_many :messageable_includes, class_name: "Rating"
end
Message.includes(:messageable => :messageable_includes) ...
我不确定我会将此策略用作广泛使用的解决方案,但如果您的案例变得复杂,那么它可能对您有用。
答案 1 :(得分:0)
我在自己的项目中使用了以下帮助方法:
def polymorphic_association_includes(association, includes_association_name, includes_by_type)
includes_by_type.each_pair do |includes_association_type, includes|
polymorphic_association_includes_for_type(association, includes_association_name, includes_association_type, includes)
end
end
def polymorphic_association_includes_for_type(association, includes_association_name, includes_association_type, includes)
id_attr = "#{includes_association_name}_id"
type_attr = "#{includes_association_name}_type"
items = association.select {|item| item[type_attr] == includes_association_type.to_s }
item_ids = items.map {|item| item[id_attr] }
items_with_includes = includes_association_type.where(id: item_ids).includes(includes).index_by(&:id)
items.each do |parent|
parent.send("#{includes_association_name}=", items_with_includes[parent[id_attr]])
end
end
这些可以让你说:
messages = Message.all
polymorhpic_association_includes messages, :messageable, {
Ticket => :comments,
User => :ratings
}
不是特别流畅的界面,但它一般都有用。
答案 2 :(得分:0)
将包含放在每个模型的默认范围内:
class Ticket
has_many :messages, as: :messageable
has_many :comments
default_scope -> { includes(:comments).order('id DESC') }
end
class User
has_many :messages, as: :messageable
has_many :ratings
default_scope -> { includes(:ratings).order('id DESC') }
end
然后,无论何时调用Message.all
,每个多态关联都将包含它自己的资源。
此外,如果您需要在没有范围的情况下调用该类,只需使用unscoped
或创建不同的范围:
class Ticket
has_many :messages, as: :messageable
has_many :comments
has_many :watchers
default_scope -> { includes(:comments).order('id DESC') }
scope :watched -> {includes(:watchers)}
end
Ticket.unscoped.all # without comments or watchers (or order)
Ticket.watched.all # includes watchers only