RailsのModelはPrimary keyに何も指定をしないとidカラムがPrimary keyとなります。(サロゲートキー)
idカラムの値はインクリメントされていくのですが、本記事はidカラムの値をインクリメントされる値から、ULIDに変更する方法です。
環境
Ruby: 2.7.2
Rails: 6.1.1
DB: PostgreSQL 13.1
ライブラリ: ULID
手順
- カラムの型を変更(Migration)
- Modelに追記
- テスト
Migration
class CreateUsers < ActiveRecord::Migration[6.1]
def change
# idカラムをstringにする
create_table :users, id: :string do |t|
t.string :name, null: false
t.timestamps
end
end
end
Model
models/user.rb
class User < ApplicationRecord
include Identifiable
end
models/concerns/identifiable.rb
module Identifiable
extend ActiveSupport::Concern
included do
# memo: primary_keyのデフォルトの値は`id`
attribute primary_key, :string, default: -> { ULID.generate }
end
end
実行結果
irb(main):001:0> User.new
=> #<User id: "01EX96S3Q185V0FSMFCCJBKN6P", name: nil, created_at: nil, updated_at: nil>
irb(main):006:0> User.create(name: 'name')
TRANSACTION (0.2ms) BEGIN
User Create (0.5ms) INSERT INTO "users" ("id", "name", "created_at", "updated_at") VALUES ($1, $2, $3, $4) RETURNING "id" [["id", "01EX95SNJ85JX57H8F43JEAGPG"], ["name", "name"], ["created_at", "2021-01-30 08:15:51.880899"], ["updated_at", "2021-01-30 08:15:51.880899"]]
TRANSACTION (3.6ms) COMMIT
=> #<User id: "01EX95SNJ85JX57H8F43JEAGPG", name: "name", created_at: "2021-01-30 08:15:51.880899000 +0000", updated_at: "2021-01-30 08:15:51.880899000 +0000">
テスト
spec/models/user_spec.rb
require 'rails_helper'
RSpec.describe User, type: :model do
it_behaves_like 'Identifiable'
end
spec/support/models/identifiable.rb
RSpec.shared_examples 'Identifiable' do
describe '#primary_key' do
context 'primary_keyカラムが`id`の場合' do
subject { described_class.new.id }
it { is_expected.to match(/[0-9A-Z]{26}/) }
end
end
end
参考
https://github.com/rails/rails/blob/5f3ff60084ab5d5921ca3499814e4697f8350ee7/activerecord/lib/active_record/attribute_methods/primary_key.rb#L89
https://api.rubyonrails.org/classes/ActiveRecord/Attributes/ClassMethods.html
https://github.com/shin1rok/ulid-rails-sample