Railsアプリへのuuidの適用方法
Railsアプリへのuuid適用方法などは、弊社の技術記事[Rails] モデルのIDにUUIDを使って玄人感を出すで既に書かれているので省略します。
今回は既存テーブルのidを変更するため、どのようにマイグレーションするか?がメインです。
uuidをrailsアプリに適用するコードだけ記します。
postgresqlのuuid拡張機能を有効化
rails g migration enable_extension_for_uuid
class EnableExtensionForUuid < ActiveRecord::Migration[6.0]
def change
enable_extension 'pgcrypto' unless extension_enabled?('pgcrypto')
end
end
initializers内でprimary keyのデフォルト値をuuid化
Rails.application.config.generators do |g| g.orm :active_record, primary_key_type: :uuid end
Railsアプリへの詳しいuuid適用方法は下記を参照してください! [Rails] モデルのIDにUUIDを使って玄人感を出す
バージョン
- Ruby 2.7.0
- Rails 6.0.3.4
- PostgreSQL 13.0
スキーマ
下記構成で記述します
テーブル名
- アソシエーション
- アソシエーション
users
- has_many event_participants
events
- has_many event_participants
event_participants
- belongs_to users
- belongs_to events
users
| id | name |
|---|---|
| 1 | hoge |
| 2 | huga |
events
| id | name |
|---|---|
| 1 | hoge |
| 2 | huga |
event_participants
| id | event_id | user_id |
|---|---|---|
| 1 | 1 | 1 |
| 2 | 2 | 1 |
| 3 | 2 | 2 |
上の構成ですべてですが、ざっくり日本語で書くと、ユーザーがイベントに参加できて、イベントの参加者を多対多の中間テーブルで管理する。みたいな感じです。
マイグレーション
まずusersテーブルからマイグレーションしていきます。
class ChangeUserIdTypeToUuid < ActiveRecord::Migration[6.0]
def up
# usersテーブルにuuid追加
add_column :users, :uuid, :uuid, null: false, default: 'gen_random_uuid()'
# 関連テーブルにuuid追加
add_column :event_participants, :user_uuid, :uuid
# 関連テーブルのuuidを更新(これでusersのuuidとevent_participantsのuser_uuidが紐づく)
execute <<~SQL
UPDATE event_participants SET user_uuid = users.uuid
FROM users WHERE event_participants.user_id = users.id;
SQL
# usersの元々のprimary keyであるidを消す
# 外部キーとして参照されていると消せないので、関連テーブルからの参照を切る
remove_foreign_key :event_participants, :users
remove_reference :event_participants, :user, index: true
# usersのidを消して、追加したuuidのカラム名をidに変更
change_table :users do |t|
t.remove :id
t.rename :uuid, :id
end
# usersのuuid化したidをprimary keyとして設定
execute 'ALTER TABLE users ADD PRIMARY KEY (id);'
# 関連テーブルに追加したuuidを元々あった名前に変更(元々あったuser_idはusersテーブルのidを消した時に消えてるはずなので競合しない)
rename_column :event_participants, :user_uuid, :user_id
# 関連テーブルのuuid化したuser_idを外部キーとして設定
add_foreign_key :event_participants, :users
add_index :event_participants, :user_id
change_column_null :event_participants, :user_id, false
end
def down
# idに戻すことは無いと思うのでrollback不可を明示的にする
raise ActiveRecord::IrreversibleMigration
end
end
これでusersのidと関連テーブルであるevent_participansのuser_idがuuidに変更できたと思います。
eventsテーブルも同じ要領でできますね。
最後にevent_participantsのidを変更していきます。
class ChangeEventParticipantsIdTypeToUuid < ActiveRecord::Migration[6.0]
def up
# event_partivipantsテーブルにuuid追加
add_column :event_participants, :uuid, :uuid, null: false, default: 'gen_random_uuid()'
# event_participantsのidを消して、追加したuuidのカラム名をidに変更
change_table :event_participants do |t|
t.remove :id
t.rename :uuid, :id
end
# event_participantsのuuid化したidをprimary keyとして設定
execute 'ALTER TABLE event_participants ADD PRIMARY KEY (id);'
end
def down
raise ActiveRecord::IrreversibleMigration
end
end
外部キーとして参照されてないidをuuidに変更するのはシンプルですね!
まとめ
やはり作成済みのテーブルのidを変更するにはひと手間かかりますね。 常にユーザーがアクセスしている本番環境で途中から変更するのは中々現実的ではないとは思いますが、 ローンチ前かつデータがちょっと入ってて消したくない(消えてもそんな問題じゃない)。みたいな時には役立つかなと思いました。
やっぱidよりuuidの方がかっちょいい!