急切加载多态

使用Rails 3.2,这个代码有什么问题?

@reviews = @user.reviews.includes(:user, :reviewable) .where('reviewable_type = ? AND reviewable.shop_type = ?', 'Shop', 'cafe') 

这引起了这个错误:

不能急于加载多态关联:可查看

如果我删除了reviewable.shop_type = ? 条件,它的作品。

如何根据shop.shop_typeshop.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 

由于以下几个原因,您无法执行该查询。

  1. 没有附加信息,ActiveRecord无法build立连接。
  2. 没有称为可审查的表格

为了解决这个问题,你需要明确定义ReviewShop之间的关系。

 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 。 数据库中不应该有一个可查看的表格。

我相信这比明确定义ReviewShop之间的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子句中的多态关联(这是有意义的,因为多态关联代表多个表)。