2013-05-30 3 views
2

я столкнулся с каким-то неожиданное поведением в Active Record (3.2.13):ActiveRecord объединяется с текущими условиями при применении области?

Там есть простая сфера на моей модели:

class User < ActiveRecord::Base 
    scope :verified, lambda { where('verified = 1') } 
end 

Это может быть использовано прекрасно сами по себе:

User.verified.to_sql 
    #=> "SELECT \"users\".* FROM \"users\" WHERE (verified = 1)" 

Когда я конкатенации where -clauses, они 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" 

Проблема:

Однако, когда я приковать область видимости, мой первый, где-оговорка сбросили атомную бомбу, последний выигрывает в слиянии:

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 Морозов после применения моей сферы.)

+0

«nuking», похоже, происходит в 'merge': http://apidock.com/rails/ActiveRecord/SpawnMethods/merge ... который, кажется, применяется при использовании' scope': http: // apidock. com/rails/ActiveRecord/Scoping/Named/ClassMethods/scope – crispy

ответ

2

Эта основа подводит итог нашим выводам по этому вопросу. https://gist.github.com/kirel/5678865

Она сводится к ActiveRecord::Scoping::Named::ClassMethods#scopeActiveRecord::SpawnMethods#merge, используя который реализует неожиданный но предназначенный поведение.

Rails 4 не использует слияние и, следовательно, ведет себя как и ожидалось (см. https://github.com/rails/rails/commit/cd26b6ae7c1546ef8f38302661bbedf8cb487311). Между тем обходной путь заключается в том, чтобы просто избегать области применения и использовать методы класса.

1

Изменить его

User.verified.where(company_id: 1).where(company_id: 2).to_sql 

кажется, что, когда ты использовал scope после предложения where, он просто создает новый хэш прикованного where where, а затем AND it в конце.

следовательно

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)" 
+0

В моей ситуации это не так просто. В моем контроллере: 'load_and_authorize_resource через:: company'. cancan содержит два предложения: Первый с использованием параметров [: company], а второй - с помощью правила способности ('can: read, User, company_id: @ user.company_ids').После этого я беру загруженную и авторизированную переменную '@ users' в свой контроллер и хочу применить мою область действия. – crispy