日々Derailment

技術的なことの備忘録。脱線事故が起きまくってるので、なるべくrails wayを守れるよう頑張ります。

change_columnでuuidカラムに変更する

無知だったので、開発当初はuuidを知らずに、stringカラムにモデル側でbefore_createでなんちゃってユニークなIDを生成していた。
その時はなんとまぁ

create_table :hoges, id: false do |t|
  t.string :id, null: false
end

とかやってたもんですから、primary_keyをデータベースで設定せず、モデル(ActiveRecord)でprimary_key = 'id'とか、いま見返すとなかなかすごいことをしていた。
で、いまこのあたりのテコ入れをせざるを得なくなったわけです。

テーブルのid自体の変更は
1.現状のidカラムの退避先をtemporaly_idとか適当に作る 2.remove_columnでidを消す 3.add_columnでuuidにするのとprimary_keyの振り直し 4.変更したテーブルを参照しているテーブルがある場合はtemporaly_idを元にselect & 変更後のuuidにアップデート

ってな感じでやったんですが、ちょっとハマったのが変更をかけたテーブルを参照しているカラムがある場合、こんなエラーが出る。

PG::UndefinedFunction: ERROR:  operator does not exist: character varying = uuid

型が違うよ!ってことを言ってるわけですね。 string型からuuid型になっているので、参照しているカラムと型が一致しないわけなので、referenceのカラムにも変更をかける必要があります。

で、そのときに

  change_column :hoges, :fuga_id, :uuid, foreign_key: true

安直にこれでいきました。

が、失敗します。

ERROR:  column "fuga_id" cannot be cast automatically to type uuid
HINT:  You might need to specify "USING fuga_id::uuid"

こんな感じでヒントくれます。

  change_column :hoges, :fuga_id, "USING fuga_id::uuid", foreign_key: true

が、失敗します。
syntax errorで怒られます。

最終的にこうしました。

  change_column :hoges, :fuga_id, 'uuid USING CAST(fuga_id AS uuid)', foreign_key: true, index: true

無事、解決。

データベースの寿命はアプリケーションよりも長い

データベースといえばこの方。

twitter.com

「失敗から学ぶRDBの正しい歩き方」
めちゃくちゃ読んでます。
アンチパターンだらけで逆に笑えてきます。

「一番最初にお伝えすべきことは、データベースの寿命はアプリケーションよりも長いということです。」

はい、おっしゃる通りです。 rails触る前にもっとデータベースの設計とか、ちゃんとやっておくべきでした、、、。 DBはほんとに負債がたまりやすい。
しかも変に作っても動いてしまうものだし、時限爆弾のごとくある日突然、未来の自分にダメージを与えるんですよねー。
まぁ設計力あげるためにも失敗は避けて通れないのかなと前向きに行きましょう。