Модель не проходит проверку, но создается
Я давно сталкиваюсь с проблемой. У меня есть следующий код:
class BrokenModel < ActiveRecord::Base
validates_with BrokenValidator
has_many :association_name
end
class BrokenValidator < ActiveModel::Validator
def validate record
@record = record
check_alerted
end
private
def check_alerted
return if @record.association_name.to_a.empty?
alerted = <test for alerted>
if alerted
@record.errors[:base] << "It was alerted recently"
end
p "check_alerted: #{@record.errors[:base]}"
end
end
worker.rb
[...]
BrokenModel.create(association_name: [model1, model2])
[...]
В моих журналах для последней распечатки показано, что проверка прошла только один раз, но у меня есть несколько записей, созданных для этой модели с association_name
подарок.
В моей среде это выполняется в нескольких потоках и нескольких ядрах, но поскольку записи создаются за несколько минут друг от друга, это не проблема параллелизма, если исключение в отдельном потоке не влияет на создание модели.
Просто ради любопытства, это работает в Sidekiq.
редактировать
Поэтому я заметил в своих журналах, что это может быть проблемой параллелизма. Итак, вот что происходит:
- проверка экземпляра 1: последнее предупреждение: сбой (последнее предупреждение)
- проверка экземпляра 2: недавно получено предупреждение: пройдено
- проверка экземпляра 2: другая проверка: не удалось (другая проверка)
- ошибки создания экземпляра 2: недавно было получено предупреждение + другая проверка
- ошибки создания экземпляра 1: Нет
Любая подсказка, если в ActiveModel::Validator есть какой-либо вид небезопасности потока или @record может быть перезаписан / разделен другими потоками?
1 ответ
Добавление ошибок в запись НЕ делает ее недействительной. Фактически, когда модель проверяется перед сохранением, все предыдущие ошибки, включая ту, которую вы добавляете в свой код, стираются.
Сделайте эту проверку в модели... Не в рабочей.
validate :check_alerted
def check_alerted
return if association_name.to_a.empty?
alerted = test
if <test for alerted>
errors.add(:base, "It was alerted recently")
end
end