読者です 読者をやめる 読者になる 読者になる

light log

学んだこととか

Ruby2.2.0とcounter_cacheでハマった

引き続き以下の本をやっていて、

Ruby on Rails 4 アプリケーションプログラミング

Ruby on Rails 4 アプリケーションプログラミング

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

原因

RubyRailsが特定のバージョンのときに発生するActiveRecordhas_cached_counter?のバグのようす。

以下らへんを参考にした。

リンク先によると、解決するには、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発行してないし、キャッシュも動いてるようす。

まとめ

バージョンには気をつけようと思った。(月並み)