初心者目線のmigrationまとめ(1)【migration消しちゃった?!】

初心者の俺　「migrationを……」

# 消したいけど、どうしたらいいんよ?!

## migrationのここが大切
- migrationとは、直接SQLを使わずにデータベースのテーブルやカラムなどの構造(スキーマ)を変更できる仕組み
- migrationファイルを新しく作ったら、```rails db:migrate```しないと```ActiveRecord::PendingMigrationError```エラーになる
- migrationファイルは更新履歴みたいなもの。**好き勝手に消したり付け加えてはいけない。いいか、好き勝手に消したり付け加えてはいけないぞ！そこの俺、聞いてるか？！**


## じゃあどうやって修正するの？
方法は２つ。
#### 1.migrationファイルを新たに作成し、上書きする（推奨)
#### 2.migrationの適用を戻すコマンドを使い、修正する

１と2を説明する前に……
# そもそも、migrationファイルでDBを更新する流れをおさらい
知ってる人は次の項目へスキップ:runner_tone3:

①最初、DBの構造(スキーマ)は空の状態
②マイグレーションファイルを作成して、DBの変更内容を書く。
③```rails db:migrate```を実行するとDBに指定したスキーマが生成される。
このとき、バージョン管理用のテーブルも自動生成され、その中でどのマイグレーションファイルまでを実行したかが記録される。
④新しいマイグレーションを実行する毎にバージョンが追加されていく。

**マイグレーションファイルでDBの設計図を書いて、```rails db:migrate```で実際にDBを操作するイメージ。**

ちょっと違うかもだけど、Amazonでカートに物入れた状態がマイグレーションファイル書いた状態で、実際購入ボタン押すのが```rails db:migrate```。購入履歴を操作しようとしてもできなくて、一回キャンセルしたり、もう一度改めて注文しないと変更できないあの感じに似ている。(絶対に違う)

では、本題に戻る。

## 1.migrationファイルを新たに作成し、上書きする（推奨)

#### 推奨理由
複数人で開発した時に、好き勝手DBをいじれてしまうと混乱するため。migrationファイルが一度```rails db:migrate```したら基本的に変更を受け付けないのも、時系列で変更を管理することで、DBの変更に矛盾が起きないようにしている仕組みだから。

### 実際の修正方法
下記のusersテーブルにageカラムを追加してみる。
|users |
|:-:   |
|id : integer   |
|name : string  |
|email : text |

①まずはmigrationファイルを新規作成
```#rails generate migration ファイル名 [カラム名:型[:index]]```
```
rails generate migration AddAgeToUser age:integer
```
migrationファイルは更新履歴の代わりになるものなので、**何の変更を加えたか分かりやすい名前をつけます。**

上記コマンドを打った結果作成されたmigrationファイル↓
```db/migrate/20230420103137_add_age_to_user.rb
class AddAgeToUser < ActiveRecord::Migration[7.0]
  def change
    add_column :users, :age, :integer
  end
end
```
ここで、schema.rbとmigrationファイルの状態がどうなっているか見てみます。
```db/schema.rb
ActiveRecord::Schema[7.0].define(version: 2023_04_20_103042) do
  create_table "users", force: :cascade do |t|
    t.string "name"
    t.text "email"
    t.datetime "created_at", null: false
    t.datetime "updated_at", null: false
  end
end
```

```
$ rails db:migrate:status

Status   Migration ID    Migration Name
--------------------------------------------------
   up     20230420103042  Create users
  down    20230420103137  Add age to user
```
まだmigrationファイルは適用されておらず(downの状態)、schema.rbにも反映されていないことが分かります。

サーバも見てみましょう。
![スクリーンショット 2023-04-20 19.45.53.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2817989/4a71aed5-37f0-8ad4-4b13-ebad6363c4b9.png)
エラーがでてます。

##### では、張り切っていってみましょう
```
rails db:migrate
```
このコマンドめっちゃ好き……

