Reputation: 5877
I have encountered some unexpected behavior in Active Record (3.2.13):
There is a simple scope on my model:
class User < ActiveRecord::Base
scope :verified, lambda { where('verified = 1') }
end
This can be used fine on its own:
User.verified.to_sql
#=> "SELECT \"users\".* FROM \"users\" WHERE (verified = 1)"
When I concatenate where
-clauses, they are and
ed as expected:
User.where(company_id: 1).where(company_id: 2).to_sql
"SELECT \"users\".* FROM \"users\" WHERE \"users\".\"company_id\" = 1 AND \"users\".\"company_id\" = 2"
Problem:
However, when I chain a scope, my first where-clause is nuked, the last one wins in a merge:
User.where(company_id: 1).where(company_id: 2).verified.to_sql
"SELECT \"users\".* FROM \"users\" WHERE \"users\".\"company_id\" = 2 AND (verified = 1)"
How to apply a scope on a relation with existing conditions?
(Those existing conditions have been established through cancan's load_and_authorize_resource
so I cannot just apply those where
clauses after applying my scope.)
Upvotes: 2
Views: 785
Reputation: 36
This gist sums up our findings on the issue. https://gist.github.com/kirel/5678865
It boils down to ActiveRecord::Scoping::Named::ClassMethods#scope
using ActiveRecord::SpawnMethods#merge
which implements the unexpected but intended behavior.
Rails 4 will not use merge und thus behave as expected (see https://github.com/rails/rails/commit/cd26b6ae7c1546ef8f38302661bbedf8cb487311). Meanwhile the workaround is to just avoid scope and use class methods instead.
Upvotes: 2
Reputation: 47482
Change it to
User.verified.where(company_id: 1).where(company_id: 2).to_sql
It seems that when you used scope
after the where
clause it simply create a new hash of the chained where clause and then AND it at the end.
hence
User.where(company_id: 1).where(company_id: 2).verified.to_sql
Gives you
"SELECT \"users\".* FROM \"users\" WHERE \"users\".\"company_id\" = 2 AND
(verified = 1)"
BUT
User.where(company_id: 1).where(contact_id: 2).verified.to_sql
Gives you
"SELECT \"users\".* FROM \"users\" WHERE \"users\".\"company_id\" = 2 AND
\"users\".\"contact_id\" = 2 AND (verified = 1)"
Upvotes: 1