多態的なEager Load 質問する

多態的なEager Load 質問する

Rails 3.2 を使用していますが、このコードの何が問題なのでしょうか?

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

次のエラーが発生します:

多態的関連付けを積極的にロードできません:reviewable

条件を削除するとreviewable.shop_type = ?動作します。

reviewable_typeおよびreviewable.shop_type(実際は)に基づいてフィルタリングするにはどうすればよいでしょうかshop.shop_type?

ベストアンサー1

私の推測では、モデルは次のようになります。

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 は追加情報なしでは結合を構築できません。
  2. レビュー可能なテーブルはありません

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 というテーブルは存在しないはずです。

これは、関連するフィールドによるクエリに加えて、即時読み込みも可能となるため、joinbetween とReviewを明示的に定義するよりも簡単で柔軟性が高いと考えています。Shop

これが必要な理由は、複数のテーブルが結合のもう一方の端を表し、SQL では、私が知る限り、列に格納された値で名前が付けられたテーブルを結合できないため、ActiveRecord は reviewable だけに基づいて結合を構築できないからです。追加の relationship を定義することでbelongs_to :shop、結合を完了するために必要な情報を ActiveRecord に提供します。

おすすめ記事