这似乎是一个非常简单的问题,但我没有看到它在任何地方得到解答。
如果您有以下内容,请使用rails:
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 }
但有些东西告诉我它应该更简单。我错过了什么?
答案 0 :(得分:146)
您可以使用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。
答案 1 :(得分:37)
从Rails 4开始,你会这样做:
class Article < ActiveRecord::Base
has_many :comments, -> { order(created_at: :desc) }
end
class Comment < ActiveRecord::Base
belongs_to :article
end
对于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
然而,这对reasons discussed in this question来说可能有问题。
在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
答案 2 :(得分:7)
如果您使用的是Rails 2.3并希望对此对象的所有集合使用相同的默认顺序,则可以使用default_scope来订购您的集合。
class Student < ActiveRecord::Base
belongs_to :class
default_scope :order => 'name'
end
然后,如果你打电话
@students = @class.students
将根据您的default_scope订购它们。 TBH在一般意义上排序是对默认范围的唯一真正好用。
答案 3 :(得分:6)
您可以使用ActiveRecord的find方法获取对象并对其进行排序。
@article.comments.find(:all, :order => "created_at DESC")
http://api.rubyonrails.org/classes/ActiveRecord/Associations/ClassMethods.html
答案 4 :(得分:0)
如果你需要传递一些额外的参数,比如dependent: :destroy
或其他什么,你应该在lambda之后追加一些,如下:
class Article < ActiveRecord::Base
has_many :comments, -> { order(created_at: :desc) }, dependent: :destroy
end