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

概要 原著者の許諾を得て翻訳・公開いたします。 英語記事: 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に切り替えるのは、よほどの理由がない限り避けるほうが賢明かもしれません。 関連記事 Railsのdefault_scopeは使うな、絶対(翻訳) Rails: 日付や時刻のカラム名を命名規則に合わせよう(翻訳)