hacking native UUID support into Schema:Dump

Want to use PostgreSQL’s native UUID datatype but AR won’t let you use it with migrations?

/Library/Ruby/Gems/1.8/gems/activerecord-2.0.2/lib/active_record/connection_adapters/postgresql_adapter.rb:

# insert into
def simplified_type
  # UUID type
  when /^uuid$/
  :uuid
# insert into
def native_database_types
  :uuid      => { :name => "uuid" },

Well, that’ll get your data OUT of the database, but AR will throw a fit when you try to load it back in unless you also add uuid into the range of column types TableDefinition will accept:

in /Library/Ruby/Gems/1.8/gems/activerecord-2.0.2
/lib/active_record/connection_adapters/abstract/schema_definition.rb:

# insert into
def column(name, type, options = {})
 
%w( string text integer float decimal datetime timestamp time date binary boolean uuid ).each do |column_type|

Now you can do this:

    t.uuid     "uuid",   :null => false

About the nastiest possible hack you can do but works in/out. Here’s a patch if you don’t want to do it yourself, but no guarantees.

UPDATE:

And don’t forget to write your migrations like this to stop AR from inserting its “helpful” id columns with autoincrementing serials which your DB doesn’t need and can’t use:

  def self.up
    create_table :transactions, :id => false do |t|
      t.uuid     "id",  :null => false
      t.timestamps
    end
  end

UPDATE 2:

I now do not recommend doing this. It’s more trouble than it’s worth. There is very little you gain in forcing native UUID type in Postgres, and the complexity, hacks, loss of cross-platform compatibility and general annoyance you face are just not worth it.

Just use a string class for any UUIDs. Of course, the final hint on this page – the no-id switch for migrations – is still useful and you should use that.

Tags: , , ,

3 Responses to “hacking native UUID support into Schema:Dump”

  1. jianshi.org » Blog Archive » PostgreSQL UUID with Rails Says:

    [...] From Sho Fukamachi’s Blog: [...]

  2. eno Says:

    The backside of that technique, however, is that all lookups of your models require a string index in the database which is considerably slower than an integer index. Besides, adding an unique index on your table’s id wouldn’t hurt.

  3. Sho Says:

    eno, do you have a benchmark to suggest an integer lookup is significantly faster than a string lookup? I didn’t think it was but I’m happy to be proven wrong.

    Not that it matters – you can’t use integers anyway in this use case. The reason you use UUIDs is to enable multi master replication. With multiple machines, possibly on different continents, “unique” is useless, and trying to use an incremented integer ID is a nightmare. Unless you really, really need this though, definitely stick with autoincremented integer IDs.

Leave a Reply