初心者が送る Rails での PG::DuplicateTable: ERROR の解決方法まとめ

## はじめに

こんにちは！
見習いエンジニアの 古内 です！

以前、一度作成したモデルを削除し、再度同じ名前モデルを作成したときにうまくいかず、詰まってしまったことがあったので、その解決方法を実演しながら解説をさせていただきます。

私自身も初心者なのでこの解決方法は完璧ではないかもしれませんが、慣れていない人でもわかりやすいように説明できるようがんばります！

## 環境

- Ruby 2.5.1
- Ruby on Rails 5.2.2
- Docker
- Doker Compose

## 実演

### 準備

では環境の準備から始めましょう。
私は[こちら](https://github.com/furuuchitakahiro/rails-docker)を参考に環境構築をしました。
簡単に Rails 開発環境の構築ができるので、みなさんも活用してみてください！（ こちらを使うときは最後の Docker Compose の起動まで進めてください ）

### 作業開始

まずはモデルを作成し、

`$ rails g model User`

マイグレートします。

`$ rails db:migrate`

User モデルができました。

```rb:user.rb
class User < ApplicationRecord
end
```
これを一度削除します。

`$ rails destroy model User`

再度 User モデルを作成してみましょう。

`$ rails g model User`

マイグレートします。

`$ rails db:migrate`

すると、

```
== 20190321053454 CreateUsers: migrating ======================================
-- create_table(:users)
rails aborted!
StandardError: An error has occurred, this and all later migrations canceled:

PG::DuplicateTable: ERROR:  リレーション"users"はすでに存在します
: CREATE TABLE "users" ("id" bigserial primary key, "created_at" timestamp NOT NULL, "updated_at" timestamp NOT NULL)
```

このようなエラー文が出てしまい、 User モデルを作成できません。

## 対策

User モデルを削除したときに、それが DB 側に伝わっていなかったことが問題だったです。
では解決してみましょう！

まず作成したマイグレーションファイルを削除します。

`$ rails destroy migration create_users`

続いて DB 側にモデルを削除したことを伝えるマイグレーションファイルを作成します。

`$ rails g migration drop_table_users`

続いて作成したマイグレーションファイルに以下のように追加してください。

```rb:20190321063950_drop_table_users.rb
class DropTableUsers < ActiveRecord::Migration[5.2]
  def change
    drop_table :users #追加
  end
end
```

これを追記することで DB 側のテーブルを削除できます。

マイグレートします。

`$ rails db:migrate`

先程使ったマイグレーションファイルを削除しましょう。

`$ rails destroy migration drop_table_users`

ではもう一度 User モデルを作成し、マイグレートしてみましょう。

`$ rails g model user`
`$ rails db:migrate`

これで User モデルを再度作成できました！

## 解説

今回の原因は User モデルを削除したときに、 DB 側にそれが伝わっていなかったことでした。
「なぜ作成するときは大丈夫なのに、削除するときはだめなの？」と思う方もいると思います。
これはマイグレートに原因があります。

図にすると、
<br>
&emsp;&emsp;&emsp;__Rails 側__ &emsp;&emsp; migrate &emsp;&emsp;&emsp;&emsp; __DB 側__
User model 作成 &emsp; --------> &emsp; User table 作成
<br>
&emsp;&emsp;&emsp;__Rails 側__ &emsp;&emsp;&emsp;&emsp;&emsp;&emsp;&emsp;&emsp;&emsp;&emsp; __DB 側__
User model を削除 &emsp;&emsp;&emsp;&emsp;&emsp;&emsp; User table が存在
<br>
&emsp;&emsp;&emsp;__Rails 側__ &emsp;&emsp; migrate &emsp;&emsp;&emsp;&emsp; __DB 側__
User model 作成 &emsp; --------> &emsp; User table はすでに存在
<br>
このようなことが起きているためエラー文が出てしまったのです。

ここでテーブルを削除するマイグレートを実行すると、
<br>
&emsp;&emsp;&emsp;__Rails 側__ &emsp;&emsp;&emsp;&emsp;&emsp;  migrate &emsp;&emsp;&emsp;&emsp;&emsp;&emsp;&emsp;  __DB 側__
User model 作成 &emsp;&emsp;&emsp; -------------> &emsp;&emsp;&emsp; User table 作成
<br>
&emsp;&emsp;&emsp;__Rails 側__ &emsp;&emsp;&emsp;&emsp;&emsp;&emsp;&emsp;&emsp;&emsp;&emsp;&emsp;&emsp;&emsp; &emsp;&emsp;&emsp;  __DB 側__
User model を削除 &emsp;&emsp;&emsp;&emsp;&emsp;&emsp; &emsp;&emsp;&emsp;&emsp;&emsp;  User table が存在
<br>
&emsp;&emsp;&emsp;__Rails 側__ &emsp;&emsp;&emsp;&emsp;&emsp;  migrate &emsp;&emsp;&emsp;&emsp;&emsp;&emsp;&emsp;  __DB 側__
drop_table_user 作成 &emsp; ------------> &emsp;&emsp;&emsp; User table を削除
<br>
&emsp;&emsp;&emsp;__Rails 側__ &emsp;&emsp;&emsp;&emsp;&emsp; migrate &emsp;&emsp;&emsp;&emsp;&emsp;&emsp;&emsp;  __DB 側__
User model 作成 &emsp;&emsp;&emsp; ------------->  &emsp;&emsp;&emsp; User table 作成
<br>
となり、再度 User モデルを作成できるようになります。

ちなみにマイグレートを実行すると、db/migrate ディレクトリにあるマイグレーションファイルを上から逐一 DB に反映させていくので、ここで整合性が取れていないとエラーが起きてしまいます。 ( テーブル削除のマイグレーションファイルを削除したのもこのため。テーブルを削除が完了したら、次のマイグレート実行時、削除対象がないためエラーの原因になる。 ) 

## 最後に

マイグレーション周りは複雑でわかりにくいです。
私もモデルとテーブルが別のものだと理解したり、整合性を取るようにするまでは大変でした。

モデル = DB の設計図
テーブル = モデルをもとに実際に作られたもの

と考えればわかりやすいかもしれません。