Ruby2.2.0とcounter_cacheでハマった
引き続き以下の本をやっていて、
Ruby on Rails 4 アプリケーションプログラミング
- 作者: 山田祥寛
- 出版社/メーカー: 技術評論社
- 発売日: 2014/04/11
- メディア: 大型本
- この商品を含むブログ (3件) を見る
5.6章のカウンターキャッシュのところでハマった。このせいで何時間かロスしたのでメモしておく。
結論から言うと、自分が本で指定されたRubyのバージョンを使っていなかったことが原因です。やれやれ。
事象
本に沿って、UserモデルとReviewモデルのアソシエーションを定義していて、UserモデルにReviewモデルの件数をキャッシュとして持たせた(カウンターキャッシュ)上で、コントローラで@user.reviews.size
にアクセスしたら NoMethodError undefined method `name' for nil:NilClass が発生した。
user.rb
class User < ActiveRecord::Base ... has_many :reviews ... end
review.rb
class Review < ActiveRecord::Base ... belongs_to :user, counter_cache: true ... end
record_controller.rb
class RecordController < ApplicationController ... def cache_counter @user = User.find(1) render text: @user.reviews.size end ... end
原因
RubyとRailsが特定のバージョンのときに発生するActiveRecordのhas_cached_counter?
のバグのようす。
以下らへんを参考にした。
- has_many NoMethodError: undefined method `name' for nil:NilClass -- on the ActiveScaffold column · Issue #380 · activescaffold/active_scaffold · GitHub
- Ruby 2.2.0 and ActiveRecord 4.1.0 bug · Issue #31 · hyperoslo/mingle · GitHub
- ruby on rails - create with has_many through association gets NoMethodError (undefined method `name' for nil:NilClass) - Stack Overflow
- Version bump of ActiveRecord gem needed for Ruby 2.2 · Issue #18991 · rails/rails · GitHub
リンク先によると、解決するには、Rubyを2.2のままにするならRailsを4.1.2まで上げる。あるいはRailsを4.0系のままにするならRubyを2.1.1まで下げる、ということが書かれている。
読んでる本では
を使用していて、バージョンが違うとエラーが起きる可能性があると親切に書いてくれてあるにも関わらず、自分は
を使用していた。つまり本の言いつけを守らず新しいバージョンのRubyを使っていたことが原因。ちなみに、Railsも最新版を使っていれば(少なくともここでは)エラーにならなかったみたいなので、中途半場にRailsだけ言われた通りのバージョンを使っていたことが仇になった感。
対策
ちゃんと本の指定通りのバージョンにする。
今のバージョンを確認。
$ ruby -v ruby 2.2.0p0 (2014-12-25 revision 49005) [x86_64-darwin14] $ rails -v Rails 4.0.2
rbenvでRuby 2.0.0をインストールする。
# インストール可能なバージョン一覧を表示 $ rbenv install -l # 2.0.0の最新版をインストール $ rbenv install 2.0.0-p598 # インストールされたことを確認 $ rbenv versions system 2.0.0-p598 * 2.2.0
localを指定して、プロジェクトで使用するRubyを2.0.0に切り替え。
$ rbenv local 2.0.0-p598 $ ruby -v ruby 2.0.0p598 (2014-11-13 revision 48408) [x86_64-darwin14.3.0]
サーバを起動。
$ rails s rbenv: rails: command not found The `rails' command exists in these Ruby versions: 2.2.0
と思ったらrailsが無いって怒られた。gemはRubyのバージョンごとに入れないといけないのか。考えればまぁそうか。
railsを入れる。本の指定通りバージョンは4.0.2。
$ gem install rails -v 4.0.2 $ bundle install $ rails -v Rails 4.0.2
改めてサーバを起動。
$ rails s
で、ブラウザを再読み込みしてみると、ちゃんと@user.reviews.size
の値が表示された。サーバの出力を見ても、reviewsテーブルにはSQL発行してないし、キャッシュも動いてるようす。
まとめ
バージョンには気をつけようと思った。(月並み)