TypedUUID

A Typed UUID is an UUID with an enum embeded within the UUID.

UUIDs are 128bit or 16bytes. The hex format is represented below where x is a hex representation of 4 bits.

xxxxxxxx-xxxx-Mxxx-Nxxx-xxxxxxxxxxxx

Where:

  • M is 4 bits and is the Version
  • N is 3 bits and is the Variant of the Version followed a bit

We modify this and use the following structure where the 7th & 8th bytes in the UUID are enum XORed with the result of XORing bytes 5 & 6 with bytes 9 & 10.

xxxxxxxx-YYYY-TTTT-ZZZZ-xxxxxxxxxxxx

Where:

  • TTTT is the Type ENUM 0bNNNN_NNNN_NNNN_NNNN (0 - 65,535) XORed with (YYYY xor ZZZZ)
  • YYYY bytes XORed with ZZZZ and the Type ENUM to produce the identifying bytes
  • ZZZZ bytes XORed with YYYY and the Type ENUM to produce the identifying bytes

XORing bytes 5 & 6 with 9 & 10 and XORing again with bytes 5 & 6 of the Typed UUID will give us back the ENUM of the Type using soley the UUID.

Install

Add this to your Gemfile:

gem 'typed_uuid'

Once bundled you can add an initializer to Rails to register your types as shown below. This maps the Model Classes to an integer between 0 and 65,535.

# config/initializers/uuid_types.rb

ActiveRecord::Base.register_uuid_types({
  Listing:                  0,
  Building:                 512,
  'Building::SkyScrpaer' => 65_535
})

# Or:

ActiveRecord::Base.register_uuid_types({
  0         => :Listing,
  512       => :Building,
  65_535    => 'Building::SkyScrpaer'
})

Usage

In your migrations simply replace id: :uuid with id: :typed_uuid when creating a table.

class CreateProperties < ActiveRecord::Migration[5.2]
  def change    
    create_table :properties, id: :typed_uuid do |t|
      t.string "name", limit: 255
    end
  end
end

STI Models

When using STI Model Rails will generate the UUID to be inserted. This UUID will be calculated of the STI Model class and not the base class.

In the migration you can still used id: :typed_uuid, this will use the base class to calculated the default type for the UUID. You could also set the id to :uuid and the default to false so when no ID is given it will error.