【Rails初心者向け】ブランチを切り替える前に気を付けたいDBマイグレーションの注意事項

## はじめに
Railsはとても便利なwebアプリケーションフレームワークです。
gitも非常に便利なソースコード管理ツールです。
この2つのツールがあれば、初心者でも効率良くwebアプリケーションを開発できます。

ただし、学習用の小さなアプリケーションを一人で開発しているときはブランチはひとつかふたつで十分ですが、業務などで大きなアプリケーションを複数人で開発する場合は、複数のブランチで並行して開発が進める必要が出てきます。

こういうケースではデータベースマイグレーションを正しく理解し、正しく扱わないと、開発環境やソースコードが混沌としてきます。
Rails初心者の多くはこうした知識を持たないまま、チーム開発に参加しがちです。

この記事では「学習用の小さなRailsアプリケーション」を卒業し、「チームで開発する大きなRailsアプリケーション」に足を踏み入れる前に知っておくべき、データベースマイグレーションに関する知識を説明します。

## TL;DR（長すぎるので最初にまとめ）

ちょっと長いので先に要点をまとめておきます。

- gitでブランチを切り替えても、gitはデータベーススキーマの状態までは切り替えてくれない
- ゆえにブランチを切り替えたタイミングで、「そのブランチでは本来存在するべきではないテーブルやカラム」がデータベーススキーマに残った状態になることがある
- その状態で`rails db:migrate`を実行すると、「そのブランチでは本来存在するべきではないテーブルやカラム」がひょっこり`db/schema.rb`に顔を出す
- `db/schema.rb` がdiffに含まれているときは、コミットする前にソースコードと`db/schema.rb`がきれいに同期しているか入念にチェックすべき
- コードとDBの不整合を避けるという意味で、自分がメインで開発しているブランチ以外では、なるべく`rails db:migrate`を実行しない方よい

上のまとめを読んで「いったい何を言ってるの？」と思った人は、このあとの説明をじっくり読んでみてください。

## 【重要】大前提として知っておくべきこと

Railsアプリケーションを開発するときは大半の人がgitを使ってコードの変更を管理すると思います。
gitにはブランチという機能があり、ブランチを切り替えるとコードの内容をがらっと切り替えることができます。

たとえば、あなたが「ユーザー情報として電話番号を登録できるようにする」というタスクに取り組んでいたとします。このときに作業していたブランチの名前を"add-phone-number"としましょう。

もし開発の途中で

```
git checkout main
```

を実行してmainブランチに切り替えれば、あなたが"add-phone-number"ブランチで変更したコードはきれいさっぱりなくなって、mainブランチのソースコードに切り替わります。

しかし、ここで重要なことを意識しなければなりません。それは、 **データベーススキーマ（データベース内のテーブルやカラムの定義）はブランチを切り替えてもまったく変わらない** 、ということです。

もしあなたが"add-phone-number"ブランチで`users`テーブルに`phone_number`というカラムを追加していたら、mainブランチに切り替えてもDB上には`phone_number`が残ったままになっています。

つまりこれは、`db/schema.rb`の内容と開発環境で使っているDBのデータベーススキーマが不整合を起こしていることを意味しています。

`db/schema.rb`の内容を確認するとこんなふうに`users`テーブルには`phone_number`カラムは追加されていません。

```ruby:db/schema.rb
# mainブランチのdb/schema.rbにはphone_numberカラムは存在しない
create_table "users", force: :cascade do |t|
  t.string "email"
  t.string "name"
  t.datetime "created_at", null: false
  t.datetime "updated_at", null: false
end
```

### rails db:migrateのもうひとつの仕事
ところで、Railsを使っている人ならマイグレーションを実行するのに`rails db:migrate`コマンドを実行することをご存じだと思います。

`rails db:migrate`コマンドを実行すると、新しく追加されたマイグレーションファイルの記述内容に従ってデータベースに変更が適用されます。

