validates_uniqueness_of
is not sufficient to ensure the uniqueness of a value. The reason for this is that in production, multiple worker processes can cause race conditions:
users
table and see that the name is availableThe first thing to do here is to ensure the integrity of your data. When using validates_uniqueness_of
you should always have a unique key constraint on the column in your database. E.g. when you are validating the uniqueness of usernames, the users#screen_name
column should have a unique database index.
Using unique key constraints give you a hard guarantee for the uniqueness of your values. The race condition as detailed above can no longer occur. The following will happen instead:
users
table and see that the name is availableActiveRecord::RecordNotUnique
. ActiveRecord rolls back the transaction, nothing will be saved. The user will probably see a Rails error box.In 99% of all cases adding a uniqueness key is an adequate solution, and in any case the integrity of your data is guaranteed. There are however cases where you want to improve the user behavior (Rails error box) or reduce the number of exceptions e-mailed to your / collected by AirBrake:
Wrap your entire save
call in a Mutex, so the second form submission will report a violated uniqueness validations instead of a Rails error box.
Use a Mutex as detailed above. Also embed a hidden token into your forms so you can detect a double form submission and redirect to the previously created record.