Railsチュートリアル6章の最後でHerokuへのデプロイを行なったが、本番環境でデータを追加するところでつまづいた。
$ User.create(name: "Michael Hartl", email: "michael@example.com", password: "foobar", password_confirmation: "foobar")
Traceback (most recent call last):
1: from (irb):1
NoMethodError (undefined method `password_digest=' for #<User:0x0000559649ee1be8>)
Did you mean? password=
どうやらpassword_digestというカラムが無いようなので、そんなバカなと思いつつ、Dataclipsを使ってHerokuのデータベースを覗いてみた。
HerokuではPostgreSQLが使われているため、特定のテーブルに存在するカラムを全て確認したい場合のSQL文は以下のとおり。
SELECT
*
FROM
information_schema.columns
WHERE
table_name = 'カラムを確認したいテーブル名'
ORDER BY
ordinal_position;
カラムを確認したいテーブル名を'users'に置き換えて実行してみると、たしかに存在するカラムはid, name, email, created_at, updated_atのみで、password_digestは存在しなかった。
調べている内にマイグレーションが途中で失敗した可能性を疑い、再度エラーメッセージ を読んでみることに。
$ heroku run rails db:migrate
Running rails db:migrate on ⬢ evening-depths-91412... up, run.5025 (Free)
I, [2021-02-05T16:54:30.379714 #4] INFO -- : Migrating to AddIndexToUsersEmail (20210204062823)
== 20210204062823 AddIndexToUsersEmail: migrating =============================
-- add_index(:users, :emai, {:unique=>true})
rails aborted!
StandardError: An error has occurred, this and all later migrations canceled:
PG::UndefinedColumn: ERROR: column "emai" does not exist
.
.
.
何やら、emailを書き損なった"emai"というカラムをインデックスにしようとしてエラーを起こしているようだ。
マイグレーションファイルを見直すと
class AddIndexToUsersEmail < ActiveRecord::Migration[6.1]
def change
add_index :users, :emai, unique: true
end
end
あった。
修正後rails testでエラーが出ないのを確認し、マージしてデプロイし直し再度マイグレーション。
$ heroku run rails db:migrate
Running rails db:migrate on ⬢ evening-depths-91412... up, run.8472 (Free)
I, [2021-02-05T17:43:27.569947 #4] INFO -- : Migrating to AddIndexToUsersEmail (20210204062823)
== 20210204062823 AddIndexToUsersEmail: migrating =============================
-- add_index(:users, :email, {:unique=>true})
-> 0.0107s
== 20210204062823 AddIndexToUsersEmail: migrated (0.0109s) ====================
I, [2021-02-05T17:43:27.592722 #4] INFO -- : Migrating to AddPasswordDigestToUsers (20210204143751)
== 20210204143751 AddPasswordDigestToUsers: migrating =========================
-- add_column(:users, :password_digest, :string)
-> 0.0020s
== 20210204143751 AddPasswordDigestToUsers: migrated (0.0021s) ================
今度は問題なさそうだ。
$ User.create(name: "Michael Hartl", email: "michael@example.com", password: "foobar", password_confirmation: "foobar")
=> #<User id: 1, name: "Michael Hartl", email: "michael@example.com", created_at: "2021-02-05 17:46:04.616062000 +0000", updated_at: "2021-02-05 17:46:04.616062000 +0000", password_digest: [FILTERED]>
OK。
なぜ今までローカルでは問題なく動いていたのかは調べてみないとわからないが、rails testでエラーが出なかったからといって油断してはいけないようだ。
もっとも、テストケースが不足していればエラーが出なくても実は問題があったなんてことは簡単に起こるので、今回の問題に限らず当たり前なのだが。
#参考
1.【Heroku】RailsアプリでNoMethodErrorが出たときの対処法
2.Herokuデプロイ後にデータベースの中身を確認する方法【Dataclipsの使い方】
3.PostgreSQLでテーブル名カラム名を取得する方法