概要
原著者の許諾を得て翻訳・公開いたします。
- 英語記事: Choose UUIDs for model IDs in Rails
- 原文公開日: 2017/11/26
- 著者: Andy Croll
RailsのモデルIDにUUIDを使う(翻訳)
UUID(universally unique identifier)は、コンピュータシステムで情報の識別に用いられる128ビットの数字です。GUID(globally unique identifier)と呼ばれることもあります。
PostgreSQLにはネイティブのカラム型があります。PostgreSQLの型についてはRailsガイド(英語)をご覧ください。
Railsのデフォルトであるカウントアップする整数id
の代わりに、次のPostgreSQLのUUIDサポートを使います。
Ruby on Rails 5.0以降、ActiveRecordモデルでUUIDをid
として利用できる機能があります。
PostgreSQL拡張を有効にする
bin/rails g migration enable_extension_for_uuid
を実行してEnableExtensionForUuid
モデルを以下のようにします。
class EnableExtensionForUuid < ActiveRecord::Migration[5.1]
def change
enable_extension 'pgcrypto' unless extension_enabled?('pgcrypto')
end
end
config/initializers/generators.rb
を作成する
Rails.application.config.generators do |g|
g.orm :active_record, primary_key_type: :uuid
end
これによって主キーで使われるデフォルトのカラム型が変更され、マイグレーションジェネレータで新規テーブル作成時にid: :uuid
が設定されるようになります。
以後のマイグレーション
リレーション作成時にtype: :uuid
を使う必要があります。
class AddNewTable < ActiveRecord::Migration[5.1]
def change
create_table :related_model do |t|
t.references :other, type: :uuid, index: true
end
end
end
UUIDを使う理由
Railsのモデルで、カウントアップする整数の代わりにUUIDをid
として使うことで、衝突の回避に役立ちます。UUIDの一意性はグローバルなので、異なるモデルが同じid
を持つ可能性が発生せず、クライアント側や別のシステムで代入することもできます。
整数id
がカウントアップされると、データのサイズを外部から推測可能になってしまいます。たとえばid
が5なら5番目に作成されたレコードであることがわかります。UUIDを用いるとデータベーステーブルのサイズを誰も推測できなくなります(テーブルサイズを知られたくない場合)が、外部に公開されるURLでパブリックなidやスラッグ(slug)を使っていれば一応回避できてしまいます。それにしてもRails組み込みのツールを使わない理由はどこにあるのでしょうか?
セキュリティの観点からは、UUIDを用いることで、悪意のある攻撃者がURLからモデルのid
を推測してデータにアクセスしようとする事態を防止します。UUIDの推測はきわめて困難です。
UUIDは、それによって少々複雑になっても構わない十分な理由がある場合に向いています。
UUIDを使わない方がよい場合
PostgreSQLを使っている場合はシンプルな変更で済み、パフォーマンス上のコストもほとんど増加しません。MySQLの場合はもっと複雑になります。私は気にしないと思いますが。
UUIDのid
では、ActiveRecordのfirst
やlast
のスコープが期待通りにならなくなります。直近のid
の値が最大であるという仮定は使えませんので、新しく参加する開発者がコードベースで混乱するかもしれません。
UUIDは完全に新規のプロジェクトに向いています。しかし現在稼働中のプロジェクトでUUIDに切り替えるのは、よほどの理由がない限り避けるほうが賢明かもしれません。