【问题标题】:With Rails 4, Model.scoped is deprecated but Model.all can't replace it在 Rails 4 中,不推荐使用 Model.scoped 但 Model.all 无法替换它
【发布时间】:2013-08-13 00:47:50
【问题描述】:

从 Rails 4 开始,Model.scoped 现已弃用。

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

在 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 上的幂等方法,它只返回一个范围。

我应该在这里做什么?

【问题讨论】:

标签: activerecord ruby-on-rails-4


【解决方案1】:

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

【讨论】:

  • 弃用警告说要使用load
  • 它说使用load 如果你想预先加载,并且无论如何它需要一个参数(条件),所以现在where(nil)(或true{}1) 似乎是scoped的最佳替代品
  • 不适用于我的情况:user.active_section.scoped.uniq(false) 有效,user.active_section.all.uniq(false)user.active_section.where(nil).uniq(false) 无效。
  • rails 5 怎么样?
【解决方案2】:

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

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

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

【讨论】:

  • 太好了,感谢您的更新!但是,如果您是 gem 维护者,您必须继续使用 where(nil) 直到 4.0.x 不受支持...
  • 这是一个非常古老的线程,但我们现在才升级,并且还必须保持对 Rails 3 和 4 的支持。按照if ActiveRecord::VERSION::MAJOR == 3 then Model.scoped else Model.all end的思路做事合理吗?
【解决方案3】:

正如其中一个 cmets 所述,all 应该返回一个范围 according to the docs

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

pry(main)> u = User.all;

pry(main)> u.class

=> ActiveRecord::Relation::ActiveRecord_Relation_User

【讨论】:

【解决方案4】:

除了使用where(nil),如果您知道self 是一个关系,您还可以调用clone,并获得与不带参数调用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 确实表现相同。

【讨论】:

  • 你不能在模型类上调用clone。 (例如Model.clonescoped 处理模型类和关系。
  • @kenn 是的,这就是为什么我在上面说'如果你知道 self 是一个关系'。
猜你喜欢
  • 2016-05-09
  • 2021-07-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-02-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多