Docker Compose + Rails + Postgresでいい感じにUUID v4を利用する
やりたかったこと
Docker Compose環境下のRailsでプライマリキーをUUIDにしたかった。
ググるとPostgresでUUIDを使う為のDockerfileが散見されたが、最適な手段で実装したかった。
Rails Guides の UUID Primary Keys を参考に実施していく。
PostgreSQL >= 9.4 を使う
UUIDの実装には、Postgresの pgcrypto モジュールを利用するのでPostgres >= 9.4を利用する。 MySQLでは同様の機能がなく、MySQL上で実現するには一手間必要なので今回はPostgresを利用することとした。
version: '3' services: rails: build: . command: "bundle exec rails s -p 3000 -b '0.0.0.0' -e development" environment: - TZ=Asia/Tokyo - WEB_CONCURRENCY=1 - RAILS_MAX_THREADS=5 volumes: - ./rails:/app - bundle_volume:/usr/local/bundle ports: - '3000:3000' depends_on: - postgres postgres: image: postgres:11-alpine restart: always environment: - POSTGRES_USER=postgres - POSTGRES_PASSWORD=password - POSTGRES_DB=app_development ports: - '5432:5432' volumes: - postgres_volume:/var/lib/postgresql/data volumes: postgres_volume: driver: local bundle_volume: driver: local
pgcrypto か uuid-ossp どちらを利用すべきか?
Active Record and PostgreSQL — Ruby on Rails Guides](https://edgeguides.rubyonrails.org/active_record_postgresql.html#uuid-primary-keys) に従うと pgcrypto
or uuid-ossp
エクステンションを有効にする必要がある。
検索する限りだと、 uuid-ossp
を利用している記事も多く見つかったが、 uuid-ossp に依ると、 uuid-ossp
はあまりよく維持されておらず、
注意: ランダムに生成された(バージョン4)UUIDのみが必要な場合には、代わりにpgcryptoモジュールのgen_random_uuid()を利用すること検討してください。
とあるので pgcrypto
を使う。
pgcryptoエクステンションの有効化
下記のようなのマイグレーションファイルを作って実行した。
class EnableExtensionPgcrypto < ActiveRecord::Migration[5.2] def change enable_extension 'pgcrypto' unless extension_enabled?('pgcrypto') end end
pgcryptoやuuid-osspを有効にするだけのshスクリプトを実行するよう拡張されたDockerfileも確認したが、ぶっちゃけ有効化にはSQLコマンドを実行するだけでよいので、マイグレーションファイルでの実行の方がDockerイメージを使い回せてスマート。
UUIDの利用する際にはマイグレーションファイルに下記のように書く。
class CreateUsers < ActiveRecord::Migration[5.2] def change <200b> create_table :posts, id: :uuid, default: 'gen_random_uuid()' do |t| <200b> t.text :body t.timestamps end end end
のように型は uuid
になり、
class CreateUsers < ActiveRecord::Migration[5.2] def change create_table :comments, id: :uuid, default: 'gen_random_uuid()' do |t| t.references :post, type: :uuid t.text :body t.timestamps end end end
参照する場合には、 t.references
を使う。
プライマリキーのデフォルトをUUIDにする
application.rbに下記を書けばOK
config.generators.orm :active_record, primary_key_type: :uuid
デメリット
至るところで言われているが、first, lastメソッドが意図通りには利用できなくなる。 first, lastメソッドの順番は、 rails/finder_methods.rb at 5-2-1 · rails/rails には、
def ordered_relation if order_values.empty? && primary_key order(arel_attribute(primary_key).asc) else self end end
となっている為、時系列ではないランダムなUUID v4ではcreated_at
を利用した取得方法になるだろう。
どうしてもIDの順序を保証する必要がある場合には、UUID v4以外の選択肢も検討した方がよさげ。
- Snowflake形式のIDを採用した場合の苦労ポイント - yoskhdia’s diary
- 分散環境でユニークなidを発番するGo製プロダクト「katsubushi」のご紹介 - KAYAC engineers' blog
- 軽量なTime-based ID生成器”shakeflake(仮称)”について - SmartNews Engineering Blog
Kindle Paperwhite、電子書籍リーダー、防水機能搭載、Wi-Fi 、32GB、広告つき(Newモデル)
- 出版社/メーカー: Amazon
- 発売日: 2018/11/07
- メディア: エレクトロニクス
- この商品を含むブログを見る