しかし、`rails db:migrate`の仕事はそれだけではありません。 **`rails db:migrate`を実行すると、コマンドを実行した直後のデータベーススキーマの状態を`db/schema.rb`に反映するのです。**

ここで先ほどの例に戻りましょう。mainブランチで`rails db:migrate`を実行すると何が起きるでしょうか？やってみましょう。

```
$ rails db:migrate
$
```

はい、何も起きませんね。mainブランチでは新しく作られたマイグレーションファイルはないので、新しくテーブルが追加されたりカラムが追加されたりすることはありません。

しかし、`git diff`コマンドを実行すると・・・？

```diff
diff --git a/db/schema.rb b/db/schema.rb
index 68ca253..a24c761 100644
--- a/db/schema.rb
+++ b/db/schema.rb
@@ -10,12 +10,13 @@
 #
 # It's strongly recommended that you check this file into your version control system.
 
-ActiveRecord::Schema[7.0].define(version: 2023_11_05_053248) do
+ActiveRecord::Schema[7.0].define(version: 2023_11_05_053414) do
   create_table "users", force: :cascade do |t|
     t.string "email"
     t.string "name"
     t.datetime "created_at", null: false
     t.datetime "updated_at", null: false
+    t.string "phone_number"
   end
 
 end
```

なぜか`db/schema.rb`が更新されています。
`t.string "phone_number"`は"add-phone-number"ブランチで追加したカラムです。
しかし、これはまだ開発中の機能で使うカラムなので、mainブランチとは無関係です。
もちろん、`phone_number`カラムを追加するマイグレーションファイルもmainブランチには存在しません。

これは先ほど説明した「データベーススキーマの状態を`db/schema.rb`に反映する」という`rails db:migrate`コマンドの副作用です。

つまり、ここではまだmainブランチでは登場すべきではないカラムが一足先に`db/schema.rb`に登場したことになり、これはこれでmainブランチのソースコードと矛盾を引き起こしています。

### db/schema.rbは常にソースコードときれいに同期させるべし
このままぼーっとして`git commit`＆`git push`してしまうと、他の開発メンバーが「この`users`テーブルにある`phone_number`カラムって何なん？」と首をかしげることになります。

ここで取るべき行動はmainブランチのコードとしてあるべき姿に`db/schema.rb`を戻すことです。
具体的にはmainブランチはまだ`phone_number`カラムは登場させるべきではないので、`db/schema.rb`は元の状態に戻しておきましょう。

```shell 
# 予期せずdb/schema.rbに適用されてしまった変更点をロールバックする
$ git checkout db/schema.rb
```

これで`db/schema.rb`から`phone_number`カラムがなくなりました。

```ruby:db/schema.rb
ActiveRecord::Schema[7.0].define(version: 2023_11_05_053248) do
  create_table "users", force: :cascade do |t|
    t.string "email"
    t.string "name"
    t.datetime "created_at", null: false
    t.datetime "updated_at", null: false
  end

end
```

## ここまでの説明でわかること

ここまで以下のような内容を説明しました。

- gitでブランチを切り替えても、gitはデータベーススキーマの状態までは切り替えてくれない
- ゆえにブランチを切り替えたタイミングで、「そのブランチでは本来存在するべきではないテーブルやカラム」がデータベーススキーマに残った状態になることがある
- その状態で`rails db:migrate`を実行すると、「そのブランチでは本来存在するべきではないテーブルやカラム」がひょっこり`db/schema.rb`に顔を出す

このように`rails db:migrate`をすると、状況によっては「そのブランチでは本来あるべきではない状態」を`db/schema.rb`に反映する可能性があります。
よって、`db/schema.rb`がdiffに含まれているときは「本当にこのままコミットしていいか？別ブランチで追加したテーブルやカラムが含まれていないか？」という点をじっくり確認する必要があります。

## ソースコードとデータベーススキーマに矛盾が発生したときに取るべき戦略

