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.

1
2
rails new testapp -d=postgresql
cd testapp

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

1
2
3
4
# config/initializers/generators.rb
Rails.application.config.generators do |g|
  g.orm :active_record, primary_key_type: :uuid
end

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:

1
2
3
4
5
6
# 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
end

Create your first migration

1
rails g model post title content:text

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

1
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

1
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:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
default: &default
  adapter: postgresql
  encoding: unicode
  host: localhost
  username: postgres
  password: password
  pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>

development:
  <<: *default
  database: testapp_development

test:
  <<: *default
  database: testapp_test

production:
  <<: *default
  database: testapp_production

And then we create and migrate:

1
2
rake db:create:all
rake db:migrate

And now we can test it out:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
$ rails c
Running via Spring preloader in process 3134
Loading development environment (Rails 6.0.3.4)
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.

Previously

Tailwind and Rails postcss setup

2020-11-18

Next

ankane/blazer

2020-12-04

labnotes

Previously

Getting Websters More glorious language

2020-07-30

Next

Logging with an HTTP Proxy Simple MITM debugging

2021-01-22