使用Rails 4,Model.scoped已被弃用,但Model.all不能替代它

启动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 (eg `Post.where(published: true).load`). If you want to get an array of records from a relation, you can call #to_a (eg `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 scoped ,您将面临随机问题,具体取决于在范围链中使用哪个范围。 例如, Model.where(some: value).among(ids)将运行查询,而不是返回范围。

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

我应该在这里做什么?

看来, where(nil)scoped的真正的替代,这对Rails 3和4都有效。:(

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

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

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

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

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

 pry(main)> u = User.all; pry(main)> u.class => ActiveRecord::Relation::ActiveRecord_Relation_User 

除了使用where(nil)之外,如果你知道self是一个Relation,并且调用scoped时没有参数,那么你也可以调用clone ,这样可以避免使用deprecation警告。

编辑

我现在使用这个代码作为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行为都不一样。