使用Rails 4时,不推荐使用Model.scoped,但Model.all不能替换它

时间:2013-08-13 00:47:51

标签: activerecord ruby-on-rails-4

启动Rails 4,Model.scoped现已弃用。

DEPRECATION WARNING: Model.scoped is deprecated. Please use Model.all instead.

但是,Model.scopedModel.all存在差异,即scoped.scoped返回范围,all.all运行查询。

On Rails 3:

> Model.scoped.scoped.is_a?(ActiveRecord::Relation)
=> true

On Rails 4:

> Model.all.all.is_a?(ActiveRecord::Relation)
DEPRECATION WARNING: Relation#all is deprecated. If you want to eager-load a relation, you can call #load (e.g. `Post.where(published: true).load`). If you want to get an array of records from a relation, you can call #to_a (e.g. `Post.where(published: true).to_a`).
=> false

当有条件执行某些操作或没有任何操作时,库/关注点中的用例会返回scoped,如下所示:

module AmongConcern
  extend ActiveSupport::Concern

  module ClassMethods
    def among(ids)
      return scoped if ids.blank?

      where(id: ids)
    end
  end
end

如果您将此scoped更改为all,则会遇到随机问题,具体取决于范围链中among的使用位置。例如,Model.where(some: value).among(ids)将运行查询而不是返回范围。

我想要的是ActiveRecord::Relation上的幂等方法,它只返回一个范围。

我该怎么办?

4 个答案:

答案 0 :(得分:63)

似乎where(nil)scoped的真正替代品,它适用于Rails 3和4 :(

答案 1 :(得分:25)

在Rails 4.1(beta 1)上,以下工作:

Model.all.all.is_a?(ActiveRecord::Relation)
=> true

所以看来这个问题已得到修复,并且在4.1.0 Model.scoped中已完全删除。

答案 2 :(得分:9)

如其中一条评论所述,all应该返回范围according to the docs

文档是正确的 - 它确实返回一个ActiveRecord :: Relation,但如果你想在控制台中看到它,你必须使用分号:

pry(main)> u = User.all;

pry(main)> u.class

=> ActiveRecord::Relation::ActiveRecord_Relation_User

答案 3 :(得分:4)

除了使用where(nil)之外,如果您知道clone是一个关系,并且在没有args的情况下调用self的行为相同,那么您也可以调用scoped弃用警告。

修改

我现在使用此代码代替scoped,因为我不想在我需要掌握当前范围的任何地方使用where(nil)

     # config/initializers/scoped.rb
     class ActiveRecord::Base
       # do things the modern way and silence Rails 4 deprecation warnings
       def self.scoped(options=nil)
         options ? where(nil).apply_finder_options(options, true) : where(nil)
       end
     end

我不明白为什么AR作者不能做类似的事情,因为OP指出allscoped的行为同样的。