【Rails】migrateでのエラーの対処

# 【１】はじめに

## 記事を作成した経緯
私は４月に進学した大学の課外活動で初めてプログラミング言語について学び始め、 Railsを使ってチーム開発をおこなっている。そこで多くのエラーを吐かれいろいろなサイトを参考にしてみたものの、根本的な解決方法を見つけることができなかったため、ここにまとめる。

また、内容の一部を[関連記事](https://qiita.com/takumi1227/private/63a4dc67acfc3356914b "migrateについて")を基に記載している。

## 目的
Railsに関するエラーや対処方法について、自分と同じような悩みを持つ人が読みやすい資料として一括にまとめる。また、各章末に、参考にした記事などのURLを貼っておくので活用してほしい。

## お願い
本記事内では、私が「詰まった」あるいは「必要」だと感じた内容を記載しており、内容の一部は「項４．参考サイト」にある記事を参考にしている。また、本記事内に記載のない内容についても同じくリンクしてあるので、もし不明なことがあれば参考先を確認することで解決できる場合がある。


# 【２】本記事のエラー内容の種類

## エラー１

### 実行内容

次のようにモデルを作成した。
```
myapp# rails g model User name:string schoolnumber:integer grade:integer
      invoke  　active_record
      create    db/migrate/20240925141211_create_users.rb
      create    app/models/user.rb
```
一見、成功しているようにみえるが、対象ファイルをマイグレートしようと、 ```rails db:migrate``` を実行しようとしたが、すでに対象ファイルを削除してしまっていた。ひとつ前に戻そうと ```rails rollback```をすると以下のエラーが出た。
```
--実行コマンド--
myapp# rails db:rollback

--エラー内容--
bin/rails aborted!
ActiveRecord::UnknownMigrationVersionError:  (ActiveRecord::UnknownMigrationVersionError)

No migration with version number 20240924023519.
```

### エラー内容
このエラーメッセージ ```ActiveRecord::UnknownMigrationVersionError``` は、指定されたバージョン番号 (20240924023519) のマイグレーションが存在しないことを示している。```db:rollback``` を実行しようとした際に、このバージョンのマイグレーションがデータベースにはないため、エラーが発生している。

### 予想される原因
**１．削除されたマイグレーション**
そのマイグレーションファイルが存在していない、あるいは手動で削除された可能性がある。
**２．マイグレーションのファイル名の変更**
ファイル名が手動で変更されたか、不完全な状態で存在している可能性がある。

### 解決策
**１．** ```db/schema.rb``` **の確認**
まず、```db/schema.rb``` ファイルを確認して、問題のマイグレーションが適用されているかどうかをチェックし、version フィールドに該当するバージョン番号がない場合、それはまだ適用されていないことを意味する。

**２．マイグレーションファイルの確認**
```db/migrate``` ディレクトリに移動し、```20240924023519``` のマイグレーションファイルが存在するかどうかの確認を行う必要がある。
```
$ ls db/migrate 
```
このバージョン番号に一致するファイルがない場合、それが原因である。

**３．マイグレーションバージョンを手動で修正**
- 該当バージョンのマイグレーションがすでに削除されていて実行できない場合、手動でデータベースのバージョン情報を修正することができる
- データベースの schema_migrations テーブルに該当バージョンが存在していれば、手動で削除することもできる（ただし、慎重に行う必要がある）

**コマンド例（該当バージョンが存在する場合に手動で削除）**
番号の順番に行う。
①コンソールに入る
```
myapp# rails console
```
②手動で削除
```
> DELETE FROM schema_migrations WHERE version = '20240924023519';
```

**４．強制的にリセット**
最後の手段として、データベースをリセットし、すべてのマイグレーションを再実行することが可能である。
```
myapp# rails db:drop db:create db:migrate
```
これによってデータベースが初期化され、すべてのマイグレーションが再度適用される。

## エラー２
### 実行内容
```
myapp# rails g model User name:string schoolnumber:integer grade:integer
      invoke  active_record
The name 'User' is either already used in your application or reserved by Ruby on Rails. Please choose an alternative or use --skip-collision-check or --force to skip this check and run this generator again.
```

### エラー内容
```User``` という名前のモデル名が既に存在しているか、Rails で予約されている名前（予約語）のため、新しくモデルを生成しようとした際に衝突している。

### 解決方法（いくつかの選択肢あり）
**１．モデルの名前を変更**
既存の ```User``` モデルがある場合、別の名前を使って新しいモデルを作成することができる。例えば、```Account``` や ```Member``` のような名前を使うことが考えらる。
```
rails g model Account name:string schoolnumber:integer grade:integer
```

**２．既存の ```User``` モデルを裁量する**
もし、```User``` モデルがすでに存在しており、それが再利用可能であれば、```rails g model``` コマンドを実行する必要がなく、既存のモデルを修正し、必要なフィールド（```name``` , ```schoolnumber``` , ```grade``` ）を追加することができる。
- マイグレーションを追加して、```User``` テーブルにフィールドを追加する
```
rails g migration AddDetailsToUsers name:string schoolnumber:integer grade:integer
```

- その後、マイグレーションを実行
```
rails db:migrate
```

**３．```--force``` オプションを使用して上書きする
もし、古い ```User``` モデルを削除したい、もしくは完全に新しくしたい場合は、```--force``` オプションを使って既存の衝突を無視し、新しい ```User``` モデルを上書きすることができる。
```
rails g model User name:string schoolnumber:integer grade:integer --force
```
:::note warn
```--force``` オプションを使用する場合、既存の ```User``` モデルやマイグレーションが上書きされる可能性があるため、慎重に行う必要がある。
:::

**４．衝突をスキップする**
衝突チェックをスキップして実行したい場合は、```--skip-collision-check``` を使うことも可能である。ただし、この方法では、既存のファイルが保持される可能性があるため注意が必要である。
```
rails g model User name:string schoolnumber:integer grade:integer --skip-collision-check
```

## エラー３
このエラーは、```エラー２``` のときに出たエラーである。

### 実行内容
```
myapp# rails g migration AddDetailsToUsers name:string schoolnumber:integer grade:integer
      invoke  active_record
      create    db/migrate/20240925142629_add_details_to_users.rb
root@dfbd85317b40:/myapp# rails db:migrate
== 20240925142629 AddDetailsToUsers: migrating ================================
-- add_column(:users, :name, :string)
bin/rails aborted!
StandardError: An error has occurred, all later migrations canceled: (StandardError)

Mysql2::Error: Duplicate column name 'name'
/myapp/db/migrate/20240925142629_add_details_to_users.rb:3:in change'

Caused by:
ActiveRecord::StatementInvalid: Mysql2::Error: Duplicate column name 'name' (ActiveRecord::StatementInvalid)
/myapp/db/migrate/20240925142629_add_details_to_users.rb:3:in change'

Caused by:
Mysql2::Error: Duplicate column name 'name' (Mysql2::Error)
/myapp/db/migrate/20240925142629_add_details_to_users.rb:3:in change'
Tasks: TOP => db:migrate
(See full trace by running task with --trace)
```

### エラー内容
このエラーメッセージは、データベースの ```users``` テーブルに既に ```name``` というカラムが存在しているため、マイグレーションで同じカラムを追加しようとしてエラーが発生していることを示している。