上で説明した例のように、扱うブランチがmainブランチとフィーチャブランチ（たとえば"add-phone-number"ブランチ）の2つだけ、というときはまだマシです。
ローカル環境にフィーチャブランチが複数存在し、それぞれを切り替える必要があるときはかなりややこしいことになります。

なぜなら、ブランチAとブランチBのそれぞれでマイグレーションを実行したりすると、

「ブランチBで追加した不要なテーブルやカラムを抱えたブランチA」

や

「ブランチAで追加した不要なテーブルやカラムを抱えたブランチB」

という状況を生み出してしまうからです。

こういう状況になったときに取るべき戦略をいくつか説明します。

### 戦略1: ブランチを切り替えるタイミングで変更をロールバックする

一つ目は「ブランチを切り替えるタイミングで、データベースに加えた変更をロールバックする」という戦略です。
つまり、`rails db:rollback`を実行してデータベーススキーマを「その機能の開発に着手する直前」に戻してあげる、という方法です。こうすれば、ブランチBからブランチAに切り替えても「ブランチBで追加した不要なテーブルやカラムを抱えたブランチA」ではなく、「きれいなブランチA」になります。

ただし、ブランチBで`rails db:rollback`を実行すると、`db/schema.rb`からもテーブルやカラムの情報が消えてdiffが発生します。diffを抱えたままブランチを切り替えるわけにはいかないので`git checkout db/schema.rb`で`db/schema.rb`の変更はロールバックしてからブランチを切り替える必要があります。

また、ブランチAからブランチBに戻ってきたタイミングで再度`rails db:migrate`を実行してデータベーススキーマをブランチB向けに戻す必要もあります。

もちろん、ブランチAに切り替えるタイミングで`rails db:rollback`を実行するということは、ブランチBの開発中に作成したデータも失われる、ということです。

この戦略はソースコードとデータベーススキーマに矛盾を発生させないという点では理想的ですが、実際には手間やデメリットが大きいので、筆者は滅多に採用しません。

### 戦略2: ブランチごとにデータベースを別々に用意する

二つ目は「ブランチごとにデータベースを別々に用意する」という戦略です。

たとえば以下のようにデータベースをローカル環境に複数こしらえて、ブランチごとに切り替える、というイメージです。

```yaml:config/database.yml
development:
  adapter: postgresql
  encoding: unicode
  pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
  # ブランチAで開発するときはこっち
  database: awesome_app_development
  # ブランチBで開発するときはこっち
  # database: awesome_app_development_for_b
```

しかし、これはこれで運用や開発フローが複雑になりがちなので、筆者は滅多に採用しません。
この戦略を採用するのは、ブランチBでドラスティックなスキーマ変更が入る（大量にテーブルやカラムが追加されたり、既存のテーブルやカラムが大量に削除されたりする）ときぐらいです。

### 戦略3: rails db:resetでまるっとデータベースを作り直す
三つ目は「ブランチを切り替えるタイミングで`rails db:reset`でまるっとデータベースをゼロから作り直す」という戦略です。

つまり、ブランチBからブランチAに切り替えたらデータベースを再作成、ブランチBに戻ったらまたデータベースを再作成、というようにするわけです。

たしかにこうすれば「ブランチBで追加した不要なテーブルやカラムを抱えたブランチA」みたいな状況は回避できます。
しかし、データベースを再作成すると開発用のデータが全部失われてしまいます。
業務で開発しているRailsアプリケーションでは「秘伝のタレ」のようなテストデータがローカルDBに登録されていることが多いので、`rails db:reset`は恐ろしくて実行できません。

この戦略が有効なのは、テストデータが失われても痛くもかゆくもない「学習用に作成しているRailsアプリケーション」ぐらいじゃないかと思います。

### ⭐️ 戦略4: 何もしない（矛盾を許容し、気を付けながら開発する）→ これがベスト！？

四つ目は「特に何もしない」という戦略です。
つまり、「ブランチBで追加した不要なテーブルやカラムを抱えたブランチA」や「ブランチAで追加した不要なテーブルやカラムを抱えたブランチB」という状況を許容する、ということです。

