【バグの振り返り】ビューで参照する変数の名前を間違えた
状況
クエリオブジェクトに複数あるメソッドのひとつで、ビューで返り値がもっているはずのカラムを参照しようとしたら、"no defined method"エラーになった。クエリ自体、正しい結果を返していた。だのに、なぜビューで「それ」がないと言われるのかわからない。
- クエリオブジェクトのなかには4つメソッドがあり、すべてDBのデータを集計するものだがそれぞれ集計条件が異なっている。
- 3つは正常に動作している。
- ひとつだけがなぜが失敗している。
前提
解決
ビューの変数名を正しいものに直した。同じビューに渡している別の変数を参照していた。
コード
概要
コントローラー
app/controllers/ranking_controller.rb
def show @ranking_list = Page.lastweek_access_ranking end
モデル
app/models/page.rb
scope :lastweek_access_ranking, ->() { Pages::RankingQuery.new.lastweek_ranking }
クエリオブジェクト
app/queries/ranking_queries.rb
module Pages class RankingQuery def lastweek_ranking // 集計 end end end
ビュー
- @ranking_list.each do |page| = page.rank # No defined method!
振り返り
1. 変数の名前はそろえた方がいい
現実には、クエリオブジェクトにあるそれぞれのメソッドが、複数のテンプレートに渡されるようになっていた。4つのうち、3つは変数名を同じにしていて、バグったひとつだけが違う名前になっていた。
以前の状態のコードでは、ひとつだけ名前が違うまっとうな理由があってそうしていた。その後の変更でその理由が消失したので、その時点で名前を統一すべきだが、そうしなかった。
2. すぐに調べられるポイントから見ていった方が早く解決するかもしれない
ややこしいことを調べるのは時間と労力がたくさん必要になる。なので、楽にチェックできるところから見直すとよいかもしれない。
最初に疑わしくみえた箇所がバグの原因であればよい。だが、あちこち探し回ってわからない、という具合になると疲労がはげしい。
結局、変数の名前違いに気づいたのは、考えつく限りのあやしい箇所を調べ尽くしてお手上げになり、あきらめ気分でコントローラーをみているときだった。
はじめ疑っていたのが、クエリの書き方が間違っているという線だった。ログからSQLを取り出してMySQLコンソールで実行したら期待通りの結果が返ってきたので、クエリとしては正しいことがわかっていた。そこで次の疑いが 生まれた。生クエリでJOINとかCASE WHENとか書いていたので、もしかしたら生クエリの書き方によっては、Active Record経由で期待した通りデータ構造を持つ変数に解釈されないのかもしれない、と。そんなことがあるのかどうか、簡単に調べられそうになかったので、それ以上どうともしがたかった。