Rails 3 проверяет уникальность одного значения по отношению к столбцу? - PullRequest
14 голосов
/ 10 августа 2011

У меня есть модель со столбцом 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?

Ответы [ 5 ]

14 голосов
/ 10 августа 2011

Не нужно использовать 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
7 голосов
/ 18 декабря 2016

Rails 4+ предлагает гораздо лучшее решение для этого.

  validates_uniqueness_of :company_id, conditions: -> { where(active: true) }

проверить документацию

4 голосов
/ 10 августа 2011

Хорошо, думаю, я наконец-то понял это.

Проверка на 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

Я не знаю, если это самый эффективный способ написать это, но это работает.Я открыт для любых предложений!

1 голос
/ 04 августа 2012

Старая тема, но есть самое простое решение.Ответ выше почти правильный.Вы можете использовать оператор :if в качестве ключа, например:

validates :active, :uniqueness => { :scope => :company_id }, :if => :active
0 голосов
/ 10 августа 2011
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
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...