Ruby-on-rails rails 模型的默认排序顺序?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/3393687/
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 22:59:30  来源:igfitidea点击:

Default sort order for a rails model?

ruby-on-rails

提问by Justin Tanner

I would like to specify a default sort order in my model.

我想在我的模型中指定一个默认的排序顺序。

So that when I do a .where()without specifying an .order()it uses the default sort. But if I specify an .order(), it overrides the default.

因此,当我在.where()不指定 an.order()的情况下执行 a 时,它使用默认排序。但是如果我指定一个.order(),它会覆盖默认值。

回答by Michael Durrant

default_scope

default_scope

This works for Rails 4+:

这适用于 Rails 4+:

class Book < ActiveRecord::Base
  default_scope { order(created_at: :desc) }
end

For Rails 2.3, 3, you need this instead:

对于 Rails 2.3、3,你需要这个:

default_scope order('created_at DESC')

For Rails 2.x:

对于 Rails 2.x:

default_scope :order => 'created_at DESC'

Where created_atis the field you want the default sorting to be done on.

created_at您希望对其进行默认排序的字段在哪里。

Note: ASCis the code to use for Ascending and DESCis for descending (desc, NOTdsc!).

注意:ASC是用于升序的代码,而DESC是用于降序(desc不是dsc!)。

scope

scope

Once you're used to that you can also use scope:

一旦你习惯了,你还可以使用scope

class Book < ActiveRecord::Base
  scope :confirmed, :conditions => { :confirmed => true }
  scope :published, :conditions => { :published => true }
end

For Rails 2 you need named_scope.

对于 Rails 2,您需要named_scope.

:publishedscope gives you Book.publishedinstead of Book.find(:published => true).

:published范围给你Book.published而不是 Book.find(:published => true).

Since Rails 3 you can 'chain' those methods together by concatenating them with periods between them, so with the above scopes you can now use Book.published.confirmed.

从 Rails 3 开始,您可以通过将这些方法用句点连接起来将它们“链接”在一起,因此对于上述范围,您现在可以使用Book.published.confirmed.

With this method, the query is not actually executed until actual results are needed (lazy evaluation), so 7 scopes could be chained together but only resulting in 1 actual database query, to avoid performance problems from executing 7 separate queries.

使用这种方法,直到需要实际结果(惰性求值)时才会实际执行查询,因此可以将 7 个范围链接在一起,但只会产生 1 个实际的数据库查询,以避免执行 7 个单独的查询时出现性能问题。

You can use a passed in parameter such as a date or a user_id (something that will change at run-time and so will need that 'lazy evaluation', with a lambda, like this:

您可以使用传入的参数,例如 date 或 user_id(会在运行时更改的参数,因此需要使用 lambda 进行“惰性求值”,如下所示:

scope :recent_books, lambda 
  { |since_when| where("created_at >= ?", since_when) }
  # Note the `where` is making use of AREL syntax added in Rails 3.

Finally you can disable default scope with:

最后,您可以禁用默认范围:

Book.with_exclusive_scope { find(:all) } 

or even better:

甚至更好:

Book.unscoped.all

which will disable any filter (conditions) or sort (order by).

这将禁用任何过滤器(条件)或排序(排序依据)。

Note that the first version works in Rails2+ whereas the second (unscoped) is only for Rails3+

请注意,第一个版本适用于 Rails2+,而第二个(无作用域)仅适用于 Rails3+



So... if you're thinking, hmm, so these are just like methods then..., yup, that's exactly what these scopes are!
They are like having def self.method_name ...code... endbut as always with ruby they are nice little syntactical shortcuts (or 'sugar') to make things easier for you!

所以......如果你在想,嗯,那么这些就像方法一样......,是的,这正是这些范围!
它们就像拥有def self.method_name ...code... end但与 ruby​​ 一样,它们是很好的小语法快捷方式(或“糖”),可以让您更轻松!

In fact they are Class level methods as they operate on the 1 set of 'all' records.

事实上,它们是类级别的方法,因为它们对 1 组“所有”记录进行操作。

Their format is changing however, with rails 4 there are deprecation warning when using #scope without passing a callable object.For example scope :red, where(color: 'red') should be changed to scope :red, -> { where(color: 'red') }.

然而,它们的格式正在发生变化,在 Rails 4 中,在使用 #scope 而不传递可调用对象时会出现弃用警告。例如 scope :red, where(color: 'red') 应该改为scope :red, -> { where(color: 'red') }.

As a side note, when used incorrectly, default_scope can be misused/abused.
This is mainly about when it gets used for actions like where's limiting (filtering) the defaultselection (a bad ideafor a default) rather than just being used for ordering results.
For whereselections, just use the regular named scopes. and add that scope on in the query, e.g. Book.all.publishedwhere publishedis a named scope.

作为旁注,如果使用不当,默认_scope 可能会被误用/滥用。
这主要是关于它何时用于where限制(过滤)默认选择(默认值的一个坏主意)之类的操作,而不仅仅是用于对结果进行排序。
对于where选择,只需使用常规命名范围。并在查询中添加该范围,例如Book.all.publishedwherepublished是命名范围。

In conclusion, scopes are really great and help you to push things up into the model for a 'fat model thin controller' DRYer approach.

总之,示波器真的很棒,可以帮助您将事情推到模型中,以实现“胖模型瘦控制器”DRYer 方法。

回答by Paul Oliver

A quick update to Michael's excellent answer above.

对迈克尔在上面的出色回答的快速更新。

For Rails 4.0+ you need to put your sort in a block like this:

对于 Rails 4.0+,您需要将排序放在这样的块中:

class Book < ActiveRecord::Base
  default_scope { order('created_at DESC') }
end

Notice that the order statement is placed in a block denoted by the curly braces.

请注意, order 语句放置在由花括号表示的块中。

They changed it because it was too easy to pass in something dynamic (like the current time). This removes the problem because the block is evaluated at runtime. If you don't use a block you'll get this error:

他们改变了它,因为它太容易传递动态的东西(比如当前时间)。这消除了问题,因为块是在运行时评估的。如果您不使用块,您将收到此错误:

Support for calling #default_scope without a block is removed. For example instead of default_scope where(color: 'red'), please use default_scope { where(color: 'red') }. (Alternatively you can just redefine self.default_scope.)

删除了对不带块调用 #default_scope 的支持。例如default_scope where(color: 'red'),请使用代替default_scope { where(color: 'red') }。(或者,您可以重新定义 self.default_scope。)

As @Danmentions in his comment below, you can do a more rubyish syntax like this:

正如@Dan在他下面的评论中提到的,你可以做一个更像这样的rubyish 语法:

class Book < ActiveRecord::Base
  default_scope { order(created_at: :desc) }
end

or with multiple columns:

或多列:

class Book < ActiveRecord::Base
  default_scope { order({begin_date: :desc}, :name) }
end

Thanks @Dan!

谢谢@丹

回答by Slobodan Kovacevic

You can use default_scope to implement a default sort order http://api.rubyonrails.org/classes/ActiveRecord/Scoping/Default/ClassMethods.html

您可以使用 default_scope 来实现默认排序顺序 http://api.rubyonrails.org/classes/ActiveRecord/Scopeing/Default/ClassMethods.html