Ruby
Rails
windows7
Railsチュートリアル

Rails Tutorial (3rd ed.) の Sec 6.2.5 で add_index できない

More than 3 years have passed since last update.

Ruby 2.0.0, Rails 4.2.2, Windows7 の環境において、Rails Tutorial 3rd ed. | Section 6.2.5 周辺でコケたのでメモ。テスト環境に add_index の migration をしようとしたら、index を張りたいカラムが unique じゃないと怒られた。


お急ぎの方向け

次の 2 つのコマンドで解決します(テスト環境に大事なデータを保存していない場合)。

> rake db:rollback RAILS_ENV=test

> rake db:migrate RAILS_ENV=test


少しだけ詳しい内容

bundle exec rake db:migrate を実行した後にテストを実行しようとすると、次のようなエラーが出た(bundle exec rake testrake で実行している)。

c:\rails-tutorial\sample_app>rake

rake aborted!
ActiveRecord::PendingMigrationError:

Migrations are pending. To resolve this issue, run:

bin/rake db:migrate RAILS_ENV=test

rake db:migrate RAILS_ENV=test を実行しろと怒られる。これは、先ほどの rake db:migrate が処理したのは development 環境の DB のみで、テスト環境の DB に migration をしていないことが原因らしい(確かに、sample_app/db/ 配下に development.sqlite3test.sqlite3 という 2 つのファイルが存在している)。

そこで、エラーに書いてある通りのコマンドを実行してみる。

c:\rails-tutorial\sample_app>rake db:migrate RAILS_ENV=test

== 20151018090618 AddIndexToUsersEmail: migrating =============================
-- add_index(:users, :email, {:unique=>true})
rake aborted!
StandardError: An error has occurred, this and all later migrations canceled:

SQLite3::ConstraintException: indexed columns are not unique: CREATE UNIQUE INDEX "index_users_on_email" ON "users" ("email")c:/rails-tutorial/sample_app/db/migrate/20151018090618_add_index_to_users_email.rb:3:in `change'
C:in `migrate'
Tasks: TOP => db:migrate
(See full trace by running task with --trace)

index を張りたいカラムが unique でない、と怒られる。テスト環境のコンソールを開いて、DB 内のデータを User.all で確認してみる。

c:\rails-tutorial\sample_app>rails c test --sandbox

Loading test environment (Rails 4.2.2)
Any modifications you make will be rolled back on exit
irb(main):001:0> User.all
User Load (0.0ms) SELECT "users".* FROM "users"
=> #<ActiveRecord::Relation [#<User id: 298486374, name: "MyString", email: "MyString", created_at: "2015-10-18 08:55:20", updated_at: "2015-10-18 08:55:20">, #<User id: 980190962, name: "MyString", email: "MyString", created_at: "2015-10-18 08:55:20", updated_at: "2015-10-18 08:55:20">]>

確かに { name: "MyString", email: "MyString" } というレコードが 2 つ存在している。どちらか一方のレコードを削除すれば良いのだろうが、特に大事なデータが保存されているわけでもないため、db:rollback によってテーブルを DROP してから再度 migration してみた。

c:\rails-tutorial\sample_app>rake db:rollback RAILS_ENV=test

== 20151018060419 CreateUsers: reverting ======================================
-- drop_table(:users)
-> 0.0000s
== 20151018060419 CreateUsers: reverted (0.0000s) =============================

c:\rails-tutorial\sample_app>rake db:migrate RAILS_ENV=test

== 20151018060419 CreateUsers: migrating ======================================
-- create_table(:users)
-> 0.0000s
== 20151018060419 CreateUsers: migrated (0.0000s) =============================

== 20151018090618 AddIndexToUsersEmail: migrating =============================
-- add_index(:users, :email, {:unique=>true})
-> 0.0000s
== 20151018090618 AddIndexToUsersEmail: migrated (0.0000s) ====================

テスト環境にも無事に migration できたので、rake でテストが実行できる。


参考サイト

ruby on rails - Rake Aborted , on add_index(:users, :email, {:unique=>true}) - Stack Overflow