A universally unique identifier (UUID) is a 128-bit number used to identify information in computer systems. Sometimes it is referred to as a ‘globally unique identifier’.
These are a native column type in PostgreSQL. You can find more details on native Postgres types in the Rails Guides.
…using Rails’ default incrementing integer
…PostgreSQL’s UUID support. Ruby on Rails has had the ability to use UUIDs as the
id for ActiveRecord models since version 5.0.
Enable the PostgreSQL extension
bin/rails g migration enable_extension_for_uuid
class EnableExtensionForUuid < ActiveRecord::Migration[5.1] def change enable_extension 'pgcrypto' unless extension_enabled?('pgcrypto') end end
Rails.application.config.generators do |g| g.orm :active_record, primary_key_type: :uuid end
This changes the default column type for primary keys, configuring your migration generator to set
id: :uuid for new tables.
In future migrations
You’ll have to use
type: :uuid when creating relations.
class AddNewTable < ActiveRecord::Migration[5.1] def change create_table :related_model do |t| t.references :other, type: :uuid, index: true end end end
Using UUIDs as the
id in your Rails models instead of incrementing integers helps you avoid collisions. The UUIDs are globally unique meaning you can know that different models cannot possibly have the same
id and you can even assign them client-side or in other systems.
With an incrementing integer
id the size of your data can be inferred from the outside i.e.
id 5 is the fifth record created. With UUIDs no-one can guess the size of your database tables, which might be information you are keen to keep secret. You can get round this by generating ‘public ids’ or ‘slugs’ for exposed URLs… but then, why not use a built-in tool?
From a security perspective, using UUIDs prevents the situation where a malicious attacker could attempt to gain access to data by guessing a model
id in your URLs. UUIDs are extremely hard to guess.
This is a case where you are making a choice toward a little more complexity, but for good reasons.
If you’re using PostgreSQL this is a straightforward change and has little performance cost. MySQL is a more complicated proposition and I wouldn’t bother.
last scopes work in an unexpected way with UUID ids. You can no longer assume the ‘highest’
id is the most recent, which could be confusing for new developers to your codebase.
Using UUIDs is a good idea in brand new projects, but it might be wise to avoid transferring to UUIDs in a running production system unless you have a good reason to do so.
Don’t miss my next post, sign up to the One Ruby Thing email and get my next post in your inbox.