やりたかったこと
Docker Compose環境下のRailsでプライマリキーをUUIDにしたかった。
ググるとPostgresでUUIDを使う為のDockerfileが散見されたが、最適な手段で実装したかった。
Rails Guides の UUID Primary Keys を参考に実施していく。
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以外の選択肢も検討した方がよさげ。
参考