🤖

UUID主キーをActiveRecordで使う(PostgreSQL 13+)

takeyuweb2023/01/16に公開

Modelでの設定は不要で、カラムがPostgreSQLのUUID型で作成されていれば扱えます。

サンプルコード

db/migrate/20230115084803_create_backets.rb
class CreateBackets < ActiveRecord::Migration[7.0]
  def change
    create_table :backets, id: :uuid do |t|
      t.timestamps
    end
  end
end
db/migrate/20230115090623_create_items.rb
class CreateItems < ActiveRecord::Migration[7.0]
  def change
    create_table :items, id: :uuid do |t|
      t.string :name, null: false
      t.integer :price, null: false

      t.timestamps
    end
  end
end
db/migrate/20230115090735_create_backet_items.rb
class CreateBacketItems < ActiveRecord::Migration[7.0]
  def change
    create_table :backet_items, id: :uuid do |t|
      t.references :backet, null: false, foreign_key: true, type: :uuid
      t.references :item, null: false, foreign_key: true, type: :uuid
      t.index %i[backet_id item_id], unique: true
      t.integer :quantity, null: false

      t.timestamps
    end
  end
end

生成されるスキーマ

db/schema.rb
ActiveRecord::Schema[7.0].define(version: 2023_01_15_090735) do
  # These are extensions that must be enabled in order to support this database
  enable_extension "plpgsql"

  create_table "backet_items", id: :uuid, default: -> { "gen_random_uuid()" }, force: :cascade do |t|
    t.uuid "backet_id", null: false
    t.uuid "item_id", null: false
    t.integer "quantity", null: false
    t.datetime "created_at", null: false
    t.datetime "updated_at", null: false
    t.index ["backet_id", "item_id"], name: "index_backet_items_on_backet_id_and_item_id", unique: true
    t.index ["backet_id"], name: "index_backet_items_on_backet_id"
    t.index ["item_id"], name: "index_backet_items_on_item_id"
  end

  create_table "backets", id: :uuid, default: -> { "gen_random_uuid()" }, force: :cascade do |t|
    t.datetime "created_at", null: false
    t.datetime "updated_at", null: false
  end

  create_table "items", id: :uuid, default: -> { "gen_random_uuid()" }, force: :cascade do |t|
    t.string "name", null: false
    t.integer "price", null: false
    t.datetime "created_at", null: false
    t.datetime "updated_at", null: false
  end

  add_foreign_key "backet_items", "backets"
  add_foreign_key "backet_items", "items"
end

default: "gen_random_uuid()" は不要

生成されるスキーマを見てわかるように、UUID生成のための gen_random_uuid() は自動で設定されるため、migrationにおいて default: "gen_random_uuid()" は不要です。

https://github.com/rails/rails/blob/8015c2c2cf5c8718449677570f372ceb01318a32/activerecord/lib/active_record/connection_adapters/postgresql/schema_definitions.rb#L48-L54

enable_extension 'pgcrypto' は不要

PostgreSQL 13以上では gen_random_uuid()pgcrypto 拡張は不要です。
PostgreSQL 12以下の場合は、 create_table id: :uuid の前に拡張の有効化が必要です。

enable_extension 'pgcrypto' unless extension_enabled?('pgcrypto')

https://www.postgresql.jp/document/13/html/functions-uuid.html

generatorによって作成されるmigrationの主キーのデフォルト

次のように設定しておくと作成されるmigrationの主キー型と外部キー型のデフォルトが :uuid になります。

config/application.rb
module MyApp
  class Application < Rails::Application
    # 省略
    config.generators do |g|
      g.orm :active_record, primary_key_type: :uuid
    end
  end
end

https://github.com/rails/rails/blob/v7.0.4/activerecord/lib/rails/generators/active_record/migration/migration_generator.rb#L11
https://github.com/rails/rails/blob/8015c2c2cf5c8718449677570f372ceb01318a32/activerecord/lib/rails/generators/active_record/migration.rb#L20-L28
https://github.com/rails/rails/blob/v7.0.4/activerecord/lib/rails/generators/active_record/migration/templates/create_table_migration.rb.tt#L3

参考

https://railsguides.jp/active_record_postgresql.html#uuid
https://www.postgresql.jp/document/13/html/functions-uuid.html

タケユー・ウェブ株式会社

Ruby on Rails や AWS が得意なWebサービス受託開発会社です。 中小規模のWebサービスの新規開発の他、他の個人開発者などから引き継いで保守運用を行ったりしています。 新規開発、お手伝いや顧問、レガシーなRailsプロジェクトの保守など、ニーズにあわせて対応できます。ご相談ください。

Discussion

ログインするとコメントできます