22

나는 RoR 프로젝트를 가지고있다. 내 모델의 해당 섹션이 있습니다.

has_many :communities, :through => :availabilities
has_many :availabilities, :order => "price ASC"

커뮤니티

has_many :homes, :through => :availabilities
has_many :availabilities

유효성

belongs_to :home
belongs_to :community

데이터베이스의 "사용 가능"테이블에는 추가 데이터 열 "가격"

그래서 지금 전화 할 수 있습니다.

@home.availabilities.each do |a|
  a.community.name
  a.price

원하는대로 가격순으로 정렬 된 사용 가능 여부 데이터를 가져옵니다. 내 질문은 이것이다 :

자동으로 주택을 주문하는 방법이 있습니까?avaliabilities.first.price(첫째 = 최하위)? 어쩌면default_scope :order?

5 답변


25

나는 사용을 피하도록 제안 할 것이다.default_scope특히 다른 테이블에있는 가격 같은 것. 해당 테이블을 사용할 때마다 조인 및 정렬이 수행되어 복잡한 쿼리에서 이상한 결과를 가져오고 어쨌든 쿼리를 느리게 만듭니다.

자신의 범위에있어 아무 문제가 없습니다. 더 간단하고 더 명확합니다. 다음과 같이 간단하게 만들 수 있습니다.

scope :ordered, -> { includes(:availabilities).order('availabilities.price') }

추신 :에 인덱스를 추가하는 것을 잊지 마세요.price


  • 당신이 사용해야합니까includes조인 대신에? - Jwan622
  • 의존, @ TeWu는 그의 대답의 차이를 설명하는 데 훌륭한 일을하고 있습니다. 특히 Tom Dallimore의 블로그 링크는 정말 멋지다. - ecoologic

21

도움으로 그것을 알아 냈어.이 관련 게시물.

주문을 홈 모델에서 가용성 모델로 옮겼습니다.

유효성

default_scope :order => "price ASC"

그런 다음 홈 모델에 가용성을로드하고 가격순으로 정렬하겠습니다.

default_scope :include => :availabilities, :order => "availabilities.price ASC"


8

@ecoologic대답:

scope :ordered, -> { includes(:availabilities).order('availabilities.price') }

위대한입니다,하지만 그것은 언급되어야합니다includes수 있습니다, 그리고 어떤 경우에는에 의해 대체되어야합니다joins.둘 다 최적의 사용 사례를가집니다..

실용적인 관점에서 두 가지 주요 차이점이 있습니다.

  1. includes관련 레코드를로드한다. 이 경우Availability기록.joins연관된 레코드를로드하지 마십시오. 그래서 당신은includes예를 들어 조인 모델의 데이터를 사용하려는 경우. 디스플레이price어딘가에. 한편,joins쿼리에서 조인 모델의 데이터 만 사용하려는 경우에 사용해야합니다. ...에서ORDER BY또는WHERE조항.

  2. includes모든 레코드를로드하는 동시에joins연관된 조인 모델이있는 레코드 만로드합니다. 그래서 OP의 경우,Home.includes(:availabilities)모든 집을 짐을Home.joins(:availabilities)최소한 하나의 가용성을 가진 주택 만 적재하게됩니다.

참조이 질문.


2

Rails 5.2 이상에서는 문자열 매개 변수를 주문 메소드에 전달할 때 사용 중단 경고가 표시 될 수 있습니다.

DEPRECATION WARNING : 속성이 아닌 인수 ( "s :"table.column ")로 불리는 위험한 쿼리 메서드 (인수가 원시 SQL로 사용되는 메서드). Rails 6.0에서는 비 속성 인수가 허용되지 않습니다. 이 메소드는 요청 매개 변수 또는 모델 속성과 같은 사용자 제공 값으로 호출하면 안됩니다.

이 문제를 해결하려면Arel.sql():

scope :ordered, -> {
  includes(:availabilities).order(Arel.sql('availabilities.price'))
}


1

이것을 달성하는 또 다른 방법은 다음과 같습니다.

scope :ordered, -> { includes(:availabilities).order(Availability.arel_table[:price]) }

당신은 또한 지정할 수 있습니다ASC방향과 함께

scope :ordered, -> { includes(:availabilities).order(Availability.arel_table[:price].asc) }

DESC:

scope :ordered, -> { includes(:availabilities).order(Availability.arel_table[:price].desc) }

사용arel_table...에ActiveRecord모델을 사용하면 테이블 이름이 변경되었을 때 시나리오를 저장할 수 있습니다 (그러나 매우 드물게 발생합니다).

추가하는 것이 좋습니다.main_table#id결정적인 정렬을 위해.

최종 버전은 다음과 같습니다.

scope :ordered, -> {
  includes(:availabilities).
    order(Availability.arel_table[:price].asc, order(Home.arel_table[:id].asc)
}

연결된 질문


관련된 질문

최근 질문