Rails 3 проверяет уникальность одного значения для столбца?
У меня есть модель с столбцом active
, которая является логической. Я хочу проверить уникальность всех вновь добавленных записей в отношении company_id
, чтобы я мог добавить столько записей, сколько хочу, с тем же company_id
в таблицу, если active
установлен на false
. Для каждого company_id
должна быть только одна запись active
.
Как бы я это написал? Я уже пробовал:
validates :company_id, :uniqueness => { :scope => :active }
Но это также подтверждает, что уникальные комбинации active
являются false
(такие, что я никогда не могу иметь больше двух company_id
в таблице с тем же статусом active
, вне зависимости от того, что active
is) - приведенная выше проверка позволяет использовать две записи для company_id
, одну с active = false
, а другую - с помощью active = true
. После того, как эти две записи включены, валидация блокирует все остальное.
Затем я попытался добавить это:
scope :active, where(:active => true)
Но это, похоже, не изменило валидацию вообще (та же проблема, что и выше).
Как я могу написать эту проверку, чтобы я мог добавить столько записей с тем же company_id
, пока active
является ложным, и только один active = true
за company_id
?
Ответы
Ответ 1
Не нужно использовать validates_each
- это только если вы хотите передать несколько атрибутов через один и тот же блок. Просто создайте пользовательскую проверку:
validate :company_id_when_active
def company_id_when_active
if active? and CompanyTerm.exists? ["company_id = ? AND active = 1 AND id != ?", company_id, id.to_i]
errors.add( :company_id, 'already has an active term')
end
end
Ответ 2
Rails 4+ предлагает гораздо лучшее решение для этого.
validates_uniqueness_of :company_id, conditions: -> { where(active: true) }
проверить документация
Ответ 3
Хорошо, я думаю, что, наконец, понял это.
Проверка на Rails Guides привела меня к validates_each, что привело меня к этому решению:
scope :active, where(:active => true)
validates_each :company do |model, attr, value|
active = CompanyTerm.active.where(:company_id => value)
model.errors.add(attr, 'already has an active term') unless active.empty?
end
Я не знаю, если это самый эффективный способ написать это, но он работает. Я открыт для любых предложений!
Ответ 4
Старая тема, но есть самое простое решение. Ответ выше почти правильный. Вы можете использовать оператор :if
как ключ, например:
validates :active, :uniqueness => { :scope => :company_id }, :if => :active
Ответ 5
validates :company_id, :uniqueness => { :scope => :active } unless Proc.new { self.active }
И, возможно, вы хотите позвонить самой компании
validates :company, :uniqueness => { :scope => :active } unless Proc.new { self.active }
ИЗМЕНИТЬ
Следующий ответ, основанный на вашем решении, немного эффективнее:
scope :active, where(:active => true)
validates_each :company do |model, attr, value|
model.errors.add(attr, 'already has an active term') if CompanyTerm.active.exists?(:company_id => value)
end