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
いくつかの理由により、そのクエリを実行できません。
- ActiveRecord は追加情報なしでは結合を構築できません。
- レビュー可能なテーブルはありません
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
between とReview
を明示的に定義するよりも簡単で柔軟性が高いと考えています。Shop
これが必要な理由は、複数のテーブルが結合のもう一方の端を表し、SQL では、私が知る限り、列に格納された値で名前が付けられたテーブルを結合できないため、ActiveRecord は reviewable だけに基づいて結合を構築できないからです。追加の relationship を定義することでbelongs_to :shop
、結合を完了するために必要な情報を ActiveRecord に提供します。