Я предполагаю, что ваши модели выглядят так:
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)