##あいさつ
今回は僕が遭遇した限定的なエラーでありその対処ですが、流れは基本どのエラーでも通用するはずです。
ログを読み解くのは大変な作業ですが、時間かけてでもやる価値はあります。
railsのメソッドであるfind, find_byの勉強にもなると思います。
また、今回の記事は僕自身の備忘録が中心であり、少しでも他者の理解に役立てばというところです。至らないところはあると思いますが多めに見ていただければ幸いです。
##具体的なエラー内容
開発環境では正常に動くが、本番環境でエラーになる。
Rails Tutorial 7章を終えてherokuにデプロイ後、Production環境にてユーザー登録後のredirect(/users/:id)でエラーが起きる。なお、Deverop環境の動作は正常。
##原因の突き止め方
###1. logを確認する
ターミナルで下記を実行する。
$ heroku logs
###2. logの中からerrorを探す
この作業は文字の羅列からerror文を探し、デバッグするのでしんどいですが成長に繋がります。
ただ、文字の羅列を眺めてても大変なので、下記のコマンドを実行し、error文を探します。
- command + F (検索窓を開く)
発見しました。ERRORと書いてます。(一番下の行)
ActiveRecord::StatementInvalid (PG::DatatypeMismatch: ERROR: argument of WHERE must be type boolean, not type integer
###3. error文を読み解こう
argument of WHERE must be type boolean, not type integer がヒントです。
(訳) WHEREの引数は、整数型ではなくブール型である必要があります。
つまり、
User Load (0.8ms) SELECT "users".* FROM "users" WHERE (1) LIMIT $1 [["LIMIT", 1]]
WHERE( )に入る引数はint型じゃないよ!!と言ってます。int型の「1」が入っちゃってますね。
###4. logを遡って具体的にどのコード上でエラーになっているか突き止める
ここで少しlogを遡ります。
(1) /users/1をGETでリクエストしてます。
Started GET "/users/1" for 60.125.238.10 at 2021-02-01 11:17:58 +0000
(2) UsersController#showを通ります。
Processing by UsersController#show as HTML
ここでshowメソッドに問題があると気づきます。
このコードのどこが問題か理解できたら僕より強者ですwわからなければ最後までお付き合いください。
###5. 実際にコードを直す
少し話が飛びますが、RailsというのはActiveRecordによって、SQLを意識せずにデータベースを扱う事が可能というものでしたね。メソッドを書くだけで、勝手にSQLに変換しデーターベースを操作してくれます。
ということは、問題のコードもSQLに変換しているんですね。
この例だと
>> User.find_by(1)
Traceback (most recent call last):
1: from (irb):19
ArgumentError (Unsupported argument type: 1 (Integer))
こんな感じです。あれエラーになってますね。
はい。実はfind_byメソッドの引数が間違ってるんですね。
find_byメソッドは整数型(Integer)を渡すのではなく、ハッシュを渡すのを思い出してください。
正しい呼び出し方は
User.find_by(id: "1")
User Load (0.1ms) SELECT "users".* FROM "users" WHERE "users"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]]
=> #<User id: 1, name: "Rails Tutorial", email: "example@railstutorial.org", created_at: "2021-02-01 05:27:00", updated_at: "2021-02-01 05:27:00", password_digest: "$2a$10$auC9Flb47s9XjRGov6byfuHhZmUEw3J1AOSNu.TRAqZ...">
はい。引数にハッシュを渡したらしっかり返ってきました。
つまり、僕はfind_byメソッドを使っているのに、整数型を渡してたんですね...(´・-・。)クスン
正しいコードは下記です。
ちなみに整数型を渡すのであればfindメソッドを使います。
>> User.find(1)
User Load (0.2ms) SELECT "users".* FROM "users" WHERE "users"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]]
=> #<User id: 1, name: "Rails Tutorial", email: "example@railstutorial.org", created_at: "2021-02-01 05:27:00", updated_at: "2021-02-01 05:27:00", password_digest: "$2a$10$auC9Flb47s9XjRGov6byfuHhZmUEw3J1AOSNu.TRAqZ...">
はい。しっかり返ってきましたね。
findメソッド書く場合のコードは下記です。
###まとめ
今回のエラーはfind_byの使い方に問題がありました。このデバッグ方法は僕の先輩にあたる方からご教授いただき、身につけた方法です。ありがとうございます。logからデバッグをするのは基本中の基本なので、最初はめんどくさく感じて嫌になりそうですが、時間かけてでも着実にやることで成長できると感じました。
最後までお付き合いいただきありがとうございました。