77

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

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

Model.scoped但是, and有区别Model.all,即scoped.scoped返回一个范围,同时all.all运行查询。

在 Rails 3 上:

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

在 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

如果您将其更改scopedall,您将面临随机问题,具体取决于在among作用域链中使用的位置。例如,Model.where(some: value).among(ids)将运行查询而不是返回范围。

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

我应该在这里做什么?

4

4 回答 4

64

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

于 2013-08-13T01:32:08.943 回答
25

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

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

所以看来这个问题已经解决了,并且在 4.1.0Model.scoped中已经被完全删除了。

于 2013-12-26T20:48:58.097 回答
9

正如其中一条评论中提到的,应该根据 docsall返回一个范围。

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

pry(main)> u = User.all;

pry(main)> u.class

=> ActiveRecord::Relation::ActiveRecord_Relation_User
于 2013-12-02T20:19:13.250 回答
4

除了使用之外,如果您知道这是一个关系,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

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

于 2013-08-20T05:57:04.267 回答