Rails初心者が個人的にもっと早く聞きたかったシリーズ1 type: :uuid
シリーズとか書いているけどシリーズ化するかは分かりません。
最近、改修という名の過去の自分と戦う羽目になるケースが非常に多いです。
気分はコロッセオのディアボロです。
1年経って見返してもよく分かるんですが、非常に無駄が多いんですね。
(無駄に気付けるってことは、それだけ成長したといえば聞こえはいいですが。)
ただ、無駄はよくない。リソースが少ない状況なので尚更。
そんなわけで今になって思う、もっと早く聞きたかったことをまとめておく。
何億番煎じか分からないけど、今回はuuidについて。
uuidとは
知らない人のために簡単に書いておくと
重複しない一意なid
のことです。
細かい原理とかはここで省きます。
いつ使うのか
Railsではデフォルトのprimary_keyがintegerのオートインクリメンタルになっている。
で、だいたいrails_wayに素直に従っていれば
/users/:id
とかのルーティングになっているので
/users/1
とかになっているわけですね。
これは簡単に別のユーザーのIDが推測できてしまうなどなど、色々な問題があります。
そこでuuidの出番です。
環境
rails 5.2.3
ruby 2.5.3
postgresql 9.6.4
導入方法
1.マイグレーションファイルを作成する
(ファイル名は分かりやすければなんでも良い)
rails g migration enable_uuid_extention
# xxxxxxxxxxxxxxxxxx_enable_pgcrypto_extention.rb class EnablePgcryptoExtention < ActiveRecord::Migration[5.2] def change enable_extension 'pgcrypto' end end
rails db:migrate
3.モデルを作成する
rails g model Hoge name:string
class CreateHoges < ActiveRecord::Migration[5.2] def change create_table :hoges, id: :uuid do |t| # id: :uuidを追記する t.string :name t.timestamps end end end
rails db:migrate
5.レコードの作成
irb(main):001:0> Hoge.create(name: "sample") (0.2ms) BEGIN Hoge Create (29.8ms) INSERT INTO "hoges" ("name", "created_at", "updated_at") VALUES ($1, $2, $3) RETURNING "id" [["name", "sample"], ["created_at", "2019-07-06 04:42:08.809181"], ["updated_at", "2019-07-06 04:42:08.809181"]] (7.2ms) COMMIT => #<Hoge id: "ff67302a-8319-42e6-b94e-be7b0241cde1", name: "sample", created_at: "2019-07-06 04:42:08", updated_at: "2019-07-06 04:42:08">
関連付け
class HogeRelationships < ActiveRecord::Migration[5.2] def change create_table :hoge_relationships do |t| t.references :hoge, foreign_key: true, type: :uuid # type: :uuidを指定する t.references :fuga, foreign_key: { to_table: :hoges }, type: :uuid t.timestamps end end end
ちなみに今回の項目とは全く関係ないけど、
foreign_key: { to_table: :テーブル名 }
でカラム名とは別のテーブルを指定できます。
同じモデル同士の関連付けでカラム名を変えたい場合などに使いましょう。
まとめ
サービス開発ではuuidほぼマストかなと思いますが、自分で調べてみないとこれ分からないですよね。
デフォルトでuuidがあると知らなかった頃は
create_table :users, id:false do |t| t.string :id, null: false end
とか定義して、before_createでSecureRandomで作ったuuid値をセットするとかいう愚行をおかしてました。
(内輪向けのアプリでまだよかったけど)
パフォーマンスに関しても、通常のインクリメンタルと比べて低下は2割程度、というのを以前見かけました。
(ソースは探し直したけど見当たらず、、、。)
状況によると思いますが、それでidの重複を気にしなくて良くなるなら、全然OKなのかなという気がします。