Rails + Postgres + UUID

Overview

1. What the heck is UUID?

A universally unique identifier (UUID) is a 128-bit number used to identify information in computer systems…While the probability that a UUID will be duplicated is not zero, it is close enough to zero to be negligible. — Wikipedia

Here’s an example:

2. Why would I want to use a UUID?

Bad actors: and no, I don’t mean Steven Seagal and his perma-sunglasses face.

Steven Seagal gif where someone replaced a gun he was holding with an electric toothbrush
Steven Seagal gif where someone replaced a gun he was holding with an electric toothbrush
Mr. Seagal prepares to brush his teeth in public.

When you’re just using the straight-outta-the-box incremental integer IDs, a bad actor may be able to intuit quite a bit about your resources. It makes URL-hacking that much easier. If Mr. Seagal visits his user account page and peeps the URL that reads:

cooldudes.com/users/13

He might see that he’s user #13 and find that to be an unlucky number and leave the site. Seagal might think a site with only 13 users is embarrassing then tweet about it. He also might also see his messages page URL:

cooldudes.com/users/13/private-messages/7

…and think to himself “Hmmm. I wonder if I can peep other people’s private messages by substituting those integer ids for other numbers that I think of while brushing my teeth.”

So yeah, we want to avoid people making too many inferences on our backend for some decent OpSec!

2016 image of person on plane typing into laptop wearing a knitted garment that obscures the screen and their hands
2016 image of person on plane typing into laptop wearing a knitted garment that obscures the screen and their hands
Mega secure with Becky Stern’s “Compubody Sock”

3. Rails Setup

Go ahead and spin up a new Rails API with a Postgres database. PG is great for Heroku deployment especially since they don’t support Rails’ default database: SQLite

rails new app-with-uuid-keys --api --database=postgresql

Before we generate migrations for any of your models you’ll want to tell Rails that when generating migrations it should use uuid instead of plain old integers by creating this file:

Next you’ll want to generate your models/migrations for your Postgres database. But first we must enable the pgcrypto extension in our Postgres database:

rails generate migration enable_uuid --no-test-framework

This migration file should end up looking like this:

When generating your models if you specifically rails generate a model and not a migration then the Rails generator config that we set up moments ago will handle the uuid-ing of the user’s primary key.

Running rails g model user name:string email:string --no-test-framework generates a blank User model class annnnnd this beautiful migration:

database migration code showing the id as a uuid
database migration code showing the id as a uuid
Users migration table

4. Database Setup

Go ahead and run rails db:create && rails db:migrate

console printed text showing successful migrations of pgcrypto extension, users
console printed text showing successful migrations of pgcrypto extension, users
This is what you should see!

5. The Big Reveal

GIF: Drag queen Violet Chachki on RuPaul’s Drag Race walking a runway and revealing a red garment from under a black one
GIF: Drag queen Violet Chachki on RuPaul’s Drag Race walking a runway and revealing a red garment from under a black one

If you call on your rails console in your terminal and create a User you’ll see that they’re being keyed with uuids instead of integers! Time to PARTY!! 🥳🥳🥳

Rails console readout that confirms id is uuid and not an integer
Rails console readout that confirms id is uuid and not an integer

6. Epilogue

I will say that I did have some considerable frustration at one point in getting the hang of activating the pgcrypto extension. I was being foolish and manually creating the database from the Postgres macOS app without properly activating the extension. Which gave me fun errors like this:

a database error stating that function gen_random_uuid() does not exist

I eventually learned how to manually enable it in the terminal during my database doom spiral. You can paste this into your terminal while making sure to properly name your existing database: psql -d <database-name-here-no-carrots> -c ‘CREATE EXTENSION pgcrypto’

Again, not necessary if you let Rails do the heavy lifting with creation and migration of the database, but I’m glad I know this option exists!

Thanks for reading ❤

Full Stack Software Engineer. Multimedia performance engineer and performer. Through technology, I ❤ to bring ideas to reality–on the stage or in a browser.