私の推測では、モデルは次のようになります。
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はレビュー可能のみに基づいて結合を構築できないためです列に。追加の関係を定義することによりbelongs_to :shop
、結合を完了するために必要な情報をActiveRecordに提供します。
@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)