Tôi đoán rằng các mô hình của bạn trông như thế này:
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
Bạn không thể thực hiện truy vấn đó vì một số lý do.
- ActiveRecord không thể tạo kết nối mà không có thông tin bổ sung.
- Không có bảng nào được gọi là có thể xem lại
Để giải quyết vấn đề này, bạn cần xác định rõ ràng mối quan hệ giữa Review
và 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
Sau đó, bạn có thể truy vấn như sau:
Review.includes(:shop).where(shops: {shop_type: 'cafe'})
Lưu ý rằng tên bảng là shops
và không reviewable
. Không nên có một bảng được gọi là có thể xem lại trong cơ sở dữ liệu.
Tôi tin rằng điều này dễ dàng và linh hoạt hơn việc xác định rõ ràng join
giữa Review
và Shop
vì nó cho phép bạn tải nhanh ngoài việc truy vấn theo các trường liên quan.
Lý do mà điều này là cần thiết là ActiveRecord không thể xây dựng một kết nối chỉ dựa trên có thể xem xét, vì nhiều bảng đại diện cho đầu kia của kết nối và SQL, theo như tôi biết, không cho phép bạn tham gia một bảng được đặt tên theo giá trị được lưu trữ trong một cột. Bằng cách xác định mối quan hệ bổ sung belongs_to :shop
, bạn đang cung cấp cho ActiveRecord thông tin cần thiết để hoàn thành việc tham gia.
@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)