Skip to content
This repository

Binary uuid keys in Rails

tree: bb9fcf46c8

Fetching latest commit…

Cannot retrieve the latest commit at this time

README.mkd

activeuuid

Add binary(16) UUIDs to ActiveRecord.

Example

Create a Migration

activeuuid adds the uuid type to your migrations. Example:

class CreateEmails < ActiveRecord::Migration
  def self.up
    create_table :emails, :id => false  do |t|
      t.uuid :id, :primary_key => true
      t.uuid :sender_id  # belongs_to :sender

      t.string :subject
      t.text :body

      t.timestamp :sent_at
      t.timestamps
    end
    add_index :emails, :id
  end

  def self.down
    drop_table :emails
  end
end

include ActiveUUID::UUID in your model

class Email < ActiveRecord::Base
  include ActiveUUID::UUID
  belongs_to :sender
end

use it:

Here are some example specs:

require 'spec_helper'

describe Email do

  context "when using uuid's as keys" do
    before(:each) do
      Email.delete_all
      @guid = "1dd74dd0-d116-11e0-99c7-5ac5d975667e"
      @e = Email.new(:subject => "hello", :body => "world") {|e| e.id = UUIDTools::UUID.parse(@guid) }
      @e.save
    end

    it "the id guid should be equal to the uuid" do
      @e.id.to_s.should eql(@guid)
    end

    it "should be able to find an email by the uuid" do
      f = Email.find(UUIDTools::UUID.parse(@guid))
      f.id.to_s.should eql(@guid)
    end

  end
end

Motivation

From [2]:

[Here is a] UUID: 1e8ef774-581c-102c-bcfe-f1ab81872213

A UUID like the one above is 36 characters long, including dashes. If you store this VARCHAR(36), you're going to decrease compare performance dramatically. This is your primary key, you don't want it to be slow.

At its bit level, a UUID is 128 bits, which means it will fit into 16 bytes, note this is not very human readable, but it will keep storage low, and is only 4 times larger than a 32-bit int, or 2 times larger than a 64-bit int.

Many of the existing examples of how to use UUIDs as primary keys in Rails use strings rather than bytes (e.g. [3]).

However, this plugin stores the primary keys as bytes. To the application the keys are represented by a UUIDTools::UUID object.

Benefits of UUIDs as primary key

  • no id conflict during multi-master write
  • no locking due to auto-increment
  • with time-based UUIDs you can store a timestamp within your UUID
  • you can create natural keys (based on the SHA of model attributes)

Future work

  • more transparent support for natural and composite keys
  • support for MySQLs INSERT ... ON DUPLICATE KEY UPDATE syntax
  • support a primary column name other than id
  • work on other databases (Postgres, etc)
  • tests

Inspiration

James Golick's friendly is a great gem for NoSQL on MySQL. It's a great gateway drug to systems like Cassandra for teams that are already familiar with the ins-and-outs of MySQL.

Installation

Add this to your Gemfile

gem "activeuuid"

Or get the code here: https://github.com/jashmenn/activeuuid

Notes

Fixtures

You can use activeuuid in fixtures by using the !!binary directive in YAML. The trick is to base64 encode the raw bytes of the hexdigest.

    devin_ifttt_new_tweet:         
      id: !!binary "<%= Base64.encode64(UUIDTools::UUID.parse_hexdigest('2D79B402CBA811E1AA7C14DAE903E06A').raw) %>"
      data:
        user_id: 1
        source_id: 1               
        recipe_id: 1               
        created_at: Mon, 09 Jul 2012 14:06:21 -0700 
        body: Nice blog entry!

References

Dependencies

Rails ~> 3.1.0 - It uses the custom column serialization Aaron Patterson introduced in Rails 3.1.

Author

Nate Murray nate@xcombinator.com

Something went wrong with that request. Please try again.