急切加载多态
使用Rails 3.2,这个代码有什么问题?
@reviews = @user.reviews.includes(:user, :reviewable) .where('reviewable_type = ? AND reviewable.shop_type = ?', 'Shop', 'cafe')
这引起了这个错误:
不能急于加载多态关联:可查看
如果我删除了reviewable.shop_type = ?
条件,它的作品。
如何根据shop.shop_type
和shop.shop_type
(其实是shop.shop_type
)进行shop.shop_type
?
我的猜测是你的模型是这样的:
class User < ActiveRecord::Base has_many :reviews end class Review < ActiveRecord::Base belongs_to :user belongs_to :reviewable, polymorphic: true end class Shop < ActiveRecord::Base has_many :reviews, as: :reviewable end
由于以下几个原因,您无法执行该查询。
- 没有附加信息,ActiveRecord无法build立连接。
- 没有称为可审查的表格
为了解决这个问题,你需要明确定义Review
和Shop
之间的关系。
class Review < ActiveRecord::Base belongs_to :user belongs_to :reviewable, polymorphic: true # For Rails < 4 belongs_to :shop, foreign_key: 'reviewable_id', conditions: "reviews.reviewable_type = 'Shop'" # For Rails >= 4 belongs_to :shop, -> { where(reviews: {reviewable_type: 'Shop'}) }, foreign_key: 'reviewable_id' end
那么你可以这样查询:
Review.includes(:shop).where(shops: {shop_type: 'cafe'})
请注意,表名是shops
,不可reviewable
。 数据库中不应该有一个可查看的表格。
我相信这比明确定义Review
和Shop
之间的join
更简单,更灵活,因为除了相关字段的查询以外,它还允许您进行热切的加载。
这是必要的原因是,ActiveRecord无法build立基于单独审查的连接,因为多个表代表连接的另一端,据我所知,SQL不允许您连接一个由存储的值命名的表在一列。 通过定义额外关系belongs_to :shop
,您将为ActiveRecord提供完成连接所需的信息。
作为一个附录顶部的答案,这是非常好的,你也可以指定:include
关联,如果由于某种原因,你正在使用的查询不包括模型的表,你会得到未定义的表错误。
像这样:
belongs_to :shop, foreign_key: 'reviewable_id', conditions: "reviews.reviewable_type = 'Shop'", include: :reviews
没有:include
选项,如果你只是在上面的例子中访问关联review.shop
,你会得到一个UndefinedTable错误(在Rails 3中testing,而不是4),因为关联会做SELECT FROM shops WHERE shop.id = 1 AND ( reviews.review_type = 'Shop' )
。
:include
选项会强制joinJOIN。 🙂
恐怕以前的答案是不完全可以接受的。 它不会工作,除非你把你的查询放在where(shops: {shop_type: 'cafe'})
。
我发现自己没有简单的解决scheme…
@reviews = @user.reviews.includes(:user, :reviewable) .where('reviewable_type = ? AND reviewable.shop_type = ?', 'Shop', 'cafe').references(:reviewable)
当您在WHERE中使用SQL片段时,引用有必要join您的关联。
如果你得到一个ActiveRecord :: EagerLoadPolymorphicError,这是因为includes
只有在preload
才支持多态关联的时候才决定调用eager_load
。 这是在这里的文档: http : //api.rubyonrails.org/v5.1/classes/ActiveRecord/EagerLoadPolymorphicError.html
所以总是使用preload
多态关联。 有一个告诫:无法查询where子句中的多态关联(这是有意义的,因为多态关联代表多个表)。