```diff_ruby
ActiveRecord::Schema[7.0].define(version: 2023_04_20_103137) do
  create_table "users", force: :cascade do |t|
    t.string "name"
    t.text "email"
    t.datetime "created_at", null: false
    t.datetime "updated_at", null: false
  + t.integer "age"
  end
end
```
```
$ rails db:migrate:status
 Status   Migration ID    Migration Name
--------------------------------------------------
   up     20230420103042  Create users
   up     20230420103137  Add age to user
```
upになっている状態のmigrationファイルに変更を加えて```rails db:migrate```コマンドを打っても変更されません。

では、これをdown状態に戻すのはどうしたらいいでしょうか？


## 2.migrationの適用を戻すコマンドを使い、修正する
個人開発や```rails db:migrate```を実行してすぐの変更であればこちらも便利

#### 直前の```rails db:migrate```を取り消す
```
rails db:rollback 
```
実行後の状態
```
$rails db:migrate:statu
Status   Migration ID    Migration Name
--------------------------------------------------
   up     20230420103042  Create users
  down    20230420103137  Add age to user
```

#### 指定のマイグレーションファイルまで戻す

分かりやすくするためにmigrationファイルを追加しました。
```
$ rails db:migrate:status

 Status   Migration ID    Migration Name
--------------------------------------------------
   up     20230420103042  Create users
   up     20230420103137  Add age to user
   up     20230420113934  Add password to user
   up     20230420114101  Add avatar to user
   up     20230420114254  Remove avatar to user
```

方法が３つあります
①```rails db:rollback```を繰り返し、１つずつ戻っていく
②```rails db:rollback STEP=n```
```
# 例：３つ前まで戻る
$ rails db:rollback STEP=3

Status   Migration ID    Migration Name
--------------------------------------------------
   up     20230420103042  Create users
   up     20230420103137  Add age to user
  down    20230420113934  Add password to user
  down    20230420114101  Add avatar to user
  down    20230420114254  Remove avatar to user

```
③戻るマイグレーションファイルのバージョンを指定する
```rails db:migrate:down VERSION= Migration ID```
```
# Add age to userのファイルを戻す
$ rails db:migrate:down VERSION= 20230420103137

Status   Migration ID    Migration Name
--------------------------------------------------
   up     20230420103042  Create users
  down    20230420103137  Add age to user
   up     20230420113934  Add password to user
   up     20230420114101  Add avatar to user
   up     20230420114254  Remove avatar to user
```

俺へ
これやって整合性無くなってエラー吐きまくってわけわからないことになって結局DBリセットしたのでおすすめしないよ
俺より

## 🙋‍♂️「先生、upのmigrationファイル消しちゃいました」

何だと？！好き勝手に消したり付け加えてはいけないってdifっJ陽gJrg子；g自vdsm素fkgお＠!!!!!!!!

#### upのmigrationファイルを消すとどうなるか
→ *** NO FILE ***と表示される
```
Status   Migration ID    Migration Name
--------------------------------------------------
   up     20230420103042  Create users
   up     20230420103137  Add age to user
   up     20230420113934  Add password to user
   up     20230420114101  Add avatar to user
   up     20230420114254  ********** NO FILE **********
```
NO FILEと表示されるのはrails db:migrateした時にschema_migrationsテーブルにバージョンが保存されているためです。
![スクリーンショット 2023-04-20 21.22.49.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2817989/134c8909-40b6-fc98-4d03-bbd171231d01.png)
このレコードを削除すればNO FILEの表示は消えますが、基本的には削除するのは良くないぽい。削除したファイル自体を戻すなどして対応した方が良いと思います。

downしたファイルは消しても大丈夫です。
```
$ rails db:rollback
$ rails db:migrate:status

Status   Migration ID    Migration Name
--------------------------------------------------
   up     20230420103042  Create users
   up     20230420103137  Add age to user
   up     20230420113934  Add password to user
   up     20230420114101  Add avatar to user
```



### 参考にしたもの
https://railsguides.jp/active_record_migrations.html
https://qiita.com/s_tatsuki/items/3e1f119c91e21b8f0c33
https://pikawaka.com/rails/migration