Skip to main content

Switch to UUIDs

Published: November 10, 2020
Updated: November 10, 2020

This is part of The Annotated Guide to a New Rails App, a list of recommendations to make developing your Rails app more productive and joyful.

In this article, we are talking about switching the database primary keys to UUIDs, universally unique identifiers.

When

On one hand, it is not trivial to change a table’s primary key from the default integer to UUIDs. For that reason, it is helpful to switch to UUIDs as early as possible.

On the other hand, the benefits of using UUIDs are generally not an important concern for new applications, so there is little reason to do it right away.

Why

By default, Rails uses integers as primary keys. Using UUIDs instead prevents ids or the number of entries from being guessed. Using UUIDs also avoids an integer overflow problem if many objects are created.

How

Enable UUIDs in PostgreSQL:

We assume you have already made the switch to PostgreSQL.

  1. Generate a migration: rails generate migration EnableUuids.
  2. Put this in the change method of the migration: enable_extension 'pgcrypto'
  3. Run the migration: rake db:migrate

Configure the generators to use UUIDs as primary keys:

In config/application.rb add config.generators.orm :active_record, primary_key_type: :uuid.

Test the change

After making a commit, test that this works by running rails generate model foo and rake db:migrate.

The migration and schema should both indicate that the id is a UUID.

Run rake db:rollback and remove the generated files before continuing.

Gotchas

When creating a foreign key column (using references or belongs_to) you must indicate the type if the id is a UUID.

For example:

create_table :post, id: :uuid do |t|
end

create_table :comment, id: :uuid do |t|
  t.belongs_to :post, type: :uuid
end

If you do not do this, there is a risk of silent errors when the UUIDs are coerced into an integer to fit into a column that expects an integer.