developer tip

열망 부하 다형성

copycodes 2020. 8. 23. 09:23
반응형

열망 부하 다형성


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) 기준으로 필터링하려면 어떻게 해야합니까?


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

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에 조인을 완료하는 데 필요한 정보를 제공하게됩니다.


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

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


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

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


As an addendum the answer at the top, which is excellent, you can also specify :include on the association if for some reason the query you are using is not including the model's table and you are getting undefined table errors.

Like so:

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

Without the :include option, if you merely access the association review.shop in the example above, you will get an UndefinedTable error ( tested in Rails 3, not 4 ) because the association will do SELECT FROM shops WHERE shop.id = 1 AND ( reviews.review_type = 'Shop' ).

The :include option will force a JOIN instead. :)

참고URL : https://stackoverflow.com/questions/16123492/eager-load-polymorphic

반응형