У меня есть следующий блок кода:
unless User.exist?(...)
begin
user = User.new(...)
# Set more attributes of user
user.save!
rescue ActiveRecord::RecordInvalid, ActiveRecord::RecordNotUnique => e
# Check if that user was created in the meantime
user = User.exists?(...)
raise e if user.nil?
end
end
Причина, как вы, вероятно, можете догадаться, заключается в том, что несколько процессов могут вызывать этот метод одновременно, чтобы создать пользователя (если он этого не делаетуже существует), поэтому, пока первый входит в блок и начинает инициализацию нового пользователя, устанавливает атрибуты и, наконец, вызывает save !, пользователь может уже быть создан.В этом случае я хочу еще раз проверить, существует ли пользователь, и вызвать исключение, только если оно все еще не существует (= если другой процесс не создал его за это время).
Проблема в том, что регулярно ActiveRecord:: RecordInvalid исключения возникают из сохранения!и не спасен от спасательного блока.Есть идеи?
РЕДАКТИРОВАТЬ:
Хорошо, это странно.Я должен что-то упустить.Я реорганизовал код в соответствии с советами Симоны, чтобы он выглядел следующим образом:
unless User.find_by_email(...).present?
# Here we know the user does not exist yet
user = User.new(...)
# Set more attributes of user
unless user.save
# User could not be saved for some reason, maybe created by another request?
raise StandardError, "Could not create user for order #{self.id}." unless User.exists?(:email => ...)
end
end
Теперь я получил следующее исключение:
ActiveRecord::RecordNotUnique: Mysql::DupEntry: Duplicate entry 'foo@bar.com' for key 'index_users_on_email': INSERT INTO `users` ...
в строке, где написано «разве что user.save».Как это может быть?Rails думает, что пользователь может быть создан, потому что электронная почта уникальна, но тогда уникальный индекс Mysql предотвращает вставку?Насколько вероятно это?И как этого избежать?