Rails 5.1 + Using a UUID as a primary key in ActiveRecord with PostgreSQL

13th April 2017

Introduction

Rails 5.1 brings many improvements and plenty of changes. Among them is the change of function that is used when generating UUIDs.

For PostgreSQL >= 9.4, ActiveRecord will now use pgcrypto’s gen_random_uuid function whereas previously uuid-ossp’s uuid_generate_v4 function was used.

Follow these steps to add UUID primary keys to your Rails 5.1+ application.

Add a migration

First we need to enable the PostgreSQL pgcrypto extension in a migration. Lets start by creating a blank migration:

$ rails generate migration enable_pgcrypto_extension

Then change the file to enable the extension. It should look something like this:

class EnablePgcryptoExtension < ActiveRecord::Migration[5.1]
  def change
    enable_extension 'pgcrypto'
  end
end

Change the primary default type

When you generate models ActiveRecord will use Integer as the type for id by default. In Rails 5 you can change this behaviour by adding the following to your config/application.rb file.

config.generators do |g|
  g.orm :active_record, primary_key_type: :uuid
end

Try it out

Now when you run rails generate model post title:string your migration file should look something like this:

class CreatePosts < ActiveRecord::Migration[5.1]
  def change
    create_table :posts, id: :uuid do |t|
      t.string :title

      t.timestamps
    end
  end
end

Further help

It’s most likely you’ve ended up here from a Google search, here are some errors that you might experience that relate to this guide:

I get an error about gen_random_uuid when I run rake db:migrate ?

If you get the following error when you run rake db:migrate then it’s likely you’ve hit the issue I wrote this post above.

function gen_random_uuid() does not exist

I get an error about uuid_generate_v4 when I run rake db:migrate ?

If you get the following error when you run rake db:migrate:

function uuid_generate_v4() does not exist

It’s likely you have old references to uuid_generate_v4 in your code. Most likely a migration like this:

add_column :posts, :id, default: "uuid_generate_v4()", null: false

To ensure all your old as well as your new migrations continue to run simply enable both extensions in a migration:

class EnablePgcryptoExtension < ActiveRecord::Migration[5.1]
  def change
    enable_extension 'uuid-ossp'
    enable_extension 'pgcrypto'
  end
end