新しいテーブルが追加されたり、新しいカラムが追加されたりした場合、多くの場合はブランチを切り替えてもRailsアプリの動作には影響を与えません（既存のテーブルやカラムが削除されたりした場合は話が別ですが）。

「今作業しているのはブランチAだが、データベースにはブランチBで追加したテーブルやカラムが含まれている」といったことを頭の片隅に置いておけば、何か問題が起きたときも落ち着いて対処できます。

実際、矛盾した状態で発生する問題の大半は予期しない`db/schema.rb`の更新ぐらいです。
なので、`db/schema.rb`に変なdiffが混入しないように気を付ける、というぐらいの対応でなんとかなったりします。

筆者が一番よく採用するのはこの戦略です。

### 番外：マイグレーションの実行をなるべく避ける
番外編として「マイグレーションの実行をなるべく避ける」という戦略も紹介しておきます。

たとえば、「自分がメインで開発しているのはブランチAだが、状況によってはたまにブランチBを参照しなければいけない」という場合、ブランチBでは「コードを眺めるだけで`rails db:migrate`は実行しない」とすれば、「ブランチBで追加した不要なテーブルやカラム」がブランチAにやってくることはありません。

もちろん、チーム開発であれば、マイグレーションが発生するような複数の開発タスクを並行して進めないように開発スケジュールや担当者アサインを調整してもらう、ということも大事です。

とにかく、 **「むやみやたらに`rails db:migrate`を実行すると、まだ取り込むべきでないデータベースの変更が取り込まれてしまい、ブランチを切り替えてもその変更が残ったままになってしまう」という意識を持つことが大事** です。

マイグレーションを実行する前は「本当にやる？本当に大丈夫？」と自問自答するぐらいの慎重さを持ってもいいと思います。

## rails db:migrate:status の情報を読む
さて、ここまで「ブランチを切り替えてもデータベーススキーマは切り替わらないんだよ」「状況によってはソースコードとデータベーススキーマは矛盾した状態になることがあるんだよ」という話を書いてきました。

では、矛盾が起きているかいないかを客観的に判断するにはどうしたらよいでしょうか？
そんなときに便利なのが`rails db:migrate:status`コマンドです。

以下は`rails db:migrate:status`の実行例です。

```
$ rails db:migrate:status

database: db/development.sqlite3

 Status   Migration ID    Migration Name
--------------------------------------------------
   up     20231105053248  Create users
   up     20231105053414  ********** NO FILE **********
  down    20231105073625  Add address to users
```

`rails db:migrate:status`の実行結果は、以下のような点に着目するとよいです。

**Statusがupで、Migration Nameに名前が表示されている行** （1行目のようなケース）
- マイグレーションが実行され、そのマイグレーションに対応するマイグレーションファイルも存在する状態
- こういう行は矛盾を引き起こしていないので気にしなくてOK

**Statusがdownの行** （3行目のようなケース）
- まだ実行されていないマイグレーションファイルの存在を意味する
- マイグレーションファイルを新規作成した直後や、git pullして新しいマイグレーションファイルがダウンロードされてきた状態
- `rails db:migrate`を実行するとupに変わるはず
- が、本当に`rails db:migrate`を実行すべきかどうかは熟慮すべし（前述の「番外：マイグレーションの実行をなるべく避ける」を参照）

**Statusがupで、Migration Nameが"NO FILE"の行** （2行目のようなケース）

- 何らかのマイグレーションは実行されているが、そのマイグレーションに対応するマイグレーションファイルが見つからない状態
- おそらく別のブランチで追加＆実行されたマイグレーションファイルがある
- この行があるときはちょっと注意が必要

### 「upかつNO FILE」の行がある場合は要注意

最後に挙げた「upかつNO FILE」の行がある場合は、なぜこんな状態になっているのかを確認した方が良いです。
多くの場合、これは別のブランチで追加＆実行されたマイグレーションがあることを意味しています。

