使用UUID主键进行ActiveRecord迁移

时间:2011-02-14 19:29:47

标签: sql-server ruby-on-rails-3 primary-key rails-migrations

在我想要创建的迁移中,表的主键是一个名为“id”的字段,但它不是一个自动递增的整数。它的数据类型应该是uniqueidentifier(一个uuid)。这是我尝试过的:

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

这会创建表格,但没有主键(因为我说:id => false)。如果我说“create_table:some_things,:id => true,:primary =>:id”,则“id”成为主键,但它是一个自动递增的整数,而不是非自动递增的uuid

如何使此迁移工作,以便主键是名为“uniqueidentifier”类型的“id”字段(非自动递增)?

我正在使用: SQL Server 2008, Rails / ActiveRecord 3.0.3, activerecord-sqlserver-adapter gem, 和ODBC连接。

2 个答案:

答案 0 :(得分:1)

我不知道如何直接解决问题,但我有一个解决方法。

在没有“primary”指令的情况下输入您的迁移列ID。在迁移中的'create_table'方法之后执行SQL的添加约束

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

(不要使用MSSQL,可能在SQL语法中有误)

在您的模型中,通过添加

来定义主键
self.primary_key = "id"

set_primary_key :id

答案 1 :(得分:1)

以下是我解决这个问题的方法:

1)在我的迁移中,我允许迁移自动生成id和id_sequence,并添加了一个虚拟uuid列(此处称为guid)。这只是进入开发路径的最简单方法。

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

我使用迁移

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)迁移后,我可以通过SQL客户端

运行以下命令
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)我正在使用两颗宝石来帮助解决这个问题

gem 'uuidtools'
gem 'postgres_ext'

显然,我的解决方案是针对Postgres数据库...但我发布这个因为它似乎与你的一个问题相关,即你如何使用Rails来保持数据库的长度?无论如何,UUIDtools是db不可知的。

4)在我的Thing课程中,我使用了这个

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

其中UUID只是一个像这样的模块

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

顺便说一下,我在这个要点中找到了后者:

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

但我的解决方案有点不同。