Reputation: 19398
I met interesting behavior of activerecord relations.
class A < ActiveRecord::Base
def self.one
where("1=1")
end
def self.two
puts A.where("2=2").to_sql
end
def self.test
one.two
end
end
A.test # prints ... WHERE 1=1 AND 2=2
I expected that Ad.where("2=2") doesn't include "1=1" in self.two, but it is. Is it feature?
Upvotes: 0
Views: 79
Reputation: 12564
Yes, it is a feature.
All values passed to where
are internally stored by the relation (@values[:where]
) and joined with AND to build the WHERE statement.
When calling two
in the context of the relation returned by one
, the "where values" stored by one are used as a basis to build the new scope.
You can obtain desired behavior using unscoped
:
one.unscoped.two
EDIT: yes, it is clearly weird and counter-intuitive.
I just got bit by the same problem as you.
After a lot of digging, it appears that since rails 4, all models keep a thread-local registry that stores the current scope used on that class / relation. I don't know exactly why they did it, my guess is it has to do with performance.
The point is, when you already have chained a bunch of scopes and try to call another one that references the class (like two
in your example), ActiveRecord just fetches the current scope for the class - that is, the relation on which you called the scope in the first place ! Pretty silly. In fact, your two
method could be rewritten without the A
class reference, it wouldn't change anything.
Weirder and weirder, another problem appeared to me when using STI : in my scope, I made a totally unrelated call to the parent model using pluck
. Not only this "feature" affected the query in unexpected ways, but it seems it also has "reset" the default scope, so that the next query (which was the actual return of the scope) "forgot" about all conditions passed by previous scopes... WTF ?
Conclusion : I think we should open a ticket on rails github and at least ask the team to document this weird behaviour. (using MyClass.unscoped
on my first query solved my problem, but is not intuitive)
Upvotes: 2