Rails

【SQLite3::SQLException: table "users" already exists】の原因と対処

09/04/2023

順番に起因するエラーイメージ(rails aborted!
StandardError: An error has occurred, this and all later migrations canceled:
SQLite3::SQLException: table "users" already exists)

テストしたところエラーが発生。

Railsチュートリアル(Rails7)11章で躓いた時のことを書きます。

% rails test
Migrations are pending. To resolve this issue, run:

    bin/rails db:migrate RAILS_ENV=test

You have 1 pending migration:

20230219143247_create_users.rb

指示どおり実施。

% bin/rails db:migrate RAILS_ENV=test
== 20230219143247 CreateUsers: migrating ======================================
-- create_table(:users)
rails aborted!
StandardError: An error has occurred, this and all later migrations canceled:

SQLite3::SQLException: table "users" already exists
/Users/xxxxxxxx/src/github.com/sample_app/db/migrate/20230219143247_create_users.rb:3:in `change'

Caused by:
ActiveRecord::StatementInvalid: SQLite3::SQLException: table "users" already exists
/Users/xxxxxxxx/src/github.com/sample_app/db/migrate/20230219143247_create_users.rb:3:in `change'

Caused by:
SQLite3::SQLException: table "users" already exists
/Users/xxxxxxxx/src/github.com/sample_app/db/migrate/20230219143247_create_users.rb:3:in `change'
Tasks: TOP => db:migrate
(See full trace by running task with --trace)

already exists なので既存のテーブルを一度削除してみました。

% rails db
SQLite version 3.39.5 2022-10-14 20:58:05
Enter ".help" for usage hints.
sqlite> .tables
ar_internal_metadata schema_migrations  
sqlite> .drop table ar_internal_metadata
Error: unknown command or invalid arguments: "drop". Enter ".help" for help
sqlite> drop table ar_internal_metadata;
sqlite> drop table schema_migrations;
sqlite> .quit

異なるエラーが発生しました。

% rails db:migrate
== 20230122150428 AddIndexToUsersEmail: 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
/Users/xxxxxxxx/src/github.com/sample_app/db/migrate/20230122150428_add_index_to_users_email.rb:3:in `change'

Caused by:
ActiveRecord::StatementInvalid: SQLite3::SQLException: no such table: main.users
/Users/xxxxxxxx/src/github.com/sample_app/db/migrate/20230122150428_add_index_to_users_email.rb:3:in `change'

Caused by:
SQLite3::SQLException: no such table: main.users
/Users/xxxxxxxx/src/github.com/sample_app/db/migrate/20230122150428_add_index_to_users_email.rb:3:in `change'
Tasks: TOP => db:migrate
(See full trace by running task with --trace)

この上記エラーの要因についてわからずに悩みました。

ファイルに記載のソースには誤りが見当たらなかったためです。

「テーブルがない」とありますが、main.usersがどの部分を指しているのか。

/20230122150428_add_index_to_users_email.rb

class AddIndexToUsersEmail < ActiveRecord::Migration[7.0]
def change
  add_index :users, :email, unique: true
end
end

結局、理由は最初に来るべき「create_users」ファイルが、名前変更によって最後に来てしまったためでした。


マイグレーションファイル名は接頭辞が数字になっており、YYYYMMDDHHMMSS_ (西暦・月・日・時・分・秒) と並びます。

そして、マイグレーション (テーブルの変更) はこの時系列順に実行してきます。


2つめのエラーは、users テーブルの作成前 (create_users 前)に、uses テーブルに email の INDEX を追加しようと動いているため起きているエラーでした。

1つめのエラーは、create_users の接頭辞が変更されたため「未処理のマイグレーションファイル」という判定になり、もう一度 users テーブルを作ろうとしたため起きていたエラーです。

ファイル名を元の状態に変更し、DBを作り直すことで解決しました。

% cd db/migrate       
% mv 20230219143247_create_users.rb 20230121135308_create_users.rb
% bin/rails db:reset
Dropped database 'db/development.sqlite3'
Dropped database 'db/test.sqlite3'
Created database 'db/development.sqlite3'
Created database 'db/test.sqlite3'
You have 1 pending migration:
 20230219142309 AddActivationToUsers
Run `bin/rails db:migrate` to update your database then try again.
% bin/rails db:migrate
== 20230219142309 AddActivationToUsers: migrating =============================
-- add_column(:users, :activation_digest, :string)
  -> 0.0008s
-- add_column(:users, :activated, :boolean, {:default=>false})
  -> 0.0003s
-- add_column(:users, :activated_at, :datetime)
  -> 0.0003s
== 20230219142309 AddActivationToUsers: migrated (0.0014s) ====================

以前はエラー発生時には、該当箇所のソースコードを修正すればよいという程度しか理解できていませんでした。

仕組みを知って、エラーがどのような動作の中で起きたのか、意識することが解決のために必要することが大事なのだと学ぶことができてよかったです。

-Rails