Проверка уникальности, если только она не является частью отношений родитель-потомок

Я работаю над проектом, в котором у меня есть модель под названием transaction. У transaction может быть много дочерних транзакций, использующих ключ parent_transaction_id. Отношения родитель-потомок могут быть только на один слой в глубину, поэтому у ребенка не может быть собственного потомка.

transaction также имеет атрибут с именем reference_number. Я бы хотел, чтобы этот атрибут был уникальным, за исключением отношений родитель-потомок. Таким образом, родительская и дочерняя транзакции могут иметь одинаковые reference_number, а две несвязанные транзакции — нет. В настоящее время у меня есть:

validate :reference_number, uniqueness: true, allow_blank: true

Первоначально я думал, что при проверке будет условие unless: -> { is_parent_child }, но, похоже, невозможно сделать то, что я хочу, с помощью этого метода.

Любая помощь в поиске способа сделать это будет принята с благодарностью.


person user2320239    schedule 07.02.2018    source источник
comment
Разрешаете ли вы, чтобы ссылочный номер ребенка отличался от ссылочного номера родителя?   -  person SteveTurczyn    schedule 07.02.2018
comment
Нет, если у транзакции есть родитель, они должны иметь один и тот же ссылочный номер.   -  person user2320239    schedule 07.02.2018
comment
Тогда вам действительно не нужно хранить ссылочный номер в дочерней модели. Вы можете создать свой собственный метод доступа def reference; return parent_transaction&.reference if parent_transaction&.reference; self[:reference];end. Он вернет ссылку на родителя, а если родителя нет, он вернет ссылку на текущую транзакцию.   -  person SteveTurczyn    schedule 07.02.2018
comment
Это отличная идея, спасибо!   -  person user2320239    schedule 07.02.2018
comment
Извините, я столкнулся с проблемой, кажется, что теперь дети не проходят проверку уникальности, потому что возвращают ссылку на своих родителей? Как предотвратить это?   -  person user2320239    schedule 07.02.2018
comment
Вы можете сделать validates :reference_number, uniqueness: true, if: 'parent_transaction_id.blank?' и получить before_validation :reset_reference_number и def reset_reference_number; self.reference_number = nil if parent_transaction_id.present?; end   -  person SteveTurczyn    schedule 07.02.2018


Ответы (1)


Существует решение, которое заключается в написании пользовательской проверки, как показано ниже:

validate :reference_number_uniq

def reference_number_uniq
  if self.reference_number && self.exists?('id != ? AND reference_number = ?', 
    self.child_transaction_id, 
    self.reference_number)
    errors.add(:reference_number, "is not valid")
  end
end

Использование unless может работать, но может потребоваться выполнить еще один запрос перед проверкой уникальности reference_number.

person Tai    schedule 07.02.2018
comment
Да, я надеялся избежать написания своей собственной проверки уникальности, я думал, что может быть что-то вроде обратной области, где это позволяет дублирование, если идентификатор тот же, но похоже, что это не так. - person user2320239; 07.02.2018
comment
Ага. Встроенная проверка предназначена для общего случая, в вашем случае, я думаю, вам следует написать собственную. - person Tai; 07.02.2018
comment
Вы имели в виду self.class.exists?, и произойдет сбой, когда вы сохраните существующую запись, и произойдет сбой, когда вы сохраните дочерний элемент, а не родительский - person SteveTurczyn; 07.02.2018
comment
Да, вы правы. Запрос неверный, как вы указали, но я не думаю, что он больше нужен автору. Так что не буду обновлять, подумаю об этом позже. - person Tai; 07.02.2018