Rails 4中has_many带有order的已弃用警告

112
class RelatedList < ActiveRecord::Base
  extend Enumerize

  enumerize :list_type, in: %w(groups projects)

  belongs_to :content
  has_many :contents, :order => :position

end

在我的Rails应用程序中,我有这个模型,在控制台中尝试创建记录时会出现警告。

DEPRECATION WARNING:您的RelatedList.has_many:contents声明中以下选项已过时::order。请改用范围块。例如,以下内容:has_many:spam_comments,条件:{spam:true},class_name:'Comment'应重写为以下内容:has_many:spam_comments, -> {where spam: true},class_name:'Comment' . (来自 /Users/shivam/Code/auroville/avorg/app/models/related_list.rb:7 的调用)

看起来Rails 4在模型中有新的:order语法,但我似乎找不到Rails指南中的文档。

5个回答

257
在Rails 4中,:order 已被弃用,需要使用 lambda 范围块来替换,就像你在问题中发布的警告一样。另一个需要注意的是,这个范围块需要传递在其他关联选项之前,例如dependent: :destroy等。

试试这个:

has_many :contents, -> { order(:position) } # Order by :asc by default

要指定排序方向,即使用 ascdesc,如 @joshua-coady 和 @wsprujit 所建议的,请使用:

has_many :contents, -> { order 'position desc' }

或者,使用哈希风格:

has_many :contents, -> { order(position: :desc) }

Active Record Scopes for has_many的更多参考内容。


3
非常出色!在指南或文档中可以找到这样的信息吗?我找不到。谢谢。 - shankardevy
6
如果你有多个被弃用的选项,比如 orderinclude,该怎么办?这段代码:{ order(:position), include(:track) } 在逗号处会报错。 - kakubei
2
要进行升序/降序排序,请使用 -> { order(name: :asc) } - wspruijt
1
如果出于某些原因,您只想有时对集合进行排序,您也可以执行 list.contents.order('position desc'),这可能更有效,并且不会像模型侵入性那样(在投票答案中,列表知道内容字段,而在此处控制器知道它)。 - Dirty Henry
这给了我一个错误信息:“语法错误,意外的'\n',期望=>' - - 但是没有使用新方法中的“=>”。使用wspruijt的版本,我得到了错误:“语法错误,意外的tLABEL ...,-> { order (created_at: :desc) }”。可惜Rails 4现在放弃了旧的更清晰的语法,转而采用这种无意义的语法。似乎如果你有任何其他条件,它们都必须进入一些花括号痉挛中,否则你不能再对模型进行排序了。 - JosephK

38

我花了一些时间才弄清楚如何进行排序和包含,最终发现可以链式调用作用域语句。

has_many :things, -> { includes(:stuff).order("somedate desc") }, class_name: "SomeThing"

2
这正是我的问题。试图弄清如何通过父属性对has_many关系进行排序。没有意识到可以像这样使用includes然后排序。谢谢! - timothyashaw

31

只是想补充一下,如果您有任何选项哈希参数,它们必须放在lambda后面,就像这样:

has_many :things, -> { order :stuff }, dependent: :destroy

我自己花了一分钟才理解这个问题 - 希望这能帮助到其他遇到同样问题的人。


3
这也适用于对象上可能存在的“通过”关联 - has_many :items, -> { order 'name' }, through: :suppliers - Major Major
谢谢,我也用了依赖选项进行搜索!!谢谢。 - Matrix

0

这对我来说在Rails 4和MongoDB上可行。

has_many :discounts, order: :min_amount.asc

-4

或者,您可以将order子句放在模型上,例如:

has_many :options, order: 'name' # In class Answer

变成

has_many :options # In class Answer

default_scope { order 'name' } # In class Option

PS:在执行has_many :things, -> {}时,我遇到了ArgumentError: wrong number of arguments (1 for 0)的错误。


4
不要使用默认作用域。如果你习惯这样做,可以在那个特殊方法中添加更多的逻辑。将来很难覆盖它。 - Grzegorz Łuszczek

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接