I have covered forcing ActiveRecord to respect UUID data types in Migrations before. That helps us create our database – now what about in use? We need to create the UUIDs and store them in the database.
These examples all rely on the uuidtools
gem, so install that if you haven’t already (and require it somewhere in environment.rb
).
1. Setting a UUID using ActiveRecord callbacks
If you don’t need the UUID in the object upon creation but only want to ensure it’s there upon save, do this. Suggestion initially from this page, changes are mine.
We will use the before_create
callback to ask AR to add a UUID of our choosing before the record is saved.
Add this to your lib directory:
# lib/uuid_helper.rb require 'uuidtools' module UUIDHelper def before_create self.id = UUID.random_create.to_s end end
And now include this in your models:
class Airframe < ActiveRecord::Base include UUIDHelper #my stuff end
>> Airframe.new => #< Airframe id: nil, maker_id: nil> >> Airframe.create! => #< Airframe id: "1a82a408-32e6-480e-941d-073a7e793299", maker_id: nil>
2. Initialising a model with a UUID
If you want the UUID in the model before save, i.e. upon initialisation, we have to get a little more fancy:
# lib/uuid_init.rb require 'uuidtools' module UUIDInit def initialize(attrs = {}, &block) super ['id'] = UUID.random_create.to_s end end
Now include this in your models:
class Flightpath < ActiveRecord::Base include UUIDInit # my stuff end
>> Flightpath.new => #< Flightpath created_at: nil, id: "5e5bcd63-070d-4252-8556-2876ddd83b54">
Be aware that it will conflict with any other initialisation you do in there, so you might want to simply copy in the whole method if you need other fields upon initialisation:
class User < ActiveRecord::Base def initialize(attrs = {}, &block) super ['balance'] = 0.0 ['id'] = UUID.random_create.to_s end end
>> User.new => #
3. Sessions
All this is very well for your own models, but what about Rails’ inbuilt sessions? By default, they want an autoincrementing integer primary key.
The good news is it’s easy to override. Your migration should look like this:
create_table "sessions", :id => false, :force => true do |t| t.string "session_id" t.text "data" t.datetime "updated_at" t.datetime "created_at" end
Now add this to your environment.rb file:
# config/environment.rb CGI::Session::ActiveRecordStore::Session.primary_key = 'session_id'
And this to your Application Controller:
# app/controllers/application.rb class ApplicationController < ActionController::Base before_filter :config_session # at the top, if possible def config_session session.model.id = session.session_id end end
And voila, your session store is using the session_id as its primary key. I don’t see any point in using a UUID for your sessions’ PK, but if you want to you’ll find an example override class in:
actionpack/lib/action_controller/session/active_record_store.rb.
Remember to drop any preexisting sessions table in your database, or it will likely complain of null ids when you switch to session_id
as your primary key.
Tags: postgresql, rails, uuid
July 8th, 2008 at 11:00 am
[...] Switching to PostgreSQL Strict databases are great for discipline hacking native UUID support into Schema:Dump UUIDs in Rails redux [...]