Consider these scopes on an ActiveRecord model:
scope :onsale, where(:sales_state => "onsale")
scope :outdated, where(:sales_state => "outdated")
scope :onsale_or_outdated, where(" sales_state = 'onsale' OR sales_state = 'outdated' ")
Why is it that Rails knows to override :onsale with :outdated, but not :onsale with :onsale_or_outdated?
My use case:
I have a relation object with many scopes (let’s say it’s a saved search), and one of those is :onsale. I want to make another relation starting from that, but this time I want the sales_state to be either onsale or outdated.
If I use relation.onsale_or_outdated, the sales_state is not overridden, it just adds a new condition.
[...] WHERE "cars"."sales_state" = 'onsale' [...] AND (("cars"."sales_state" = 'onsale' OR "cars"."sales_state" = 'outdated'))
How can I use my ‘or’-ed condition in this context?
That’s how scopes work. They append, not replace. If you have two mutually exclusive scopes, you need to use one or the other, not both. The special case is when you have a scope involves a single field in
:symbol = <value>syntax. Rails is smart enough to allow one scope to cancel the other out. In your case, theonsale_or_updatedscope is simply a string, Rails has no means to tell which fields are involved and so the scopes are chained.You should rewrite your scope to use fields/values instead of a blob of SQL, so Rails knows which fields are involved.
Alternatively, if you want to use only your
onsale_or_outdatedscope, you canunscopethe relationship and reapply a scope:Note that this will remove any previously applied scopes.