たとえば、上の例だとmainブランチから"add-phone-number"ブランチに切り替えて`db/migrate`ディレクトリを確認すると、`20231105053414_add_phone_number_to_users.rb`というファイルがあるので、このマイグレーションファイルの変更内容がデータベースに適用されたことがわかります（Migration IDの`20231105053414`が一致している）。

```ruby:db/migrate/20231105053414_add_phone_number_to_users.rb
# "add-phone-number"ブランチには、このファイルが存在する
# （mainブランチにはない）
class AddPhoneNumberToUsers < ActiveRecord::Migration[7.0]
  def change
    add_column :users, :phone_number, :string
  end
end
```

もちろん、"add-phone-number"ブランチで`rails db:migrate:status`コマンドを実行すると、"NO FILE"にはなりません。

```
$ rails db:migrate:status

database: db/development.sqlite3

 Status   Migration ID    Migration Name
--------------------------------------------------
   up     20231105053248  Create users
   up     20231105053414  Add phone number to users
```

### 「すべてupかつ、"NO FILE"が1件もない状態」が理想形

理想的な`rails db:migrate:status`の実行結果は、すべてupかつ、"NO FILE"が1件もない状態です。
こうなっていればソースコードとデータベーススキーマはきれいに同期されている可能性が高いです。

逆に"NO FILE"が含まれていると、ソースコードとデータベーススキーマが矛盾している恐れがあります。

「これはたぶんあのブランチで追加したマイグレーションファイルだな」と、"NO FILE"の原因が予想できる場合はまだよいですが、「なんでこんなにも大量に身に覚えのない"NO FILE"があるんだ？」と首をかしげてしまう場合は、ちょっと時間をかけて原因を調査した方が良いかもしれません。

## それでもなぜか db/schema.rb にdiffが発生することもある

上で述べたように、`rails db:migrate:status`の実行結果がすべてupかつ、"NO FILE"が1件もない状態になっていれば、ソースコードとデータベーススキーマはきれいに同期されているはずです。

しかし、そうであるにも関わらず、`rails db:migrate`を実行するとなぜか `db/schema.rb` にdiffが発生してしまうケースがあります。

### integerがbigintに変わってしまう

元々integer型だったのに、`rails db:migrate`を実行するとなぜか`bigint`に変わってしまうことがあります（SQLite3でよく起きる？）。

```diff_ruby 
-    t.integer "user_id", null: false
+    t.bigint "user_id", null: false
```

この件についてはその昔、いろいろ調査してissueを報告したことがあります。
issue自体は修正されてクローズしたはずなんですが、今でもときどき発生していて、原因はよくわかりません。
が、SQLite3ではintegerでもbigintでも扱いは同じなので、そこまで深刻な問題ではありません。

https://github.com/rails/rails/issues/43168

### 列の順番が変わってしまう

gitで管理している`db/schema.rb`の列の順番と、ローカルのデータベースの列の順番が異なっていると、`rails db:migrate`を実行するたびに毎回列の順番が入れ替わるdiffが発生します。

```diff_ruby 
   create_table "users", force: :cascade do |t|
-    t.string "email"
     t.string "name"
+    t.string "email"
     t.datetime "created_at", null: false
     t.datetime "updated_at", null: false
   end
```

上の例では、gitで管理している`db/schema.rb`では`email`→`name`の順番でカラムが定義されているのに、ローカルのデータベースでは`name`→`email`の順番で定義されているためにdiffが発生しています。

おそらく、複数のメンバーが並行して開発しているときに、ある人は`email`→`name`の順にカラムを追加（＝マイグレーションを実行）し、自分は`name`→`email`の順でカラムを追加してしまって、他の人とカラムの定義順がズレてしまったんだと思います。

MySQLではALTER TABLE文でカラムの定義順を変更できるようですが、PostgreSQLにはそうした機能はないため、列の並び順を変えるのはかなり面倒です。

https://wiki.postgresql.org/wiki/Alter_column_position/ja

PostgreSQLを使っている場合は上のページで説明されている手順に従ってがんばって並び順を変えるか、diffの発生を諦めるかのどちらかになると思います。

