今回は実際のシステム開発の現場でuuidを使ったのでこれについてまとめました。
uuidとは?
uuid(Universally Unique Identifier)は、128ビットの一意の識別子として用いられます。
わかりやすくいうと、uuidは8-4-4-4-12の形式で表される32文字の16進数と4つのハイフンから構成されるため、1兆個のuuidを生成しても重複する確率は低いです。
そのため、大規模なシステムや分散システムでも、重複しない識別子として利用できます。主にデータベースやネットワーク上で一意の識別子として使用されます。
またuuidは16バイトのバイナリ形式で保存するため、文字列形式の36バイトに比べて大幅にストレージを節約できます。合わせてインデックスが小さくなり、検索が高速化されます。
uuidの設定
・ステップ1
まず、userモデルを作成し、「t.binary :uuid, limit: 16」というカラムを設定し、「add_index :users, :uuid, unique: true」という設定を加えます。
class CreateUsers < ActiveRecord::Migration[6.0]
def change
create_table :users do |t|
t.binary "uuid", limit: 16, null: false # 16バイトのバイナリ形式でUUIDを保存
t.string :name
t.string :email
t.timestamps
end
add_index :users, :uuid, unique: true
end
end
その後、rails db:migrateを行います。
ここでuuidをバイナリ形式で保存することで、インデックスのサイズが小さくなり、検索処理が高速になります。
インデックスのサイズが小さくなると、データベースがインデックスをメモリに保持できる可能性が高くなり、結果として検索クエリのパフォーマンスが向上します。また、バイナリ形式の比較は文字列形式よりも効率的に行えるため、検索処理自体も軽くなります。
・ステップ2
dbにデータを登録する際に、uuidを作成するモジュールとして設定をします。
module UuidGeneratable
extend ActiveSupport::Concern
included do
before_create :generate_unique_uuid
def generate_unique_uuid
loop do
self.uuid = self.class.binary_uuid( SecureRandom.uuid )
break unless self.class.exists?( uuid: self.uuid )
end
end
def self.binary_uuid( uuid_string )
[uuid_string.delete( '-' )].pack( 'H*' )
end
def uuid_string
self.class.string_uuid( uuid )
end
def self.string_uuid( binary_uuid )
binary_uuid.unpack1( 'H*' ).scan( /.{8}|.{4}|.{4}|.{4}|.{12}/ ).join( '-' )
end
def self.find_by_uuid( uuid )
params_uuid = [uuid.delete('-')].pack('H*')
self.find_by( uuid: params_uuid )
end
end
end
※「loop do」の処理はなくてもいいかもしれません。
・ステップ3
modelファイルにモジュールをincludeする
class User < ApplicationRecord
include UuidGeneratable
end
ルーティングでUUIDをIDとして使用する手順
先ほどの処理でuuidは登録できるようになりました。
今度はuuidをurlに含めて使用できるように設定をします。
・ステップ1
ルーティングを修正
namespace :clients do
root "dashboards#index"
resources :companies, only: %i[ show ], param: :uuid # ここにURLでuuidをidにするよう設定
end
・ステップ2
viewファイルにあるパスでidを渡していたところにuuidを設定
またここではdbから取得したインスタンスのuuidを直接使用するはできません。
理由としては、データベースから取得したUUIDデータはバイナリ形式で保存されており、そのままでは使用できません。そこで、uuid_string メソッドを使用してバイナリデータを文字列形式に変換し、読みやすい形で利用できるようにします。
そのためパスに渡す引数でメソッドを設定することでバイナリデータを文字列形式に変換します。
= link_to clients_company_path( @company.uuid_string )
これにより適切にルーティングでuuidをidとして使用できるようになります。