Ian Bradbury

August 19, 2021

How to configure Ruby on Rails and Postgres to use UUIDs for primary keys

Scenario = you want or need to increase your application security by switching from simple integer based database primary keys to much more secure UUID's.  

Example UUID uri:
https://www.my-app.com/invoices/5e2e0f3e-71d9-4a0a-a0f1-1f67cd6a418e

How do you configure Rails to use UUIDs for your database IDs?

I will assume that you're running Rails v6+ and Postgres v9.1+

Ideally you will implement this configuration after you have run `rails new` and before you've created any tables.

Step 1:

Create a migration that will configure Postgres to include the required library that is responsible for generating UUIDs.

rails g migration postgres_uuid

And here's the migration file content:
class postgres_uuid < ActiveRecord::Migration[6.0]
  def change
    enable_extension 'pgcrypto'
  end
end

Migrate the database:  
rails db:migrate

Step 2:

We need to configure Rails to ensure that any generators used to create models and migrations, default to using UUIDs for the primary keys.

Create a new file in your project:  
config/initializers/generators.rb

Here's the file content:
Rails.application.config.generators do |gs|
  gs.orm :active_record, primary_key_type: :uuid
end

Configuration done.  👍🏻

That's great but how do we now use this new power?

Creating a new database table

Here's an example database migration file that creates a new table and shows how to specify UUIDs for the primary key:

class CreateInvoices < ActiveRecord::Migration[6.0]

  def change
  
    create_table :invoices, id: :uuid do |t|

    	t.string :type
	t.string :name
		
	t.timestamps

    end
  end
end


Default table Sort

One side efffect of using UUIDs as our primary keys is that the default sort order will be "broken" - in that .first and .last will be ordered on the random nature of UUIDs.  To resolve this situation we need to notify ActiveRecord that the default sort order should be created_at.

Update /app/models/application_record.rb

class ApplicationRecord < ActiveRecord::Base

  self.abstract_class = true
  
  # Adjust default sort order
  self.implicit_order_column = :created_at
  
end


Job done.  You now have a much more secure application.  

Good work 🙌🏻