Using UUIDs in Rails

Why use UUIDs?

It may seem like a trivial decision at first glance, but using UUIDs can have an intricate effect on your applications design structure. If you are building an application and have an id:integer column that auto increments with the creation of every item you add to that table you could end up with some sever issues. As applications grow in size we end up having to seperate parts of the application into different servers: a cluster of database servers, background, jobs, cache server, an httpd server, and throw in a few servers for actual application and you’ve got a whole cluster of services to deal with.

Lets say you’ve got 3 servers running the actual application, each one chugging along running serveral instances of your web application. Now say it’s a basic CRUD application if you’ve got several instances writing to the database at once you will have a conflict. If you’ve got a table named books and a few rows are being added at once by seperate visitors, you’re auto incrimenting the rows and lets say on each one it creates row id: 72. Now when they combine their information together you’re going to have an issue with inconsistent data trying to overlap.

UUIDs are simple 128-bit generated values and only consisting of formated using hexadecimal text. Depending on how they’re being generated their values are generally a random value that will rarely have a collision value. It’s generally safe to say that you can use a distributed application and have several servers generating rows of data and almost never have the same UUID generated (I’m not saying it can’t happen, it’s just a lot less likely to happen).

How can I do this is Rails?

When you are generating models and scaffolds the id column is usually automatically generated with every table (unless specified), this is a feature build into Rails to make it easier and faster to develop.

Now depending on what database you are using to test, develop, and deploy you application there are different steps that are required in order to get your application to properly recognize and use the UUID datatype. I have seperated into different sections how I got UUIDs to work in both Postgresql and the SQLite databases.

Postgresql

The method in order to get uuids to work with Postgres tends to be quite a bit easier (in my opinion), because Postgres has a built in method for generating unique uuids for row ids.

rails g migration enable_uuid_extension

In the migration we tell the Postgres database to use the uuid extension, we do this in order to have the database automatically generate UUIDs on the objects creation rather than having the Rails Application generate the UUIDs and adding additional process time to the server.

Now access the rails console rails c in order to verifiy that UUIDs are being generated upon the models object creation. At this point in time the default version of UUID generation used by Rails is uuid_generate_v4() which seems to be quite sufficient to avoiding collisions.

If you look closely you will notice that the Book.id is no longer being generated a basic integer, it is not being generating a Hex based text string. As show above: Book[id]: f55ea573-1eec-4053-b7f5-7b693b344da9

SQLite

To begin using UUIDs with sqlite you will need to install the activeuuid gem, when using this gem it will save the uuid: as a binary(16) datatype. I haven’t dug around to much into the gem, but it does seem to work quite effectively for it’s purpose.

# Gemfilegem'activeuuid'# https://github.com/jashmenn/activeuuid

We will now need to adjust the migration to explicity use the uuid: datatype for :id and completely disregard using the default :id dataset and configuration.

You will also need to include ActiveUUID::UUID in your model to enable UUID generation, you will need to specify a natural_key to supply a dataset in order to generate a UUID. If this step is not included the application will throw a heap of errors about the books.id using an invalid uuid datatype.

Updated: 08/27/2019

The previous method used the uuid-ossp extension which relies on uuid_generate_v4 to generate UUIDs. The recommended method pgcrypto uses the Postgres function gen_random_uuid to generate UUIDs, this method generates UUIDs faster and with better collision prevention.