### こういうdiffが発生したら毎回ロールバックする
上で挙げた2つのdiffは、アプリケーションの動作にはほぼ影響与えないので無視しても構いません。
ただ、発生したdiffをうっかりコミットしてしまうと不必要な変更をコードに加えてしまうことになるので、`rails db:migrate`を実行して勝手に混入してきた`db/schema.rb`のdiffはロールバックするのがよいと思います。

歴史の長いRailsアプリケーションや複数人で開発しているRailsアプリケーションでは、このほかにも`rails db:migrate`を実行するだけで勝手に混入する`db/schema.rb`のdiffがあるかもしれません。
そういったdiffの対処法はケースバイケースで異なってくるため、チーム内で対処方法を検討するようにしてください。

## コードと矛盾したdb/schema.rbをきれいに直す方法

何らかの理由でそのブランチのコードと`db/schema.rb`が矛盾してしまった場合は、以下のコマンドで修正することができます。

```shell  
# [注意] RAILS_ENV=testを必ず付けること！！
$ RAILS_ENV=test rails db:migrate:reset
```

このコマンドを実行すると、テスト環境のDBをdrop/createし、マイグレーションを最初から最後まで実行し直します。
そして、`db/schema.rb`にその結果（テスト環境のデータベーススキーマ）を反映します。

これにより、「そのブランチに存在するマイグレーションファイルと完全に同期した `db/schema.rb` ができあがる」というわけです。

注意点は **必ず `RAILS_ENV=test`を付ける** 、ということです。
これを付けないとdevelopment環境のDBをdrop/createすることになり、開発用に使ってきたローカル環境のデータがすべてぶっ飛んでしまうことになります。

また、この操作ではあくまで `db/schema.rb`（と、test環境のデータベーススキーマ）がソースコードと同期するだけです。development環境のデータベーススキーマはソースコードと矛盾したままになっているかもしれない点に注意してください。

（謝辞：このテクニックは弊社ソニックガーデンの @pi_chan に教えてもらいました🙏）

## 途中からプロジェクトに参加した人はrails db:schema:loadを使う

ところで、この記事で何度も登場している`db/schema.rb`はそもそも何のファイルなんでしょうか？データベーススキーマの状態をコード上で確認するためだけに存在しているのでしょうか？

実は、`db/schema.rb`はデータベーススキーマをゼロから構築する際に実行する`rails db:schema:load`コマンドで利用されます。

データベーススキーマをゼロから構築する際は以下の2つの方法があります。

- `rails db:migrate` 
  - `db/migrate`ディレクトリにあるマイグレーションファイルを順番に実行する
- `rails db:schema:load` 
  - `db/schema.rb`のスキーマ情報をそのままデータベースに反映する（`db/migrate`のマイグレーションファイルは使わない）

きれいに作られてきているRailsアプリケーションではどちらでも同じ結果になるはずですが、そうではない場合、お行儀の悪いマイグレーションファイルが含まれていると、`rails db:migrate`を実行したときにエラーが発生して、マイグレーションが途中で止まってしまうことがあります。

`rails db:schema:load` ではマイグレーションファイルを実行しないので、大半の場合、エラーなくデータベーススキーマを構築することができます。

Railsガイドでも新規にデータベースを構築する際は`rails db:schema:load`を使うことを推奨しています。

> アプリケーションのデータベースの新しいインスタンスを作成する場合、マイグレーションの全履歴を最初から繰り返すよりも、単に`rails db:schema:load`でスキーマファイルを読み込む方が、高速かつエラーが起きにくい傾向があります。
>
> https://railsguides.jp/active_record_migrations.html#%E3%82%B9%E3%82%AD%E3%83%BC%E3%83%9E%E3%83%95%E3%82%A1%E3%82%A4%E3%83%AB%E3%81%AE%E6%84%8F%E5%91%B3%E3%81%AB%E3%81%A4%E3%81%84%E3%81%A6

