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

ken*_*enn 76 activerecord ruby-on-rails-4

Model.scoped现在不推荐使用Rails 4 .

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

但是,有一个区别Model.scopedModel.all,也就是说,scoped.scoped返回一个范围,而all.all运行该查询.

在Rails 3上:

> Model.scoped.scoped.is_a?(ActiveRecord::Relation)
=> true
Run Code Online (Sandbox Code Playgroud)

在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
Run Code Online (Sandbox Code Playgroud)

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

module AmongConcern
  extend ActiveSupport::Concern

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

      where(id: ids)
    end
  end
end
Run Code Online (Sandbox Code Playgroud)

如果你想改变这个scopedall,你会面临因在随机的问题among是在作用域链中.例如,Model.where(some: value).among(ids)将运行查询而不是返回范围.

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

我该怎么办?

ken*_*enn 63

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

  • 我的天,真的吗?WTF. (55认同)

Oli*_*can 25

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

Model.all.all.is_a?(ActiveRecord::Relation)
=> true
Run Code Online (Sandbox Code Playgroud)

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

  • 太好了,谢谢你的更新!但是,如果你是一个gem维护者,你必须继续使用`where(nil)`直到4.0.x不受支持... (2认同)

小智 9

正如其中一条评论所述,all应该根据文档返回范围.

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

pry(main)> u = User.all;

pry(main)> u.class

=> ActiveRecord::Relation::ActiveRecord_Relation_User
Run Code Online (Sandbox Code Playgroud)


And*_*ing 5

除了使用之外,如果您知道这是一个关系,where(nil)您还可以调用并获得与不带参数的调用相同的行为,而不会出现弃用警告。cloneselfscoped

编辑

我现在使用此代码作为替代品,因为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
Run Code Online (Sandbox Code Playgroud)

我不明白为什么 AR 作者不能做类似的事情,因为正如 OP 指出的那样,all并且行为scoped一样