【ザックリ概要】`Active Record マイグレーション`について

※一部ガイド内容を省略したりとザックリとしたまとめを意識しているので不十分な個所があるという点をご了承ください
（reference、外部キー関連、など省略）
＊都度更新していく予定です

***
参考＆引用サイト：[Active Record マイグレーション](https://railsguides.jp/active_record_migrations.html)
***
# マイグレーションの概要
＊"migration"（移行）⇒「DBのテーブル作成や変更」（「状態Aから状態Bへの"移行"」みたいな意味合いを持つ）
- ActiveRecordの機能の１つ
- DBスキーマ（テーブルの定義など）を長期にわたって安定して変更など加えられるようにする仕組み
- **生のSQLを用いる必要が無い**仕組みが大きな特徴と言える
***
- マイグレーションの度に"マイグレーションファイル"が作成される。このファイルごとを"バージョン"と見なしている
- `schema.rb`という「DBに管理してもらいたいテーブル定義書」の役割を持つファイルに対して変更内容が反映されていく
    - 直接`schema.rb`を触るのではなく、マイグレーションファイルに変更内容を記述して反映していく
        - これで変更のバージョン管理をしながらDBの最新状況の反映も行える
        - 
> マイグレーションの例を以下に示します。
> ```ruby
> class CreateProducts < ActiveRecord::Migration[7.1]
>   def change
>     create_table :products do |t|
>       t.string :name
>       t.text :description
> 
>       t.timestamps
>     end
>   end
> end
> ```

|コード箇所|説明|
|---|---|
|`create_table :products ~`|"products"という名前のテーブルを作成|
|`t.string :name`|String型の`name`カラム|
|`t.text :description`|text型の`description`カラム|
|`t.timestamps`|`created_at`、`updated_at`の2つのカラムを追加（自動で生成＆管理してくれる）|

:::note info
- SQLを書かなくてもDBへのテーブル作成＆カラム変更の命令を実装できる
- 基本、マイグレーションファイルを編集してDBへ変更内容を反映する
:::

## マイグレーションを生成する
### マイグレーションファイルについて
- `db/migrate`ディレクトリに保存
- 1つのマイグレーションファイルが1つのマイグレーションクラスに対応（1対1）
    - 先述のマイグレーション例の場合、マイグレーションクラス`CreateProducts`に対してマイグレーションファイル`YYYYMMDDHHMMSS_create_products.rb`が対応する
- マイグレーションファイル名は`YYYYMMDDHHMMSS_create_products.rb`（YYYYMMDDHHMMSS = "西暦 月 日 時 分 秒"）
    - YYYYMMDDHHMMSS をファイル名につけることで「実行順番が必ず最新の反映内容が採用されるようになる」「一意になる」「変更履歴がファイル名から分かる」というメリットがある

> ```ruby
> $ bin/rails generate migration AddPartNumberToProducts
> ```
> 上を実行すると、空のマイグレーションが適切な名前で作成されます。
> 
> ```ruby
> class AddPartNumberToProducts < ActiveRecord::Migration[7.1]
>   def change
>   end
> end
> ```

### 新しいカラムを追加・削除する
- マイグレーション時、コマンドに適切な引数を渡せば生成されるファイルに自動で中身に記述も加えてくれる

※"AddColumnToTable"、"RemoveColumnFromTable"をそのまま入力するのではなく以下のように書き換えるということ

|コマンド|マイグレーション内容|
|---|---|
|`Add(追加したいカラム名)To(追加先テーブル)`|カラムの追加|
|`Remove(削除したいカラム名)From(削除先テーブル)`|カラムの削除|
> マイグレーション名が"AddColumnToTable"や"RemoveColumnFromTable"で、かつその後ろにカラム名や型が続く形式になっていれば、適切なadd_column文やremove_column文を含むマイグレーションが作成されます。
> ```
> $ bin/rails generate migration AddPartNumberToProducts part_number:string
> ```
> 上を実行すると以下のマイグレーションファイルが生成されます。
> ```ruby
> class AddPartNumberToProducts < ActiveRecord::Migration[7.1]
>   def change
>     add_column :products, :part_number, :string
>   end
> end
> ```
⇒`add_column :products, :part_number, :string`の部分は自動で追加した上でファイル生成してくれる

:::note info
【構文】
`$ bin/rails generate migration Add(カラム名)To(テーブル名) (カラム名１):(データ型１) (カラム名２):(データ型２) ... (カラム名Ｎ):(データ型Ｎ)`
`$ bin/rails generate migration Remove(カラム名)From(テーブル名) (カラム名１):(データ型１) (カラム名２):(データ型２) ... (カラム名Ｎ):(データ型Ｎ)`
:::

※`AddColumnToTable`の`Column`に関しては任意の文字列でも問題ないという旨が確認される ← （未検証なので検証必要）
　（`AddColumnToTable`の`Table`および`RemoveColumnFromTable`は不可） ← （これも未検証なので検証必要）

### 新しいテーブルを作成する
- テーブルの作成は`Create(テーブル名)`で指定する（要領はカラムの時と同じ）

> `$ bin/rails generate migration CreateProducts name:string part_number:string`
> 上を実行すると以下のマイグレーションファイルが生成されます。
> ```ruby
> class CreateProducts < ActiveRecord::Migration[7.1]
>   def change
>     create_table :products do |t|
>       t.string :name
>       t.string :part_number
> 
>       t.timestamps
>     end
>   end
> end
> ```
:::note info
【構文】
`$ bin/rails generate migration Add(カラム名)To(テーブル名) (カラム名１):(データ型１) (カラム名２):(データ型２) ... (カラム名Ｎ):(データ型Ｎ)`
:::

### テーブル・カラムの変更
- 既存のテーブルおよびカラムに対して変更も可能
    - `ALTER TABLE...`と同等の作用

> ＃以下、ガイドより引用したテーブルの変更サンプル）
> ```ruby
> change_table :products do |t|
>   t.remove :description, :name
>   t.string :part_number
>   t.index :part_number
>   t.rename :upccode, :upc_code
> end
> ```

||詳細|
|---|---|
|t.remove :description, :name|`products`テーブルの`description`,`name`カラムを削除|
|t.string :part_number|`products`テーブルに`part_number`を追加|
|t.index :part_number|`products`テーブルの`part_number`にインデックスを追加|
|t.rename :upccode, :upc_code|`products`テーブルの`upccode`カラム名を`upc_code`に変更|

> ＃以下、ガイドより引用したカラムの変更サンプル
> ```ruby
> change_column :products, :part_number, :text
> ```

||詳細|
|---|---|
|change_column :products, :part_number, :text|`products`テーブルの`part_number`カラムのデータ型を`text`に変更|

## マイグレーションの実行＆ロールバック
- 基本`rails db:migrate`でマイグレーションファイルの内容に従って実行される
    - まだ実行されていない`def change`を実行する。（本記事では省略した`up`メソッドも対象）
    - 未実行のマイグレーションがない場合は何もせずに終了
        - `rails db:migrate`を何回実行しても実害はないという事なので、「あれ？このマイグレーションファイルって実行したっけ？」という状況になったら確認の意味でも実行してするのもOK
    - マイグレーションの実行順序は、マイグレーションの日付が基準になります
        - これがマイグレーションファイル名を`YYYYMMDDHHMMSS_create_products.rb`とする理由
- ロールバックは`$ bin/rails db:rollback`
    - マイグレーション実行はされていない。前の適用内容は取り消したよという状態
- `$ bin/rails db:migrate:redo`のコマンドではロールバックしてからマイグレーション実行
    - `$ bin/rails db:rollback && bin/rails db:migrate`と同等

:::note info
【構文】
`rails db:migrate`：最新のマイグレーションファイルの内容に従って実行
`bin/rails db:rollback`：最後に適用したマイグレーションファイルから１つロールバック（マイグレーションは未実行）
:::

:::note warn
- `YYYYMMDDHHMMSS`がバージョンの意味を持つので`$ bin/rails db:migrate VERSION=YYYYMMDDHHMMSS`と引数を渡すと「そのバージョンまでを実行する」といった指定実行を可能にしている
- ロールバックも同様に「最新マイグレーション適用時点から何個前に遡るか」を`STEP=(バージョンダウンする数)`で渡すことが可能。`bin/rails db:rollback STEP=3`とすると「最後に適用したマイグレーションから"３"つ前のマイグレーションにロールバックする」といった指令実行になる

＊なんとなく「ファイル名に作成時刻を入れてる」な程度の認識でいたが、**"YYYYMMDDHHMMSS"はバージョンとしての意味合いが強い**点は留意すべき
:::

## スキーマダンプの意義
＊「`schema.rb`というファイルは必要あるの？」という章
＞基本`schema.rb`を直接触らないのに何でファイルとして置いておくのか

- 「DBのマイグレーション適用状況が`schema.rb`から分かる」から
    - より砕くと「何か色々とマイグレーションファイルを作って実行してきたが、現状はどんな感じでスキーマが構築されているんだろう？」という時にマイグレーションファイルを１つ１つログのように辿るのではなく、スキーマファイルを確認して最終的なマイグレーションの反映状況を把握するのに役立つ

:::note info
- `schema.rb`は自分のマイグレーション反映状況を把握できる情報源
:::