Rails:rails 模型的默认排序顺序?

Posted

技术标签:

【中文标题】Rails:rails 模型的默认排序顺序?【英文标题】:Rails: Default sort order for a rails model? 【发布时间】:2011-03-24 13:10:12 【问题描述】:

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

所以当我执行.where() 而不指定.order() 时,它使用默认排序。但是如果我指定.order(),它会覆盖默认值。

【问题讨论】:

【参考方案1】:

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 是用于降序的代码(desc , 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 =&gt; 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 一样,但与 ruby​​ 一样,它们是很好的小语法快捷方式(或“糖”),可以让你更轻松!

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

然而,它们的格式正在改变,在使用 rails 4 时,在不传递可调用对象的情况下使用 #scope 时会出现弃用警告。 例如,范围:red,where(color: 'red') 应更改到scope :red, -&gt; where(color: 'red')

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

总之,范围真的很棒,可以帮助您将事物推入模型中,以实现“胖模型瘦控制器”DRYer 方法。

【讨论】:

顺便说一句,有没有办法将默认范围引用为排序顺序?喜欢Book.order(:default_scope) default_scope order("#table_name.created_at DESC") 不是更安全吗? Rails 4:default_scope order(created_at: :desc) 至少4.2.6 似乎按updated_at 而不是created_at 排序。 @AinTohvri 是对的。这让我在 Rails 4.2 中感到惊讶。为什么默认按updated_at 排序? :-|【参考方案2】:

快速更新迈克尔的上述出色答案。

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

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

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

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

删除了对不带块调用 #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

谢谢@Dan!

【讨论】:

在 rails 4 中,如果您像我一样尝试最小化 rails 中的 sql 语法,也可以写成 default_scope order(created_at: :desc) 。如果您有多个列要排序并且想要使用您可能需要的新语法将 desc 列包装成这样的小胡子 default_scope order(begin_date: :desc, :name) @Dan - 您的评论不仅消除了 SQL,而且是一种更加 Rubyish 的语法。【参考方案3】:

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

【讨论】:

链接正常,但该页面上没有任何关于 default_scope 的内容,因为它已从 ActiveRecord::Base 重构为 ActiveRecord::Scoping::Default::ClassMethods (api.rubyonrails.org/classes/ActiveRecord/Scoping/Default/…)

以上是关于Rails:rails 模型的默认排序顺序?的主要内容,如果未能解决你的问题,请参考以下文章

Rails:如何为 Rails activerecord 模型中的属性创建默认值? [复制]

非确定性Rails关联默认顺序?

Rails - 为多个设计模型配置默认值

如何更改 Rails 脚手架中的默认模型模板?

Rails 单选按钮:根据模型/数据库条目设置默认值

覆盖rails3中模型名称的默认复数