Answers:
我的猜测是您的模型如下所示:
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
由于某些原因,您无法执行该查询。
为了解决这个问题,你需要明确定义之间的关系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'
# Ensure review.shop returns nil unless review.reviewable_type == "Shop"
def shop
return unless reviewable_type == "Shop"
super
end
end
然后您可以像这样查询:
Review.includes(:shop).where(shops: {shop_type: 'cafe'})
请注意,表名称是shops
和不是reviewable
。数据库中不应有一个称为reviewable的表。
我相信,这比显式定义join
之间的方法更容易,更灵活Review
,Shop
因为它不仅使您可以按相关字段进行查询,而且还渴望加载。
之所以需要这样做,是因为ActiveRecord无法单独基于可审阅来建立联接,因为多个表代表了联接的另一端,据我所知,SQL不允许您联接以存储的值命名的表在列中。通过定义额外的关系belongs_to :shop
,可以为ActiveRecord提供完成连接所需的信息。
:reviewable
是Shop
。照片属于网店。
belongs_to :shop, foreign_type: 'Shop', foreign_key: 'reviewable_id'
reviews
包括急于加载相关的shop
使用代码时Review.includes(:shop)
,belongs_to定义 belongs_to :shop, -> { where(reviews: {reviewable_type: 'Shop'}) }, foreign_key: 'reviewable_id'
抛出错误提示missing FROM-clause entry for table "reviews"
。我通过以下方式更新belongs_to定义来修复它: belongs_to :shop, -> { joins(:reviews) .where(reviews: {reviewable_type: 'Shop'}) }, foreign_key: 'reviewable_id'
如果收到ActiveRecord :: EagerLoadPolymorphicError,这是因为当仅支持多态关联时includes
决定调用。在此处的文档中:http : //api.rubyonrails.org/v5.1/classes/ActiveRecord/EagerLoadPolymorphicError.htmleager_load
preload
因此,始终preload
用于多态关联。需要注意的是:您不能在where子句中查询多态关联(这很有意义,因为多态关联表示多个表。)
@reviews = @user.reviews.includes(:user, :reviewable)
.where('reviewable_type = ? AND reviewable.shop_type = ?', 'Shop', 'cafe').references(:reviewable)
当您将SQL片段与WHERE一起使用时,必须有引用才能加入关联。
作为附录的顶部答案,这是个很好的答案,您也可以:include
在关联上指定由于某种原因,如果您所使用的查询不包括模型的表,并且您收到未定义的表错误。
像这样:
belongs_to :shop,
foreign_key: 'reviewable_id',
conditions: "reviews.reviewable_type = 'Shop'",
include: :reviews
如果没有该:include
选项,则如果您仅review.shop
在上面的示例中访问该关联,则将收到UndefinedTable错误(在Rails 3中进行测试,而不是在4中测试),因为关联会这样做SELECT FROM shops WHERE shop.id = 1 AND ( reviews.review_type = 'Shop' )
。
该:include
选项将强制执行JOIN。:)
@reviews = @user.reviews.joins("INNER JOIN shops ON (reviewable_type = 'Shop' AND shops.id = reviewable_id AND shops.shop_type = '" + type + "')").includes(:user, :reviewable => :photos)