🧗

Railsで既存テーブルを削除する手順(ロールバック、復元の考慮)

2024/01/25に公開

最近テーブル削除のマイグレーションを書く機会があって、怖かったので自分なりの手順を整理してました。

言いたいこと

  • テーブル削除に限らず、マイグレーションを書くときは原則としてロールバック可能な書き方をしよう
  • ロールバックで戻せるのはあくまでスキーマであって、レコードは消えるので注意

既存のテーブルを削除したい!どんな手順で進める?

丁寧に書くと以下の手順になると思います。

  1. 必要に応じて、削除対象のテーブルのレコードを控えておいたり、復元スクリプトを用意しておく
  2. bin/rails g migration XXXを実行
    • XXXはマイグレーションクラス名(Drop<削除したいテーブル名>とか)
    • 空のマイグレーションファイルが生成される
  3. マイグレーションファイル内に以下を記載
    class XXX < ActiveRecord::Migration[7.1]
      def change
        drop_table(:<削除したいテーブル名>) do |t|
        end
      end
    end
    
  4. db/schema.rb内の、削除したいテーブルの中身(カラムやインデックスの情報)をdrop_tableのブロック内にコピペする
    class XXXXX < ActiveRecord::Migration[7.1]
      def change
        drop_table(:<削除したいテーブル名>) do |t|
          t.string("name", null: false, comment: "名前") # カラムの情報をオプション含めてそのまま書いておくことでスキーマの復元が可能
          t.integer("xxx_id", null: false)
          ...
          t.datetime("created_at", precision: nil, null: false)
          t.datetime("updated_at", precision: nil, null: false)
          t.index(["yyy_id"], name: "index_xxx_on_yyy") # indexも書いておく
        end
      end
    end
    
  5. bin/rails db:migrateを実行して成功確認
    • 関連部分の動作が問題ないか確認(最終確認は後でやるのでざっとでいいかも)
  6. bin/rails db:rollbackを実行して成功確認
    • db/schema.rbがマイグレーション実行前の状態に戻っているか確認
    • 関連部分の動作が問題ないか確認
    • レコードの復元スクリプトがあるなら実行して動作確認
  7. 改めてbin/rails db:migrateを実行して成功確認
    • 最終的な動作確認をする
  8. コミットしてPR挙げる!
    • PRにロールバックまで確認したよとか、復元スクリプト書いとくとかするとレビュアーも安心してapproveできるかも

マイグレーション実装時に考慮すべきこと

DBのバックアップさえしていれば復元はできますが、アプリケーションコードの実装段階で以下を考慮しておくべきだと思います。

  • テーブルを消してから、実は消してはいけないものだったと気づいた場合にリカバリーできるか?
    • コードと違ってDBはコミットdropしてforce pushとかrevertコミットとかでは戻せない
    • せめてスキーマはコマンド一発で元に戻せるようにしたい(手元でロールバック確認する癖をつける)
  • スキーマを復元できたとしてもレコードは消える
    • テーブルの性質によっては、復元スクリプトや手順を控えておいた方がいいかも
    • 例えば都道府県マスタのような、レコード数が少なめで、基本変更されないテーブルなら、コマンドだけで戻しやすいと思う
  • DBのバックアップが取られていることは事前に確認すべき

マイグレーションは慎重にやっていきたいです🧗‍♀️
他にも留意事項とか効率いい方法とかあればぜひ教えてください!

参考

Discussion