ですので、途中からRailsプロジェクトに参加してきたメンバーがいたら、`rails db:migrate`ではなく、`rails db:schema:load`を実行するように伝えてあげてください。

```shell 
$ rails db:create
# db:migrateだとエラーが起きるかもしれないので、db:schema:loadを実行
$ rails db:schema:load
```

もちろん、その場合は`db/schema.rb`にソースコードと矛盾したおかしな定義情報が含まれていないことが大前提です。

## その他、知っておくと良いこと

### GitHubにpushしたマイグレーションファイルを安易に修正しない

マイグレーションファイルに記述ミスがあったからといって、安易にそのファイルを修正してしまうと、他の開発メンバーが迷惑するケースがあります。
詳しくは以下の記事を参照してください。

https://qiita.com/jnchito/items/3525fd22973477b88411

### コンフリクトしたschema.rbをきれいにマージする手順

複数メンバーが並行して開発していると、schema.rbがコンフリクトすることもよくあります。
その場合の対応手順を以下の記事にまとめています。

https://qiita.com/jnchito/items/494a0499b808f109e0a8

### マイグレーション作成時のチェックポイント

筆者が書いた記事ではありませんが、マイグレーション作成時に気を付けた方がいいポイントがきれいにまとめられています。
コメント欄で筆者もコメントしているので、その内容も参考にしてみてください。

https://qiita.com/nay3/items/ef773006cd7f815a07cd

### 既存のテーブルやカラムの削除は後戻りできないので慎重に

当たり前ですが、 `drop_table` や `remove_column` で既存のテーブルをカラムを削除すると、そこに保存されていたデータはもう戻ってきません（バックアップがあればリストアできるが、実際はやるのはかなり面倒）。

なので、まずはソースコード上で削除したいテーブルやカラムにアクセスしないように変更して、しばらく何もエラーが起きなければ本当に削除する、という手順を踏んだ方が良いです。

なお、カラムを削除する場合は`ignore_columns`メソッドを使うと、指定したカラムを論理削除できます。物理削除する前にまず論理削除して、何も問題が起きないことを確認しましょう。

```ruby 
class Post < ApplicationRecord
  # titleカラムを論理削除する
  self.ignored_columns = [:title]
end
```

https://zenn.dev/yosipy/articles/3074a255be2c5e

### 「やばい！」と思ったら先輩プログラマを頼る

ここまで説明してきたように、gitできれいに管理できず、簡単にソースコードと不整合を起こしてしまうデータベーススキーマの扱いはかなり厄介です。

「やばい！なんかやらかしてしまった気がする……」とか「いろいろ触ってるうちに今自分が何をやってるのかわからなくなった😭」といった状況に陥ったら、すぐにメンターや先輩プログラマに助けを求めましょう。

自力でなんとかしようとすると泥沼にはまって余計に状況を悪化させるかもしれませんよ！

## まとめ
というわけで、この記事ではRailsのデータベースマイグレーションで気を付けるべき注意事項をあれこれ書いてみました。
具体的には以下のような内容を説明しました。

- gitでブランチを切り替えても、gitはデータベーススキーマの状態までは切り替えてくれない
- ゆえにブランチを切り替えたタイミングで、「そのブランチでは本来存在するべきではないテーブルやカラム」がデータベーススキーマに残った状態になることがある
- その状態で`rails db:migrate`を実行すると、「そのブランチでは本来存在するべきではないテーブルやカラム」がひょっこり`db/schema.rb`に顔を出す
- `db/schema.rb` がdiffに含まれているときは、コミットする前にソースコードと`db/schema.rb`がきれいに同期しているか入念にチェックすべき
- コードとDBの不整合を避けるという意味で、自分がメインで開発しているブランチ以外では、なるべく`rails db:migrate`を実行しない方よい

こうした知識は一人でRailsの勉強をしているときはほとんど気付けないので、これからチーム開発に入ろうとしている人や、チーム開発に入って間もない人はぜひ理解しておいてください。