Ruby-on-rails 如何在 Rails 中自动对 has_many 关系进行排序?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/738971/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-02 21:07:15  来源:igfitidea点击:

How do I automatically sort a has_many relationship in Rails?

ruby-on-rails

提问by Brian Armstrong

This seems like a really simple question but I haven't seen it answered anywhere.

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

In rails if you have:

在 Rails 中,如果您有:

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

Why can't you order the comments with something like this:

为什么你不能用这样的东西对评论进行排序:

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

Named scope works if you need to reference it a lot and even people do stuff like this:

如果您需要大量引用命名范围,甚至人们也会这样做:

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

But something tells me it should be simpler. What am I missing?

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

回答by Jim Puls

You can specify the sort order for the bare collection with an option on has_manyitself:

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

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

Or, if you want a simple, non-database method of sorting, use sort_by:

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

article.comments.sort_by &:created_at

Collecting this with the ActiveRecord-added methods of ordering:

使用 ActiveRecord 添加的排序方法收集它:

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

Your mileage may vary: the performance characteristics of the above solutions will change wildly depending on how you're fetching data in the first place and which Ruby you're using to run your app.

您的进展可能会有所不同:上述解决方案的性能特征将发生巨大变化,具体取决于您首先如何获取数据以及您使用哪种 Ruby 来运行您的应用程序。

回答by Matt Sanders

As of Rails 4, you would do:

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

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

For a has_many :throughrelationship the argument order matters (it has to be second):

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

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

If you will always want to access comments in the same order no matter the context you could also do this via default_scopewithin Commentlike:

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

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

However this can be problematic for the reasons discussed in this question.

然而,由于这个问题中讨论原因,这可能是有问题的

Before Rails 4 you could specify orderas a key on the relationship, like:

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

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

As Jim mentioned you can also use sort_byafter you have fetched results although in any result sets of size this will be significantly slower (and use a lot more memory) than doing your ordering through SQL/ActiveRecord.

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

If you are doing something where adding a default order is cumbersome for some reason or you want to override your default in certain cases, it is trivial to specify it in the fetching action itself:

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

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

回答by nitecoder

If you are using Rails 2.3 and want to use the same default ordering for all collections of this object you can use default_scope to order your collection.

如果您使用的是 Rails 2.3 并希望对这个对象的所有集合使用相同的默认排序,您可以使用 default_scope 来排序您的集合。

class Student < ActiveRecord::Base
  belongs_to :class

  default_scope :order => 'name'

end

Then if you call

那么如果你打电话

@students = @class.students

They will be ordered as per your default_scope. TBH in a very general sense ordering is the only really good use of default scopes.

它们将根据您的 default_scope 进行排序。TBH 在非常一般的意义上排序是默认范围的唯一真正好的用途。

回答by vrish88

You can use ActiveRecord's find method to get your objects and sort them too.

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

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

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

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

回答by Max L.

And if you need to pass some additional arguments like dependent: :destroyor whatever, you should append the ones after a lambda, like this:

如果你需要传递一些额外的参数,比如dependent: :destroy或其他什么,你应该在 lambda 之后附加这些参数,如下所示:

class Article < ActiveRecord::Base 
  has_many :comments, -> { order(created_at: :desc) }, dependent: :destroy
end