Overriding default_scope in Rails
Asked Answered
S

4

19

In my Post.rb model, I have default_scope :conditions => {:deleted => 'false'}

But if I try to run Post.find(:all, :conditions => "deleted='false'"), it won't return anything. It's as if the default_scope takes precedence over everything.

I want it so that when I do Post.find() it doesn't return deleted posts, but I'd also like to be able to access them if I need to. What needs to be changed in either my query or my Rails model?

Thanks.

Sabu answered 15/1, 2010 at 17:10 Comment(1)
default_scope does take precedence over everything. I wrote an answer using named_scope to your previous question that I think would be applicable here as well: #2073697Chretien
D
17

with_exclusive_scope is protected, so you have to create a class method:

def self.include_deleted_in
  Event.with_exclusive_scope { yield }
end

then in your controller call

Post.include_deleted_in { Post.find(:all) }
Defant answered 15/1, 2010 at 18:15 Comment(1)
Event.with_exclusive_scope { yield } doesn't worked for me, i had to put Post.with_exclusive_scope { yield }. Anyway great answer. Save my life today.Podgorica
B
60

This one was somehow left hidden :)

Just use Post.unscoped.where(:deleted => true), if you're using Rails 3

Credit goes to José Valim for this.

Boart answered 17/10, 2010 at 19:0 Comment(4)
Doesn't seem to work when the default_scope has an :order clause and you want to override that.Patiencepatient
Zabba, that was exactly my case and this worked flawlessly for me. thanks edgerunner.Tasteful
@Zabba, use reorder for thatBoart
Be careful with this one. If you're working with an association unscoped will blow that away too.Apis
D
17

with_exclusive_scope is protected, so you have to create a class method:

def self.include_deleted_in
  Event.with_exclusive_scope { yield }
end

then in your controller call

Post.include_deleted_in { Post.find(:all) }
Defant answered 15/1, 2010 at 18:15 Comment(1)
Event.with_exclusive_scope { yield } doesn't worked for me, i had to put Post.with_exclusive_scope { yield }. Anyway great answer. Save my life today.Podgorica
G
1

use with_exclusive_scope

 Post.with_exclusive_scope { Post.find(:all) }
Gaulin answered 15/1, 2010 at 17:52 Comment(2)
Using this (outside Post model) results in: protected method `with_exclusive_scope' called for #<Class:0x10faf5c70>Mcintosh
You can use Post.send(:with_exclusive_scope) { ... }Sousa
V
1

Scopes are meant to be composable, meaning you can combine a bunch of them and it effectively applies all the conditions. In this case ActiveRecord is just too naive to determine that the explicit condition should negate the first one. It just builds the query joining all the clauses with ANDs. For this reason default_scope has the most utility with the :order clauses which is not composable (in ActiveRecord 2.3's implementation anyway). There is more discussion here.

Also note that in Rails 3 ActiveRecord is using Arel for a lot of query construction which will greatly increase the power of ActiveRecord query generation while simplifying a lot of the internals. It's likely that with Arel will improve your situation. In the meantime I recommend not putting conditions in a default_scope unless there are rows that you really want to be invisible to your Rails app.

Victorinavictorine answered 15/1, 2010 at 18:13 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.