6

In the migration that I want to create, the primary key of the table is a field called "id" but it is not an auto-incrementing integer. It's datatype should be uniqueidentifier (a uuid). Here is what I have tried:

create_table :some_things, :id => false do |t|
  t.column :id, :uniqueidentifier, :primary => true
  t.column :name, :string, :limit => 255
  t.column :type, :tinyint
  t.column :deleted_flag, :bit
  t.column :class_id, :uniqueidentifier
  t.timestamps
end

This creates the table alright, but there is no primary key (because I said :id=>false). If I said "create_table :some_things, :id => true, :primary => :id", then "id" becomes the primary key, but it is an auto-incrementing integer, not a non-auto-incrementing uuid.

How can I make this migration work so that the primary key is a field called "id" of type "uniqueidentifier" (non-auto-incrementing)?

I'm using: SQL Server 2008, Rails/ActiveRecord 3.0.3, the activerecord-sqlserver-adapter gem, and an ODBC connection.

Mark
  • 61
  • 3
  • This is a duplicate of http://stackoverflow.com/questions/1200568/using-rails-how-can-i-set-my-primary-key-to-not-be-an-integer-typed-column -- should we consolidate the questions? – David J. Mar 05 '13 at 02:06

2 Answers2

1

I don't know how to solve problem directly, but I've got a workaround.

Put in your migration column id without 'primary' directive. And after method 'create_table' in migration execute SQL's add constraint

execute "ALTER TABLE some_things ADD PRIMARY KEY (id);"

(don't use MSSQL and may be mistake in SQL-syntax for it)

In your model define primary key by adding

self.primary_key = "id"

or

set_primary_key :id
dmr
  • 322
  • 1
  • 11
1

Here was how I solved this problem:

1) In my migration, I allowed the migration to autogenerate the id and the id_sequence, and added a dummy uuid column (called guid here). It was simply the easiest way to go in the development path. So for

class Thing < ActiveRecord::Base
  attr_accessible :name, :description, :guid
end

I use migration

class CreateThings < ActiveRecord::Migration
  def change
    create_table :things do |t|
      t.string :name
      t.string :description
      t.uuid :guid

      t.timestamps
    end
  end
end

2) After the migration, I can run the following through a sql client

ALTER TABLE things DROP CONSTRAINT things_pkey;
ALTER TABLE things ADD PRIMARY KEY (guid);
ALTER TABLE things DROP COLUMN id;
ALTER TABLE things RENAME COLUMN guid TO id;

3) I am using two gems to help with this

gem 'uuidtools'
gem 'postgres_ext'

Clearly, my solution is against a Postgres DB ... but I post this because it seems relevant to one of your issues, namely how do you use Rails to keep the db at arms length? At any rate UUIDtools is db agnostic.

4) In my Thing class I use this

class Thing < ActiveRecord::Base
  include Extensions::UUID

where UUID is simply a module like so

module Extensions
  module UUID
    extend ActiveSupport::Concern

    included do
      # set_primary_key 'guid'
      before_create :generate_uuid

      def generate_uuid
        self.id = UUIDTools::UUID.random_create.to_s
      end
    end
  end
end

By the way, I found the latter in this gist:

https://gist.github.com/rmoriz/937739

But my solution is a little different.

jjk
  • 536
  • 7
  • 15