Overriding a Rails default_scope

Ruby on-Rails

Ruby on-Rails Problem Overview


If I have an ActiveRecord::Base model with a default-scope:

class Foo < ActiveRecord::Base

  default_scope :conditions => ["bar = ?",bar]

end

Is there any way to do a Foo.find without using the default_scope conditions? In other words, can you override a default scope?

I would have thought that using 'default' in the name would suggest that it was overridable, otherwise it would be called something like global_scope, right?

Ruby on-Rails Solutions


Solution 1 - Ruby on-Rails

In Rails 3:

foos = Foo.unscoped.where(:baz => baz)

Solution 2 - Ruby on-Rails

Short answer: Do not use default_scope unless you really have to. You'll probably be better off with named scopes. With that said, you can use with_exclusive_scope to override the default scope if you need to.

Have a look at this question for more details.

Solution 3 - Ruby on-Rails

If all you need is to change the order defined in default_scope, you can use the reorder method.

class Foo < ActiveRecord::Base
  default_scope order('created_at desc')
end

Foo.reorder('created_at asc')

runs the following SQL:

SELECT * FROM "foos" ORDER BY created_at asc

Solution 4 - Ruby on-Rails

Since 4.1 you can use ActiveRecord::QueryMethods#unscope to fight default scope:

class User < ActiveRecord::Base
  default_scope { where tester: false }
  scope :testers, -> { unscope(:where).where tester: true }
  scope :with_testers, -> { unscope(:where).where tester: [true, false] }
  # ...
end

It is currently possible to unscope stuff like: :where, :select, :group, :order, :lock, :limit, :offset, :joins, :includes, :from, :readonly, :having.

But still please avoid using of default_scope if you can. It's for your own good.

Solution 5 - Ruby on-Rails

You can override a default scope using the with_exclusive_scope method. So:

foos = Foo.with_exclusive_scope { :conditions => ["baz = ?", baz] }

Solution 6 - Ruby on-Rails

On Rails 5.1+ (and maybe earlier, but I've tested it works on 5.1) it is possible to unscope a specific column, which imho is the ideal solution for removing a default_scope in a fashion that can be used inside a named scope. In the case of the OPs default_scope,

Foo.unscope(where: :bar)

Or

scope :not_default, -> { unscope(where: :bar) }
Foo.not_default

Will both result in a sql query that doesn't apply the original scope, but does apply whatever other conditions get merged into the arel.

Solution 7 - Ruby on-Rails

Rails 3 default_scope does not appear to get overridden like it did in Rails 2.

e.g.

class Foo < ActiveRecord::Base
  belongs_to :bar
  default_scope :order=>"created_at desc"
end

class Bar < ActiveRecord::Base
  has_many :foos
end

> Bar.foos
  SELECT * from Foo where bar_id = 2 order by "created_at desc";
> Bar.unscoped.foos
  SELECT * from Foo;  (WRONG!  removes the "has" relationship)
> Bar.foos( :order=>"created_at asc" )  # trying to override ordering
  SELECT * from Foo where bar_id = 2 order by "created_at desc, created_at asc"

In my app, using PostgreSQL, the ordering in the default scope WINS. I'm removing all of my default_scopes and coding it in explicitly everywhere.

Pitfall Rails3!

Solution 8 - Ruby on-Rails

With Rails 3+ you can use a combination of unscoped and merge:

# model User has a default scope
query = User.where(email: "[email protected]")

# get rid of default scope and then merge the conditions
query = query.unscoped.merge(query)

Solution 9 - Ruby on-Rails

Well, you can always use the old time favorite find_by_sql with the complete query. For example: Model.find_by_sql("SELECT * FROM models WHERE id=123")

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionGarethView Question on Stackoverflow
Solution 1 - Ruby on-RailsVincentView Answer on Stackoverflow
Solution 2 - Ruby on-RailsPär WieslanderView Answer on Stackoverflow
Solution 3 - Ruby on-RailsGuiGSView Answer on Stackoverflow
Solution 4 - Ruby on-RailsjibielView Answer on Stackoverflow
Solution 5 - Ruby on-RailsJohn TopleyView Answer on Stackoverflow
Solution 6 - Ruby on-RailswbhardingView Answer on Stackoverflow
Solution 7 - Ruby on-RailsvanboomView Answer on Stackoverflow
Solution 8 - Ruby on-RailssantervoView Answer on Stackoverflow
Solution 9 - Ruby on-RailsAdy RosenView Answer on Stackoverflow