Je suppose que vos modèles ressemblent à ceci:
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
Vous ne pouvez pas effectuer cette requête pour plusieurs raisons.
- ActiveRecord ne peut pas créer la jointure sans informations supplémentaires.
- Il n'y a pas de tableau appelé révisable
Pour résoudre ce problème, vous devez définir explicitement la relation entre Review
et 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
Ensuite, vous pouvez interroger comme ceci:
Review.includes(:shop).where(shops: {shop_type: 'cafe'})
Notez que le nom de la table est shops
et non reviewable
. Il ne doit pas y avoir de table appelée révisable dans la base de données.
Je pense que cela est plus facile et plus flexible que de définir explicitement l' join
intervalle Review
et Shop
car cela vous permet de charger rapidement en plus d'interroger des champs connexes.
La raison pour laquelle cela est nécessaire est qu'ActiveRecord ne peut pas créer une jointure basée uniquement sur révisable, car plusieurs tables représentent l'autre extrémité de la jointure et SQL, pour autant que je sache, ne vous permet pas de rejoindre une table nommée par la valeur stockée dans une colonne. En définissant la relation supplémentaire belongs_to :shop
, vous donnez à ActiveRecord les informations dont il a besoin pour terminer la jointure.
@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)