Reputation: 3343
Starting Rails 4, Model.scoped
is now deprecated.
DEPRECATION WARNING: Model.scoped is deprecated. Please use Model.all instead.
But, there's a difference inModel.scoped
and Model.all
, that is, scoped.scoped
returns a scope, while all.all
runs the query.
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
There are use cases in libraries / concerns that returns scoped
when there's a conditional to do something or nothing, like so:
module AmongConcern
extend ActiveSupport::Concern
module ClassMethods
def among(ids)
return scoped if ids.blank?
where(id: ids)
end
end
end
If you'd change this scoped
to all
, you'd face random problems depending where the among
was used in the scope chain. For instance, Model.where(some: value).among(ids)
would run the query instead of returning a scope.
What I want is an idempotent method on ActiveRecord::Relation
that simply returns a scope.
What should I do here?
Upvotes: 78
Views: 21594
Reputation: 346
As mentioned in one of the comments, all
is supposed to return a scope according to the docs.
The docs are correct -- it does return an ActiveRecord::Relation, but you have to use a semi-colon if you want to see it in the console:
pry(main)> u = User.all;
pry(main)> u.class
=> ActiveRecord::Relation::ActiveRecord_Relation_User
Upvotes: 9
Reputation: 2639
On Rails 4.1 (beta 1), the following works:
Model.all.all.is_a?(ActiveRecord::Relation)
=> true
So it appears this issue has been fixed, and in 4.1.0 Model.scoped
has been removed altogether.
Upvotes: 25
Reputation: 6366
In addition to using where(nil)
you can also call clone
if you know that self
is a Relation and get the identical behaviour of calling scoped
with no args, sans the deprecation warning.
EDIT
I am now using this code as a drop in replacement for scoped
since I don't like using where(nil)
everywhere I need to get hold of the current scope:
# 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
I don't see why the AR authors couldn't have done something similar since as the OP points out all
and scoped
do not behave the same.
Upvotes: 5
Reputation: 3343
It seems that where(nil)
is a real replacement of scoped
, which works both on Rails 3 and 4. :(
Upvotes: 67