ฉันเดาว่าแบบจำลองของคุณมีลักษณะดังนี้:
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
ไม่ควรมีตารางที่เรียกว่าตรวจสอบได้ในฐานข้อมูล
ฉันเชื่อว่าสิ่งนี้จะง่ายและยืดหยุ่นกว่าการกำหนดjoin
ระหว่างReview
และอย่างชัดเจนShop
เนื่องจากช่วยให้คุณสามารถโหลดได้อย่างเต็มที่นอกเหนือจากการสืบค้นตามช่องที่เกี่ยวข้อง
เหตุผลที่จำเป็นคือ ActiveRecord ไม่สามารถสร้างการรวมตามการตรวจสอบได้เพียงอย่างเดียวเนื่องจากหลายตารางแสดงถึงส่วนท้ายของการรวมอีกด้านหนึ่งและ SQL เท่าที่ฉันทราบไม่อนุญาตให้คุณเข้าร่วมตารางที่ตั้งชื่อตามค่าที่เก็บไว้ ในคอลัมน์ ด้วยการกำหนดความสัมพันธ์เพิ่มเติม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)