category

ridgepoleでidにUUIDを指定する

おなじみのとおり、Ruby on Railsの各モデルのidは自動生成される連番数値(INTEGER)がデフォルトです。ただ、Rails 4以降では、設定しだいでUUIDも使えます。

ある程度以上の規模のサービスを考えるとAUTO INCREMENTでは何かの拍子にモデル間の不整合が起きる可能性があるため、「事実上衝突しない」というメリットがあるUUIDの利用を検証してみました。

結論からいうと、ridgepoleとPostgreSQLを用いた構成では、以下の手順でPRIMARY KEYにuuidを利用できます。

  1. migrationでPostgreSQLのuuid機能をオンに設定する
  2. ridgepoleのidオプションに:uuidを指定して、apply

migrationでPostgreSQLのuuid機能をオンにする

まずmigrationについては、Rails 5.1 + Using a UUID as a primary key in ActiveRecord with PostgreSQLに記載されているmigrationを作成・実行します。

(PostgreSQL v9.3以前では、Use UUIDs in Rails 4 with PostgreSQLの手順でないと動作しないかもしれません)

$ rails g migration enable_pgcrypto_extension

db/migrateに生成されたファイルに1行追加。

class EnablePgcryptoExtension < ActiveRecord::Migration[5.1]
  def change
    enable_extension 'pgcrypto'
  end
end

$ rails db:migrateを実行

== 20150705164619 EnablePgcryptoExtension: migrating ==========================
— enable_extension(“pgcrypto”)
-> 0.0629s
== 20150705164619 EnableUuidOsspExtension: migrated (0.0095s) =================

ridgepoleのスキーマ定義でidをuuidに

ridgepoleのSchemafileで、create_tableのオプションにid: :uuidを指定することで、idの設定が変わります。

create_table "users", id: :uuid do |t|
end

$ ridgepole -c config/database.yml -f config/Schemafile -a を実行。

Apply `config/Schemafile`
— create_table(“users”, {:id=>:uuid})
-> 0.0161s

pgcryptoを有効にしていないときのエラー

ridgepoleを使っているのにmigrationも実行するというのは中途半端な印象もありますが、ridgepoleではpgcryptoをenableできず、以下のようなエラーになります。

$ ridgepole -c config/database.yml -f config/Schemafile -a

Apply `config/Schemafile`
-- create_table("users", {:id=>:uuid})
[ERROR] PG::UndefinedFunction: ERROR:  function gen_random_uuid() does not exist
HINT:  No function matches the given name and argument types. You might need to add explicit type casts.
: CREATE TABLE "users" ("id" uuid DEFAULT gen_random_uuid() NOT NULL PRIMARY KEY, "name" character varying, "created_at" timestamp NOT NULL, "updated_at" timestamp NOT NULL)
*  1: create_table("users", {:id=>:uuid}) do |t|
   2:  t.string("name", {})

ほかの手段としては、以下のようにpsqlコマンドからPostgreSQLを直接操作して設定をオンにすることもできます。

postgres=# c SOME_DB_NAME;
SOME_DB_NAME=# create extension "pgcrypto";

ただし、環境設定をConfigファイル化しておかないと、リカバリの際などに作業漏れの危険もあるため、とくにridgepoleの動作に支障がなければmigrationの利用は現実的な妥協点として成立するように思います。