ActiveRecord exceptions not saved

I have the following code:

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 that, as you probably can guess, several processes can simultaneously call this method to create a user (if he does not already exist), therefore, when the first one enters the block and starts the initialization of the new user, setting the attributes and, finally, by calling save !, the user can already be created. In this case, I want to check again whether the user exists and only throw an exception if it still does not work (= if no other process created it at the same time).

The problem is that regular ActiveRecord :: RecordInvalid exceptions are raised from saving! and not saved from the rescue unit. Any ideas?

EDIT:

OK, this is weird. I have to miss something. I reorganized the code according to the Simone prompt 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 ' foo@bar.com ' for key 'index_users_on_email': INSERT INTO `users` ... 

thrown into a string where it says "if the user does not have". How can it be? Rails believes that a user can be created because email is unique, but then does the unique Mysql index prevent insertion? As much as possible? And how can it be avoided?

+4
source share
2 answers

In this case, you can use the transition to create a unique index in the user table key so that the database causes an error.

Also, be sure to add validates_uniqueness_of validation to the user model.

Validation does not always prevent duplication of data (there is really a minimal chance that two parallel requests are written in the same millisecond). If you use validates_uniqueness_of in combination with an index, you do not need all this code.

 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 

becomes

 user = User.new(...) # Set more attributes of user if user.save # saved else # user.errors will return # the list of errors end 
+3
source

Rail inspections cannot determine race conditions in the database; the solution we use is also to add database restrictions.

Here is our short page of links about it: Rails ActiveRecord Validations: validates_uniqueness_of races

+3
source

Source: https://habr.com/ru/post/1334533/


All Articles