This is a series of posts where I will be talking about some database tips for long time railers.
In the past, I’ve been working on many rails projects, including big ones, that relies only on Rails validations for checking all the Data Integrety before the model is saved in the Database.
For most of validations, this makes sense. but validate_uniqueness_of is terrible broken, and could lead you to a number of problems.
Imagine the following scenario:
You have your model user, which have a unique e-mail, like this:
1 2 3 4 | |
So, in your production environment, you have configured to use unicorn + ngnix, with 4 workers.
In your production environment, the user creating is wrapped into a transaction with more business logic. So, here is the problem:
- Worker 1 starts a user creation trasaction
- Worker 2 starts a user creation trasaction
- Worker 1 makes the query to see if this e-mail is already taken, which return false, because the user wasn’t persisted in the database yet.
- Worker 2 makes the query to see if this e-mail is already taken, which return false, because the user wasn’t persisted in the database yet.
- Worker 1 finish the transaction, inserting the user.
- Worker 2 finishes the trasaction, inserting a user with duplicated e-mail.
This could be easily solved using a unique index in the database, which raises a exception if a duplicated data is entered. The index could be created in a migration, using the following code:
1
| |
For more about unique indexes, check this article: Mysql Unique Indexes and this PostgreSQL Unique indexes
Protip: be nice to your users, and rescue from the exception when this occurs, putting a nice message, like the following code:
1 2 3 4 5 6 7 8 9 10 11 12 | |