rails uuid primary key

Slightly more obscure

Published November 22, 2020 #rails, #uuid, #postgres

Exposing primary keys externally just sort of invites people to poke around in your system. Lets configure rails to use uuid instead.

Create a postgres rails app

We are going to be relying upon the pgcrypto postgres extension, so lets go ahead a create a postgres based rails application.

rails new testapp -d=postgresql
cd testapp

Now we tell our generators that we want our primary key type to be :uuid:

# config/initializers/generators.rb
Rails.application.config.generators do |g|
  g.orm :active_record, primary_key_type: :uuid

And we need to change the sort order, since when using integer id's for the primary key rails uses that. We'll tell it to use created_at instead:

# app/models/application_record.rb
class ApplicationRecord < ActiveRecord::Base
  self.abstract_class = true
  # Sort records by date of creation instead of primary key
  self.implicit_order_column = :created_at

Create your first migration

rails g model post title content:text

And make sure that we add to the change method of the migration!

enable_extension 'pgcrypto' unless extension_enabled?('pgcrypto')

Start postgres and test it out

Lets create a throwaway postgres container to see how things are working

docker run -it --rm -p 5432:5432 -e POSTGRES_PASSWORD=password postgres:13.1

This will delete itself when you close out of it.

We'll need to create a simple config/database.yml file to connect to it:

default: &default
  adapter: postgresql
  encoding: unicode
  host: localhost
  username: postgres
  password: password
  pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>

  <<: *default
  database: testapp_development

  <<: *default
  database: testapp_test

  <<: *default
  database: testapp_production

And then we create and migrate:

rake db:create:all
rake db:migrate

And now we can test it out:

$ rails c
Running via Spring preloader in process 3134
Loading development environment (Rails
irb(main):001:0> Post.create title: "First post"
   (0.5ms)  BEGIN
  Post Create (3.5ms)  INSERT INTO "posts" ("title", "created_at", "updated_at") VALUES ($1, $2, $3) RETURNING "id"  [["title", "First post"], ["created_at", "2020-11-22 16:36:20.826249"], ["updated_at", "2020-11-22 16:36:20.826249"]]
   (8.7ms)  COMMIT
=> #<Post id: "4c3f20d0-a17b-473d-99f1-9824ba5207c2", title: "First post", content: nil, created_at: "2020-11-22 16:36:20", updated_at: "2020-11-22 16:36:20">
irb(main):002:0> Post.create title: "Second post"
   (3.1ms)  BEGIN
  Post Create (13.0ms)  INSERT INTO "posts" ("title", "created_at", "updated_at") VALUES ($1, $2, $3) RETURNING "id"  [["title", "Second post"], ["created_at", "2020-11-22 16:36:27.499092"], ["updated_at", "2020-11-22 16:36:27.499092"]]
   (26.5ms)  COMMIT
=> #<Post id: "2c1da815-dfe4-48e5-bdb7-13a573035825", title: "Second post", content: nil, created_at: "2020-11-22 16:36:27", updated_at: "2020-11-22 16:36:27">
irb(main):003:0> Post.last
  Post Load (0.7ms)  SELECT "posts".* FROM "posts" ORDER BY "posts"."created_at" DESC LIMIT $1  [["LIMIT", 1]]
=> #<Post id: "2c1da815-dfe4-48e5-bdb7-13a573035825", title: "Second post", content: nil, created_at: "2020-11-22 16:36:27", updated_at: "2020-11-22 16:36:27">

The sql for the Post.last command is SELECT "posts".* FROM "posts" ORDER BY "posts"."created_at" DESC LIMIT $1 which is using the created_at column.

But this doesn't support sqlite

The uuid column type isn't supported by sqlite. I think it's better to test on the same database type as production, and with docker it's easy to throw things up and tear them down, etc. but caveat.


  1. UUID Primary Key in Rails 6 with PostgreSQL and Active Record

  2. Using UUIDs to your new Rails 6 application

Read next

See also

Tailwind and Rails

postcss setup

Tailwind is a really nice set of CSS utility classes that let you style up a page staying largely in one file at a time. Rails has it's own wild way of dealing with javascript, so lets go through how to make them play well together. Install tailwindcss Make sure that you have node 12.13 or higher: node -v If not, then upgrade node. Inside of your rails project, install tailwind.

Read more

Rails in Docker

Why install ruby locally?

In leveraging disposability for exploration we looked at how to build software without having it installed on your local computer. Lets go through how to setup and develop a rails application with this process. docker-compose.yml all the way down We're going to create our app by adding things to a docker-compose.yml file as needed. Lets create the first one, which will contain our rails container as well as a volume for keeping track of all the gems.

Read more