Domyślam się, że Twoje modele wyglądają tak:
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
Nie możesz wykonać tego zapytania z kilku powodów.
- ActiveRecord nie może zbudować sprzężenia bez dodatkowych informacji.
- Nie ma tabeli o nazwie do przeglądania
Aby rozwiązać ten problem, musisz wyraźnie zdefiniować relację między Review
i 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
Następnie możesz zapytać w ten sposób:
Review.includes(:shop).where(shops: {shop_type: 'cafe'})
Zwróć uwagę, że nazwa tabeli to shops
i nie reviewable
. W bazie danych nie powinno być tabeli o nazwie przeglądalność.
Uważam, że jest to łatwiejsze i bardziej elastyczne niż jawne definiowanie join
między, Review
a Shop
ponieważ pozwala na niecierpliwe ładowanie oprócz zapytań z powiązanych pól.
Powodem, dla którego jest to konieczne, jest to, że ActiveRecord nie może zbudować sprzężenia na podstawie samego przeglądu, ponieważ wiele tabel reprezentuje drugi koniec sprzężenia, a SQL, o ile wiem, nie pozwala na dołączenie do tabeli nazwanej przez przechowywaną wartość w kolumnie. Definiując dodatkową relację belongs_to :shop
, podajesz ActiveRecord informacje potrzebne do zakończenia łączenia.
@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)