열망 부하 다형성


104

Rails 3.2를 사용하면이 코드에 어떤 문제가 있습니까?

@reviews = @user.reviews.includes(:user, :reviewable)
.where('reviewable_type = ? AND reviewable.shop_type = ?', 'Shop', 'cafe')

이 오류가 발생합니다.

다형성 연관을 열심히로드 할 수 없습니다.

reviewable.shop_type = ?조건을 제거하면 작동합니다.

reviewable_typereviewable.shop_type(실제로는 shop.shop_type) 를 기준으로 필터링하려면 어떻게 해야합니까?

답변:


207

내 생각에는 모델이 다음과 같이 보입니다.

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

여러 가지 이유로 해당 쿼리를 수행 할 수 없습니다.

  1. ActiveRecord는 추가 정보없이 조인을 빌드 할 수 없습니다.
  2. 검토 가능이라는 표가 없습니다.

이 문제를 해결하기 위해 명시 적 사이의 관계를 정의해야 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사이 ReviewShop는 관련 분야에서 쿼리에 추가 열망로드 할 수 있기 때문에.

이것이 필요한 이유는 여러 테이블이 조인의 다른 쪽 끝을 나타내며 SQL은 저장된 값으로 명명 된 테이블을 조인하는 것을 허용하지 않기 때문에 ActiveRecord는 검토 가능만으로 조인을 작성할 수 없기 때문입니다. 열에. 추가 관계를 정의 belongs_to :shop함으로써 ActiveRecord에 조인을 완료하는 데 필요한 정보를 제공하게됩니다.


6
사실은 내가 더 무엇을 선언하지 않고이를 사용하여 결국 :@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)
빅터

1
그 이유 :reviewableShop. 사진은 Shop에 속합니다.
Victor

6
rails4에서 작동했지만 사용 중단 경고를 표시합니다. has_many : spam_comments,-> {where spam : true}, class_name : 'Comment'와 같은 스타일을 사용해야합니다. 따라서 rails4에서는 belongs_to : shop,-> {where ( "reviews.reviewable_type = 'Shop'")}, foreign_key : 'reviewable_id'가 될 것입니다. 그러나주의하세요. Review.includes (: shop)는 오류를 발생시킵니다. 적어도 하나의 where 절을 추가하십시오.
raykin 2014-04-09

49
비슷한 문제에 대해 저에게 도움이 된 foreign_type도 있습니다.belongs_to :shop, foreign_type: 'Shop', foreign_key: 'reviewable_id'
A5308Y

14
reviews연결된 shop사용 코드 Review.includes(:shop) 를 즉시 로드하는 것을 포함하여 로드 할 때 belongs_to 정의 belongs_to :shop, -> { where(reviews: {reviewable_type: 'Shop'}) }, foreign_key: 'reviewable_id' 는 다음과 같은 오류를 발생시킵니다 missing FROM-clause entry for table "reviews". 나는 다음과 같은 방식으로 정의 belongs_to 업데이트하여 고정 : belongs_to :shop, -> { joins(:reviews) .where(reviews: {reviewable_type: 'Shop'}) }, foreign_key: 'reviewable_id'
Jignesh Gohel

12

ActiveRecord :: EagerLoadPolymorphicError가 발생하면 다형성 연관이 .NET 에서만 지원 될 때 includes호출 하기 로 결정 했기 때문 입니다. 다음 문서에 있습니다. http://api.rubyonrails.org/v5.1/classes/ActiveRecord/EagerLoadPolymorphicError.htmleager_loadpreload

따라서 항상 preload다형성 연관에 사용하십시오. 이에 대한 한 가지주의 사항이 있습니다. where 절에서 다형성 연결을 쿼리 할 수 ​​없습니다 (다형성 연결이 여러 테이블을 나타 내기 때문에 의미가 있음).


가이드에 문서화되지 않은 방법 중 하나 인 guides.rubyonrails.org/…
MSC

0
@reviews = @user.reviews.includes(:user, :reviewable)
.where('reviewable_type = ? AND reviewable.shop_type = ?', 'Shop', 'cafe').references(:reviewable)

WHERE와 함께 SQL 조각을 사용하는 경우 연관을 결합하려면 참조가 필요합니다.


0

부록으로 상단의 대답은 훌륭 :include합니다. 어떤 이유로 사용중인 쿼리에 모델의 테이블이 포함되어 있지 않고 정의되지 않은 테이블 오류가 발생하는 경우 연관에 지정할 수도 있습니다.

이렇게 :

belongs_to :shop, 
           foreign_key: 'reviewable_id', 
           conditions: "reviews.reviewable_type = 'Shop'",
           include: :reviews

:include옵션이 없는 경우 review.shop위의 예 에서 연결에만 액세스 하면 연결이 수행하기 때문에 UndefinedTable 오류 (4가 아닌 Rails 3에서 테스트 됨)가 발생 SELECT FROM shops WHERE shop.id = 1 AND ( reviews.review_type = 'Shop' )합니다.

:include옵션은 대신 JOIN을 강제합니다. :)


5
알 수없는 키 : : conditions. 유효한 키 : : class_name, : class, : foreign_key, : validate, : autosave, : dependent, : primary_key, : inverse_of, : required, : foreign_type, : polymorphic, : touch, : counter_cache
Bengala
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.