Rails에서 has_many 관계를 자동으로 정렬하려면 어떻게해야합니까?


96

이것은 정말 간단한 질문처럼 보이지만 어디에서도 대답을 보지 못했습니다.

레일에 다음이있는 경우 :

class Article < ActiveRecord::Base 
  has_many :comments 
end 
class Comments < ActiveRecord::Base 
  belongs_to :article 
end

다음과 같이 주석을 주문할 수없는 이유는 무엇입니까?

@article.comments(:order=>"created_at DESC")

명명 된 범위는 많은 참조가 필요하고 사람들도 다음과 같은 작업을 수행하는 경우에 작동합니다.

@article.comments.sort { |x,y| x.created_at <=> y.created_at }

그러나 뭔가 더 간단해야한다고 말해줍니다. 내가 무엇을 놓치고 있습니까?


예기치 않은 방법을 사용하고 있습니다. @ article.comments (reload = false)는 캐시 미스 (관계를 강제로 다시로드하기 위해)를 강제하는 것입니다. 해시를 제공하면 @ article.comments (true)와 동일합니다. .all (: order => '...')을 사용하는 것을 잊지 마십시오. 벌써 몇 번 다리가 부러졌습니다.
Marcel Jackwerth 2009

답변:


152

has_many자체 옵션을 사용하여 베어 컬렉션의 정렬 순서를 지정할 수 있습니다 .

class Article < ActiveRecord::Base 
  has_many :comments, :order => 'created_at DESC'
end 
class Comment < ActiveRecord::Base 
  belongs_to :article 
end

또는 데이터베이스가 아닌 간단한 정렬 방법을 원하면 sort_by를 사용 하십시오 .

article.comments.sort_by &:created_at

ActiveRecord가 추가 한 주문 방법으로이를 수집 :

article.comments.find(:all, :order => 'created_at DESC')
article.comments.all(:order => 'created_at DESC')

마일리지는 다를 수 있습니다. 위 솔루션의 성능 특성은 처음에 데이터를 가져 오는 방법과 앱을 실행하는 데 사용하는 Ruby에 따라 크게 달라집니다.


감사합니다. "모두"가 아마도 가장 간단합니다. 좋은 물건!
Brian Armstrong

58
Rails 4에서는 주문 옵션이 제거되었습니다. -> { order(created_at: :desc) }대신 람다 를 사용하십시오 . 참조 : stackoverflow.com/questions/18284606/…
d_rail 2014

이것은 rails 4에서 더 이상 사용되지 않습니다. 참조 : stackoverflow.com/questions/18284606/…
bjelli

41

Rails 4에서는 다음을 수행합니다.

class Article < ActiveRecord::Base 
  has_many :comments, -> { order(created_at: :desc) }
end 
class Comment < ActiveRecord::Base 
  belongs_to :article 
end

A에 대한 has_many :through관계 인수 순서는 (은 두 번째 수있다) 중요한 :

class Article
  has_many :comments, -> { order('postables.sort' :desc) }, 
           :through => :postable
end

당신은 항상 어떤 상황을 중요한 순서대로 액세스 의견을 원하지 않을 경우 당신은 또한을 통해이 작업을 수행 할 수 있습니다 default_scope내에서 Comment같은 :

class Comment < ActiveRecord::Base 
  belongs_to :article 
  default_scope { order(created_at: :desc) }
end

그러나 이것은 이 질문에서 논의 된 이유 때문에 문제가 될 수 있습니다 .

Rails 4 이전 order에는 다음과 같이 관계에 대한 키로 지정할 수있었습니다 .

class Article < ActiveRecord::Base 
  has_many :comments, :order => 'created_at DESC'
end 

Jim이 언급했듯이 sort_by 결과를 가져온 후에도 있지만 크기의 결과 집합에서는 SQL / ActiveRecord를 통해 주문하는 것보다 훨씬 더 느리고 더 많은 메모리를 사용합니다.

어떤 이유로 기본 주문을 추가하는 것이 번거로운 작업을 수행하거나 특정 경우에 기본값을 재정의하려는 경우 가져 오기 작업 자체에서 지정하는 것은 간단합니다.

sorted = article.comments.order('created_at').all

1
가져 오기 작업 자체에서 어디에서 지정할 수 있습니까? 모델의 메서드를 재정의합니까?
Wit

@Wit- .order()마지막 예제와 같이 메소드 체인에 추가 할 수 있습니다 . 이것이 당신이 요구하는 것입니까?
Matt Sanders

미안 해요. 내가 무엇을 성취하려고했는지 기억이 나지 않습니다.
Wit

1
다형성 예제를 통한 has_many는 여기에서 매우 유용합니다!
Vijay

7

Rails 2.3을 사용 중이고이 객체의 모든 컬렉션에 대해 동일한 기본 순서를 사용하려면 default_scope를 사용하여 컬렉션을 정렬 할 수 있습니다.

class Student < ActiveRecord::Base
  belongs_to :class

  default_scope :order => 'name'

end

그럼 전화하면

@students = @class.students

기본 범위에 따라 주문됩니다. 매우 일반적인 의미에서 TBH는 기본 범위를 정말 잘 사용하는 유일한 방법입니다.


Rails 4부터는이를 준수하지 않습니다. 올바른 Rails 4 구문은이 솔루션을 참조하십시오. stackoverflow.com/questions/18506038/rails-4-default-scope
Kees Briggs


0

추가 인수를 전달해야하는 경우 다음과 같이 dependent: :destroy람다 뒤에 인수 를 추가해야합니다.

class Article < ActiveRecord::Base 
  has_many :comments, -> { order(created_at: :desc) }, dependent: :destroy
end
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.