Rails模型的默认排序顺序?


255

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

这样,当我.where()不指定而进行操作时,.order()它将使用默认排序。但是,如果指定.order(),它将覆盖默认值。

Answers:


544

default_scope

这适用于Rails 4+:

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

对于Rails 2.3、3,您需要以下代码:

default_scope order('created_at DESC')

对于Rails 2.x:

default_scope :order => 'created_at DESC'

created_at您要在其中进行默认排序的字段在哪里。

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

scope

一旦习惯了,也可以使用scope

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

对于Rails 2,您需要named_scope

:published范围Book.published代替了 Book.find(:published => true)

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

使用这种方法,直到需要实际结果(惰性评估)时才实际执行查询,因此可以将7个作用域链接在一起,但只能导致1个实际数据库查询,以避免执行7个独立查询时出现性能问题。

您可以使用传入的参数,例如日期或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.

最后,您可以使用以下命令禁用默认范围:

Book.with_exclusive_scope { find(:all) } 

甚至更好:

Book.unscoped.all

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

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


所以 ……如果您在想,嗯,那么这些就像方法一样……是的,这正是这些作用域!
它们就像def self.method_name ...code... end拥有红宝石一样,但是像往常一样,它们是不错的语法上捷径(或“糖”),可以使您更轻松地工作!

实际上,它们是对1组“全部”记录进行操作的类级别方法。

它们的格式正在改变,但是在使用#scope而不传递可调用对象的情况下使用rails 4会出现过时警告。例如scope:red,where(color:'red')应该更改为scope :red, -> { where(color: 'red') }

附带说明,如果使用不当,则会滥用/滥用默认 _scope。
这主要是关于何时将其用于诸如where限制(过滤)默认选择(对于默认值的一个坏主意)之类的操作,而不仅仅是将其用于排序结果。
对于where选择,只需使用常规的命名范围。并在查询中添加该范围,例如Book.all.published哪里published是命名范围。

总而言之,范围确实很棒,可以帮助您通过“胖模型瘦控制器” DRYer方法将内容推入模型。


1
使用它作为在这个职位描述之前,请考虑戴夫·托马斯关于使用default_scope警告:pragdave.blogs.pragprog.com/pragdave/2012/03/...
雷托

3
这样做会更安全default_scope { order("#{table_name}.created_at DESC") }吗?
cyrilchampier 2014年

37
Rails 4:default_scope { order(created_at: :desc) }
Marcus

2
至少4.2.6似乎updated_at不是这样created_at
艾因·托夫里

2
@AinTohvri是正确的。在Rails 4.2中,这让我感到惊讶。为什么updated_at默认情况下排序?:-|
styty4bit17年

112

快速更新了迈克尔在上面的出色答案。

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

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

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

他们更改了它,因为传递动态内容(例如当前时间)太容易了。由于该块是在运行时评估的,因此可以消除问题。如果不使用块,则会出现此错误:

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

就像@Dan在下面的评论中提到的那样,您可以像这样使用更红宝石的语法:

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

或具有多列:

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

谢谢@丹


28
在rails 4中也可以这样写default_scope { order(created_at: :desc) },就像您尝试最小化rails中的sql语法一样。<br/>如果要对多列进行排序并且要使用新语法,则可能需要包装desc像这样的胡须中的列default_scope { order({begin_date: :desc}, :name) }
2014年

1
@Dan-您的注释不仅消除了SQL,而且还具有Rubyish语法。
B 2015年

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.