How to use UUIDs as Primary keys in Rails 4 with PostgreSQL
What are UUIDs anyway and why should you use them?
UUID stands for Universally Unique Identifier and the original purpose of UUIDs was to enable distributed systems to uniquely identify objects without significant central coordination. Anyone can create UUIDs and use them to identify something with reasonable confidence that the same identifier will never be unintentionally created by anyone to identify some other kind of object.
Objects created with UUIDs can therefore later be merged into a single database without needing to resolve conflicts.
Another advantage has to do with the randomness of UUIDs. UUIDs will not follow any kind of pattern so it’s impossible for potential attackers to be able to go through your database records without you exposing a list of UUIDs. Of course, this doesn’t automatically make your application secure, but it can reduce the damage that is likely to be done if a security bug is exploited.
Make sure you have the Rails 4 gem activated and PostgreSQL installed then run:
Then open the generated migration file named enable_uuid_ossp_extension and edit it so it looks like this:
This will enable the uuid-ossp module in PostgreSQL which provides functions to generate UUIDs.
Next we need to update the migration file named create_documents:
Note that we have explicitly changed the id to be of type uuid.
Now you’re ready to create the database and run the migrations:
You can now open the Rails console and start playing with your document model:
As you can see, your model now uses a UUID as a primary key instead of a simple integer.
One thing that’s not going to work anymore when you switch to UUIDs is the
Document.last class methods. To make them work again you can use the
created_at attribute and define your own scopes in your model:
Another thing that’s not going to work anymore is the
t.references method in migrations. If you write
t.references :document for another table you create, it will create a
document_id column with an
integer as the type. This is not going to work because of obvious reasons. Instead you should define your relations using
Using UUIDs as primary keys has some drawbacks. They can be a little bit slower to generate and they requires bigger indexes compared to normal auto increment primary keys so you should consider that before using them.