Help us understand the problem. What is going on with this article?

rails db:migrate:resetできなかったのでrails db:resetした

More than 1 year has passed since last update.

結論から

dbをmigrateするときにエラーが出た場合、rails db:migrate:resetでDBリセットとmigrateを同時に行おうとすると失敗する場合がある。
migrationファイル内の実行順に問題がある可能性があるので、rails db:resetrails db:migrateを分けて行うことで解決できる場合がある。

環境

Rails 5.1.2
Ruby 2.4.3

起こったこと

migrationでエラー

rails tutorialを進めていてdbをmigrateしようとしたらこんなエラーが出ました。

$ rails db:migrate

== 20171229141042 CreateUsers: migrating ======================================
-- add_index(:users, :email, {:unique=>true})
   -> 0.0010s
-- create_table(:users)
rails aborted!
StandardError: An error has occurred, this and all later migrations canceled:

SQLite3::SQLException: table "users" already exists: CREATE TABLE "users" ("id" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, "name" varchar, "email" varchar, "created_at" datetime NOT NULL, "updated_at" datetime NOT NULL)

...

userテーブルが既にあるのにつくろうとしている、と怒られています。

reset:migrationでもエラー

そこで、 rails db:migrate:resetしようとしました。
(このコマンドは7.4.3 実際のユーザー登録の章で触れられています)

$ rails db:migrate:reset


Dropped database 'db/development.sqlite3'
Dropped database 'db/test.sqlite3'
Created database 'db/development.sqlite3'
Created database 'db/test.sqlite3'
== 20171229141042 CreateUsers: migrating ======================================
-- add_index(:users, :email, {:unique=>true})
rails aborted!
StandardError: An error has occurred, this and all later migrations canceled:

SQLite3::SQLException: no such table: main.users: CREATE UNIQUE INDEX "index_users_on_email" ON "users" ("email")

...

またusersテーブルがないと怒られました。

処理の流れを見てみると、DBを削除して作り直した後にindexを追加しようとしてこけています。そしてusersテーブルを作成する処理が行われていません。

migrationファイルを見てみる

migrationファイルを見てみると、原因がわかりました。

usersテーブルを作成する前にadd_indexしてしまっています。
rails tutorialを進める中で、migrationファイルを作る前にDBを色々操作したことが原因のようです。

class CreateUsers < ActiveRecord::Migration[5.1]
  def change
    add_index :users, :email, unique: true
    create_table :users do |t|
      t.string :name
      t.string :email

      t.timestamps
    end
  end
end

こちらに書いてあることがヒントになりました。
https://stackoverflow.com/questions/33139275/error-on-migration-sqlite3sqlexception-no-such-table-main-users

上の記事のようにmigrationを修正しても良いのですが、公式では推奨しないと書いてあるし、既にあちこちデータを触ってしまっていたので、わたしは下記の手順でエラーを解消しました。

rails:db:resetしてみる

$ rails:db:reset


Dropped database 'db/development.sqlite3'
Dropped database 'db/test.sqlite3'
Created database 'db/development.sqlite3'
Created database 'db/test.sqlite3'
-- create_table("users", {:force=>:cascade})
   -> 0.0036s
-- create_table("users", {:force=>:cascade})
   -> 0.0021s

DBが削除、再作成され、usersテーブルが無事作られました。
このあとmigrationすると、usersテーブルが存在しているため問題なく成功します。

rails db:resetとrails db:migration:resetの違い

rails db:resetrails db:migration:resetはどちらも一旦全てのDBを 削除した後に作成し直すコマンドですが、下記の違いがあります。

rails db:resetについて

rails db:resetはdb/schema.rbを元にDB作成します。db/migrate/**.rb は使われません。

Rails Guidesに下記のように記述があります。

bin/rails db:resetタスクは、データベースをdropして再度設定します。このタスクは、bin/rails db:drop db:setupと同等です。

このタスクは、すべてのマイグレーションを実行することと等価ではありません。このタスクでは現在のschema.rbの内容をそのまま使い回しているためです。マイグレーションをロールバックできなくなった場合には、bin/rails db:resetを実行しても復旧できないことがあります。スキーマダンプの詳細については、スキーマダンプの意義 セクションを参照してください。

4.3 データベースをリセットする

rails db:drop db:setupと同義ということでrails db:setupコマンドのドキュメント(4.2 データベースを設定する)を確認します。

  • データベースの作成
  • スキーマの読み込み
  • シードデータを使用したデータベースの初期化

の3つの処理を実行すると書いてあります。

rails db:migrate:resetについて

一方rails db:migrate:resetは、DBを削除した後に、db/migrate/**.rb を古い順から実行するそうです。
こちらは、migrateファイルを修正したときに、一度DBを削除した上で新たにmigrationを適用したい場合などに使うそうです。
ちなみにこちらは最新のRails Guidesにはこのコマンドが載っておらずRails 4系のドキュメントにしか記載がありませんでした。

rails -Tで検索しても存在しません。

英語版の5系のチュートリアルでもこのコマンドを実行する指示があるのですが、実際は裏コマンド扱いなのでしょうか...?

終わりに

resetとmigrateを分けてコマンドを実行する方法は、データをあちこち触る開発初期などに使うといいかと思います。

エラーの根本的解決のためには、DBとmigrationファイルを確認して不整合を修正する必要があります。

mom0tomo
ʕ ◔ϖ◔ʔ Go/インフラ 最近はQiitaじゃなくブログに書いています👉 https://mom0tomo.github.io
https://mom0tomo.github.io/
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした