3

Is there any way to override the default scope or previous scope in a where condition? (Beside re-structuring the model not to use a default_scope or use unscoped)

Also, what is the reason why this works the way it does? It feels like it is not the most expected or intuitive approach.

Sample:

class Product < ActiveRecord::Base
  default_scope -> { visible }
  scope :visible, -> { where(visible: true) }
  scope :hidden, -> { where(visible: false) }
end

When I do this:

Product.hidden

The generated sql tries to match by two values:

WHERE "products"."visible" = 't' AND "products"."visible" = 'f'

The same goes without default_scope:

class Product < ActiveRecord::Base
  scope :visible, -> { where(visible: true) }
  scope :hidden, -> { where(visible: false) }
end

When I do this:

Product.visible.where(visible: false)

Or when I do this:

Product.visible.hidden

The generated sql tries to match by two values:

WHERE "products"."visible" = 't' AND "products"."visible" = 'f'

I made this gist with a complete test case: https://gist.github.com/mmontossi/dcf71457e98a169c28a5

This is the issue when I first asked about this thinking it was a bug: https://github.com/rails/rails/issues/20907#issuecomment-122131096

agbodike
  • 1,796
  • 18
  • 27
mmontossi
  • 41
  • 1
  • 3
  • The gist doesn't explains the desired behavior? – mmontossi Jul 17 '15 at 03:17
  • duplicate question with http://stackoverflow.com/questions/1834159/overriding-a-rails-default-scope. the answer in this question has a good explanation – rob Jul 17 '15 at 05:45
  • I just edited the question, I want to find the reason of why this is the way it's. It feels strange as it but maybe the is some good reason to keep it this way. – mmontossi Jul 17 '15 at 13:51
  • The question you linked is excellent but I didn't found info about why has been designed this way. – mmontossi Jul 17 '15 at 13:57
  • it does what you want to do. you declared a default scope. the default scope runs every time (excluding you use unscoped). thats the reason why default scopes can be really ugly. they will be execute everytime, and in this case its seems to be useless, but you have responsibility for your code. – rob Jul 17 '15 at 14:05
  • I'm pointing more to the fact that there is no way to override the previous condition besides remove them all, you have a good point about the default_scope running every time and everybody should be responsible for the code but I thing this is not the more expected or intuitive result. – mmontossi Jul 17 '15 at 14:18

2 Answers2

0

To override a default scope, use the unscoped method: Product.unscoped.hidden.

The reason why it was adding up conditions is that the code is doing exactly what you told it to do: run a default scope, then any custom conditions specified.

mrodrigues
  • 1,052
  • 10
  • 14
0

There is only one thing you need to know about default_scope and it is this: don't use it.

default_scope is like a drug. At first it feels great, and everything seems easier, but as time goes on you realize that using it was a bad idea. By then it is too late, and you must forever deal with the consequences. OK that is not entirely true: you could simply stop using default_scope and rewrite your controllers to explicitly call the actual scopes, which is what you should have done in the first place, because that way it is obvious what data is being retrieved and thus is less confusing for other developers (including the future you who will forget about using default_scope). So default_scope is not as bad as getting hooked on drugs. It only feels that way sometimes.

Just say "no" to default_scope.

zetetic
  • 47,184
  • 10
  • 111
  • 119
  • I thing would be an improvement to remove default_scope or to refactor it to just as default_order. Having it but don't use it feels strange. – mmontossi Jul 24 '15 at 17:44
  • It's hard to completely remove features. `default_scope` has been around for a while and is (I'm assuming) pretty widely used. And to be honest it's not as bad as I make it out to be -- I am being somewhat tongue-in-cheek. But it is one of those features that seems like a real time-saver, but often turns into a real time-waster, especially when new coders join the team. – zetetic Jul 24 '15 at 17:50
  • I know you were joking a little bit but I really mean it, I think would be a pretty nice convention to add to rails in future versions. By default a clean model, if you want something more specific select or combine the scopes you want and by default only decide the order, if you change your mind later you can use the reorder method. – mmontossi Jul 24 '15 at 20:52