ActiveRecord объединяет текущие где условия при применении области?
Я столкнулся с неожиданным поведением в Active Record (3.2.13):
На моей модели есть простая область применения:
class User < ActiveRecord::Base
scope :verified, lambda { where('verified = 1') }
end
Это может быть прекрасно использовано самостоятельно:
User.verified.to_sql
#=> "SELECT \"users\".* FROM \"users\" WHERE (verified = 1)"
Когда я соединяю where
-классы, они and
Ред, как и ожидалось:
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"
Проблема:
Однако, когда я соединяю область видимости, мое первое предложение where обнуляется, последнее объединяется в слиянии:
User.where(company_id: 1).where(company_id: 2).verified.to_sql
"SELECT \"users\".* FROM \"users\" WHERE \"users\".\"company_id\" = 2 AND (verified = 1)"
Как применить область действия к существующим условиям?
(Эти существующие условия были созданы с помощью канкан load_and_authorize_resource
поэтому я не могу просто применить эти where
пункты после применения моей сферы.)
2 ответа
Эта суть подводит итог наших выводов по этому вопросу. https://gist.github.com/kirel/5678865
Сводится к ActiveRecord::Scoping::Named::ClassMethods#scope
с помощью ActiveRecord::SpawnMethods#merge
который реализует неожиданное, но предполагаемое поведение.
Rails 4 не будет использовать слияние и, следовательно, вести себя как положено (см. https://github.com/rails/rails/commit/cd26b6ae7c1546ef8f38302661bbedf8cb487311). Между тем, обходной путь - просто избегать области видимости и использовать вместо этого методы класса.
Измените это на
User.verified.where(company_id: 1).where(company_id: 2).to_sql
Кажется, что когда вы использовали scope
после where
предложение просто создайте новый хеш из предложения цепочки where и затем AND в конце.
следовательно
User.where(company_id: 1).where(company_id: 2).verified.to_sql
Дает тебе
"SELECT \"users\".* FROM \"users\" WHERE \"users\".\"company_id\" = 2 AND
(verified = 1)"
НО
User.where(company_id: 1).where(contact_id: 2).verified.to_sql
Дает тебе
"SELECT \"users\".* FROM \"users\" WHERE \"users\".\"company_id\" = 2 AND
\"users\".\"contact_id\" = 2 AND (verified = 1)"