I have the following code block:
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
The reason is, as you can probably guess, that multiple processes might call this method at the same time to create the user (if it doesn't already exist), so while the first one enters the block and starts initializing a new user, setting the attributes and finally calling save!, the user might already be created.
In that case I want to check again if the user exists and only raise the
exception if it still doesn't (= if no other process has created it in the meantime).
The problem is, that regularly ActiveRecord::RecordInvalid exceptions are raised from the save! and not rescued from the rescue block.
Any ideas?
EDIT:
Alright, this is weird. I must be missing something. I refactored the code according to Simone's tip to look like this:
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
Now I got the following exception:
ActiveRecord::RecordNotUnique: Mysql::DupEntry: Duplicate entry '
[email protected]' for key 'index_users_on_email': INSERT INTO `users` ...
thrown in the line where it says 'unless user.save'.
How can that be? Rails thinks the user can be created because the email is unique but then the Mysql unique index prevents the insert? How likely is that? And how can it be avoided?