如何在Rails中自动排序has_many关系?

Bri*_*ong 96 ruby-on-rails

这似乎是一个非常简单的问题,但我还没有看到它在任何地方得到解答.

在rails中如果您有:

class Article < ActiveRecord::Base 
  has_many :comments 
end 
class Comments < ActiveRecord::Base 
  belongs_to :article 
end
Run Code Online (Sandbox Code Playgroud)

为什么你不能用这样的东西订购评论:

@article.comments(:order=>"created_at DESC")
Run Code Online (Sandbox Code Playgroud)

如果您需要经常引用命名范围,甚至人们都会这样做:

@article.comments.sort { |x,y| x.created_at <=> y.created_at }
Run Code Online (Sandbox Code Playgroud)

但有些东西告诉我它应该更简单.我错过了什么?

Jim*_*uls 148

您可以使用选项指定裸集合的排序顺序has_many:

class Article < ActiveRecord::Base 
  has_many :comments, :order => 'created_at DESC'
end 
class Comment < ActiveRecord::Base 
  belongs_to :article 
end
Run Code Online (Sandbox Code Playgroud)

或者,如果您想要一种简单的非数据库排序方法,请使用sort_by:

article.comments.sort_by &:created_at
Run Code Online (Sandbox Code Playgroud)

使用ActiveRecord添加的排序方法收集此信息:

article.comments.find(:all, :order => 'created_at DESC')
article.comments.all(:order => 'created_at DESC')
Run Code Online (Sandbox Code Playgroud)

您的里程可能会有所不同:上述解决方案的性能特征会发生巨大变化,具体取决于您首先获取数据的方式以及您用来运行应用程序的Ruby.

  • 在Rails 4中,订单选项已被删除.请使用lambda` - > {order(created_at :: desc)}`.请参阅:http://stackoverflow.com/questions/18284606/deprecated-warning-for-rails-4-model-with-order (56认同)

Mat*_*ers 38

从Rails 4开始,你会这样做:

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

对于has_many :through关系,参数顺序很重要(它必须是第二个):

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

如果你总是希望访问在同一顺序的意见,不管上下文中,您还可以通过做这个default_scope范围内Comment,如:

class Comment < ActiveRecord::Base 
  belongs_to :article 
  default_scope { order(created_at: :desc) }
end
Run Code Online (Sandbox Code Playgroud)

但是,由于此问题中讨论原因,这可能会有问题.

在Rails 4之前,您可以指定order关系的关键字,例如:

class Article < ActiveRecord::Base 
  has_many :comments, :order => 'created_at DESC'
end 
Run Code Online (Sandbox Code Playgroud)

正如Jim提到的那样,你也可以sort_by在获取结果后使用,尽管在任何结果集中,这将比通过SQL/ActiveRecord进行排序要慢得多(并且使用更多的内存).

如果您正在做某些事情,由于某种原因添加默认订单很麻烦,或者您想在某些情况下覆盖默认值,那么在提取操作本身中指定它是很简单的:

sorted = article.comments.order('created_at').all
Run Code Online (Sandbox Code Playgroud)


nit*_*der 7

如果您正在使用Rails 2.3并希望对此对象的所有集合使用相同的默认顺序,则可以使用default_scope来对集合进行排序.

class Student < ActiveRecord::Base
  belongs_to :class

  default_scope :order => 'name'

end
Run Code Online (Sandbox Code Playgroud)

然后,如果你打电话

@students = @class.students
Run Code Online (Sandbox Code Playgroud)

它们将按照default_scope进行订购.TBH在一般意义上排序是默认范围的唯一真正好用.


vri*_*h88 6

您可以使用ActiveRecord的find方法来获取对象并对其进行排序.

  @article.comments.find(:all, :order => "created_at DESC")
Run Code Online (Sandbox Code Playgroud)

http://api.rubyonrails.org/classes/ActiveRecord/Associations/ClassMethods.html

  • 或简写方法@ article.comments.all(:order =>'created_at DESC') (3认同)