Ruby on rails 急负荷多态

Ruby on rails 急负荷多态,ruby-on-rails,ruby-on-rails-3,activerecord,Ruby On Rails,Ruby On Rails 3,Activerecord,使用Rails3.2,这段代码有什么问题 @reviews = @user.reviews.includes(:user, :reviewable) .where('reviewable_type = ? AND reviewable.shop_type = ?', 'Shop', 'cafe') 它引发了以下错误: 无法立即加载多态关联:可查看 如果我删除reviewable.shop\u type=?条件,它会工作 如何根据reviewable\u类型和reviewable.shop\u类

使用Rails3.2,这段代码有什么问题

@reviews = @user.reviews.includes(:user, :reviewable)
.where('reviewable_type = ? AND reviewable.shop_type = ?', 'Shop', 'cafe')
它引发了以下错误:

无法立即加载多态关联:可查看

如果我删除
reviewable.shop\u type=?
条件,它会工作


如何根据
reviewable\u类型
reviewable.shop\u类型
(实际上是
shop.shop\u类型
)进行过滤?

我猜您的模型如下所示:

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.includes(:shop).where(shops: {shop_type: 'cafe'})
然后您可以这样查询:

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.includes(:shop).where(shops: {shop_type: 'cafe'})
请注意,表名是
shops
,而不是
reviewable
。数据库中不应该有一个名为reviewable的表

我认为这比在
Review
Shop
之间显式定义
join
更容易、更灵活,因为它允许您除了通过相关字段进行查询外,还可以进行即时加载


之所以需要这样做,是因为ActiveRecord无法仅基于reviewable构建联接,因为多个表表示联接的另一端,而据我所知,SQL不允许您联接以列中存储的值命名的表。通过定义额外关系
所属:shop
,您为ActiveRecord提供了完成加入所需的信息。

作为附录,顶部的答案非常好,如果由于某种原因,您正在使用的查询不包括模型的表,并且出现未定义的表错误,则还可以在关联上指定
:include

像这样:

belongs_to :shop, 
           foreign_key: 'reviewable_id', 
           conditions: "reviews.reviewable_type = 'Shop'",
           include: :reviews
没有
:include
选项,如果您在上面的示例中仅访问关联
review.shop
,您将得到一个不可定义的错误(在Rails 3中测试,而不是在Rails 4中测试),因为关联将从shop.id=1和(reviews.review\u type='shop')的店铺中进行
选择。

:include
选项将强制联接。:)


当您使用带有WHERE的SQL片段时,需要引用才能加入您的关联。

如果您得到一个ActiveRecord::急切加载多态性错误,这是因为
包含
决定调用
急切加载
,而多态性关联仅受
预加载
支持。在这里的文档中:


因此,对于多态关联,请始终使用
preload
。对此有一个警告:您不能在where子句中查询多态关联(这是有意义的,因为多态关联表示多个表)。

实际上,我最终使用了它,但没有声明任何其他内容:
@reviews=@user.reviews.joins(“内部连接在(reviewable_type='Shop'AND shops.id=reviewable_id AND shops.Shop_type='“+type+”))。包括(:user,:reviewable=>:photos)
在rails4中工作,但会给出一个弃用警告,它说应该使用类似has-many:spam_注释、>{where-spam:true}的样式,类名:'Comment'。因此在rails4中,将属于:Shop、>{where(“reviews.reviewable_type='Shop'”),外键:'reviewable_id'。但是要小心,Review.includes(:Shop)将引发错误,它必须至少附加一个where子句。还有一个foreign类型,它为我解决了一个类似的问题:
属于:shop,foreign类型:'shop',外键:'reviewable\u id'
加载
审阅
时,包括使用code
审阅急切加载关联的
shop
。包括(:shop)
属于定义
属于:shop,->{where(reviews:{reviewable\u type:'shop'}),外键:'reviewable\u id'
抛出错误,表示表“reviews”
的子句条目缺少
。我通过以下方式更新属于定义来修复它:
属于:shop,->{joins(:reviews).where(评论:{reviewable_type:'Shop'}},外键:'reviewable_id'
我尝试过这个,但它出现了一个非常有趣的错误。如果有一个商店和一个用户具有相同的数据库id,那么在
review_type
设置为
User
的评论中调用
review.Shop
可以返回一个完全无关的商店,而不是
nil
这可能是一个非常严重的数据泄漏,因为用户可能有权访问
review
,但无权访问
review.Shop
返回的店铺。未知键::条件。有效键为::class\u name、:class、:foreign\u key、:validate、:autosave、:dependent、:primary\u key、:inverse\u of、:required、:foreign\u type、:多态、:touch、:conter_Cache我知道这是指南中没有记录的一种方法: