RailsのモデルIDにUUIDを使う(翻訳)

概要

原著者の許諾を得て翻訳・公開いたします。

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のfirstlastのスコープが期待通りにならなくなります。直近のidの値が最大であるという仮定は使えませんので、新しく参加する開発者がコードベースで混乱するかもしれません。

UUIDは完全に新規のプロジェクトに向いています。しかし現在稼働中のプロジェクトでUUIDに切り替えるのは、よほどの理由がない限り避けるほうが賢明かもしれません。

関連記事

Railsのdefault_scopeは使うな、絶対(翻訳)

Rails: 日付や時刻のカラム名を命名規則に合わせよう(翻訳)

Ruby on RailsによるWEBシステム開発、Android/iPhoneアプリ開発、電子書籍配信のことならお任せください この記事を書いた人と働こう! Ruby on Rails の開発なら実績豊富なBPS

この記事の著者

hachi8833

Twitter: @hachi8833、GitHub: @hachi8833 コボラー、ITコンサル、ローカライズ業界、Rails開発を経てTechRachoの編集・記事作成を担当。 これまでにRuby on Rails チュートリアル第2版の半分ほど、Railsガイドの初期翻訳ではほぼすべてを翻訳。その後も折に触れてそれぞれ一部を翻訳。 かと思うと、正規表現の粋を尽くした日本語エラーチェックサービス enno.jpを運営。 実は最近Go言語が好き。 仕事に関係ないすっとこブログ「あけてくれ」は2000年頃から多少の中断をはさんで継続、現在はnote.muに移転。

hachi8833の書いた記事

BPSアドベントカレンダー

週刊Railsウォッチ

インフラ

BigBinary記事より

ActiveSupport探訪シリーズ