RailsでHerokuにデプロイしたときに一部ページだけ500エラーとなるとき

マイグレーションファイルは慎重に作成し、ミスったらやり直すくらいの覚悟じゃないとHerokuにpushして`heroku run rails db:migrate`したときに沼にハマるよという話。

##発生している問題
ローカル環境ではキチンと動くのに、（[SQLite->Postgresへの対応などの基本的な設定](https://qiita.com/kazukimatsumoto/items/a0daa7281a3948701c39)を済ませてから）Herokuにデプロイするも、一部のページだけが500（Internal Server Error）となる。フロントでは「We're sorry, but something went wrong.」なので、404の「The page you were looking for doesn't exist.」とは違って内部的なエラーが発生している。
<img width="1407" alt="スクリーンショット 2020-06-23 21.58.17.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/242610/78575d5e-92b9-f6bb-ff12-eeb6879f900d.png">

`heroku logs --tail`でログを見ても以下の500エラーと書かれただけで何が原因か全然分からないかった。

```console
2020-06-23T09:27:34.223359+00:00 app[web.1]: [8ee3a40d-5258-46f4-8742-48c47f28b01f]   Category Load (1.2ms)  SELECT "categories".* FROM "categories"
2020-06-23T09:27:34.474847+00:00 heroku[router]: at=info method=GET path="/categories/1/show" host=my-app.herokuapp.com request_id=8ee3a40d-5258-46f4-8742-48c47f28b01f fwd="27.81.17.54" dyno=web.1 connect=1ms service=263ms status=500 bytes=1827 protocol=https
```

##結論
**汚いマイグレーションファイルを残したままpushして`heroku run rails db:migrate`していないか疑え！**

以下の記事の【1】と同じだった。
https://qiita.com/kaorioka09jm/items/9167ba77d1edf7addac2
>ローカル開発中にDB作りを試行錯誤したことが原因

Herokuにデプロイした全ページが500とかなら`heroku run rails db:migrate`してないなど他の理由もあるが、一部のページだけ表示されない場合はDBのマイグレーションが上手くいっていない場合が多いようだ。

結局、ローカルのマイグレーションファイルを削除したり、作り直したりしても、一度Herokuにpushしてしまったマイグレーションファイルがあると、データベースをResetしてもDestroyしても、そこから`heroku run rails db:migrate`してもデータベースは綺麗にならない。

そのため筆者の場合はHerokuからアプリを削除して再度pushし直す羽目になった。

### マイグレーションファイルの注意点
- マイグレーションファイルは一度しか`rails db:migrate`できない
- 生成される`schema.rb`を直接編集しちゃダメ（と思われる）
- テーブルの削除なども都度マイグレーションファイルを作ってやること

そのため以下のようなマイグレーションファイルの生成は慎重に行う必要がある。もし間違ってカンマを入れたり本来integerのデータ型を間違ってtextに指定してしまったなどだけで、変なマイグレーションファイルが生成される。

```console
// 例
rails g migration CreatePostCategoryRelations post_id:integer category_id:integer
// 間にカンマを入れたり、コロンの位置が違ったり、integerの綴りが違ったりと間違えがち
```

それを挽回するために別のマイグレーションファイルを作って‥なんてやってローカルでDBをぐちゃぐちゃ構築しても、それをpushした後に`heroku run rails db:migrate`を実行すると過去のマイグレーションファイルを順に実行するのでおかしくなる。

今回は[Postico](https://eggerapps.at/postico/)の使用により、DBの中のあるテーブルの`category_id`カラムがStringになっていたことに気付けたので、Heroku側のDB生成が上手くいってないことに気付けた。

DBがおかしいと気付くには、`rails db:migrate`した際のログをめんどうでもちゃんと読んで確認するのも役立つと思う。

- キチンと標準のテーブル+マイグレーションファイルで指定したテーブルが作成されているか？
- 各テーブルのカラムのデータ型は正しいか？


##テーブルの削除
Heroku上に正しいマイグレーションファイルをpushするには、まずローカルのマイグレーションファイルを綺麗にする必要がある。しかし、間違った記述のあるマイグレーションファイルを削除し、正しいマイグレーションファイルを作成して`rails db:migrate`しても、以下のように怒られて上書きはできない。

```
rails aborted!
StandardError: An error has occurred, this and all later migrations canceled:
SQLite3::SQLException: table "post_category_relations" already exists
```

そのためテーブルの削除用のマイグレーションファイルを作成して`rails db:migrate`し、再度新たなテーブル作成用のマイグレーションファイルを作成して`rails db:migrate`する必要がある。

```console
$ rails generate migration RemoveMyTable
```

```20200623XXXX_remove_my_table.rb
class RemoveMyTable < ActiveRecord::Migration[6.0]
  def change
    drop_table :my_table
  end
end
```
https://qiita.com/kanuu/items/a9223712ee0ff8d19d56

その後、テーブルの削除などに使った余分なマイグレーションファイルを削除する。こうして綺麗なマイグレーションファイルだけが残ったので、これをまっさらなHerokuにpushしてから`heroku run rails db:migrate`をしてやると綺麗なデータベースができる。

##考えたこと
###SQLiteとPostgreSQLの互換性の問題ではないか
Herokuでは SQLite が使えないので、production環境だけ PostgreSQL を使用するのはHerokuで最初につまづくポイントだが、これの変更によって使えないメソッドがあるのではと考えた。

が、そんなことはなく、そもそもマイグレーションファイルとはSQLを書かずに、かつ言語の種類（SQLiteかPostgreSQLか等）によらずにDBを操作するためのものである。

今回はControllerの以下の`includes`や`where`がPostgreSQLでは使えないのでは、といった馬鹿な勘違いをしてしまった‥orz.

```categories_controller.rb
def show
  @posts = Post.includes(:categories).where(post_category_relations: { category_id: @category })
end
```
※Gemのpgloaderを使うなどの記事を見つけたが、それはMySQLのデータをPostgreSQLのデータに移行するものであって、メソッドを変換とかではない。

###push後のWarningされてる部分に問題があるのではないか
pushした後に以下のWarningが出るが今回は無関係。またこれらは、どれも特別な使い方をしない限りは、初心者は無視していい警告だ。

```
remote: ###### WARNING:
remote:        You set your `config.assets.compile = true` in production.
remote:        You set your `config.active_storage.service` to :local in production.
remote:        We detected that some binary dependencies required to
remote:        No Procfile detected, using the default web server.
```

##マイグレーションファイルの理解を深めるのに役立ちそうな記事
そもそもマイグレーションとは何なのか👇
https://qiita.com/sobameshi0901/items/f5823fec20e2dd78d9c4

ロールバックという手法もあるらしい👇
https://qiita.com/params_bird/items/3d503b5c9f8097df147a