development と production での挙動の違い

rails2.3.11 の production ではクラスメソッドがキャッシュされてるせいか(違うかも)
一部挙動が違って死にそうになったので、メモっておきます。

環境

ruby 1.8.7
rails 2.3.11

テストプロジェクト作成

rails hoge
cd hoge
script/generate scaffold list name:string
rake db:migrate
RAILS_ENV=production rake db:migrate
vim app/controllers/lists_controller.rb
vim app/views/lists/index.html.erb

  • app/controllers/lists_controller.rb
#  サンプルなんでこの位置でモジュールを定義してますが、本当は lib の中とかでします。
module M
  class << self
    attr_accessor :x
  end

  def x
    M.x ||= rand
    #@x ||= rand
  end
end

class ListsController < ApplicationController
  include M
  helper_method :x

  # GET /lists
  # GET /lists.xml
  def index
    @x = 30

〜省略〜
  • app/views/lists/index.html.erb
x = <%= x %><br />
@x = <%= @x %><br />

〜省略〜

動かしてみる

script/server
RAILS_ENV=production script/server

それぞれのモードで鯖を起動して http://localhost:3000/lists を開きます。


development では x = の方は毎回値が変わるのに、production では x = の値は変わりません。
びっくり!!!!!!!!!!!!!!!!!

  • app/controllers/lists_controller.rb
module M
  def x
    @x ||= rand
  end
end

class ListsController < ApplicationController
  include M
  helper_method :x

  # GET /lists
  # GET /lists.xml
  def index

上記のように def x を @x ||= rand に def index の @x = 30 を消して実行すると毎回ページ読み込みのたびに値が変更されてます。


ちなみに production でコードを変更した場合はサーバーを再起動しないとだめです。
このような挙動からproduction 時の最適化とキャッシュ的なものを推測するに

  • 毎回ページを読みこまれるごとに @変数 はクリアされている。
  • クラスメソッドの変数は前回のを使っている(?)

みたいな感じなのかなー?と勝手に思ってます。
ちなみにモジュールで定義した @変数は view では反映されないようです。

なんで @x を使わないで M.x みたいにしてるの?

カプセル化のためですかね?
@x に入れちゃうとコントローラーで、もし @x に再代入してしまうと壊れるまる。


メソッド名と同じ@変数を使っていてコントローラーでそれに別の値を代入してしまった時点でもう色々終わってる気もしますが。。。
まぁ正直精神衛生上的な理由が大きかったりします(きりっ


module M の領域なら安全なので、できるだけコントローラーの変数名の汚染は最小限に留めた方がいいかなーと思ってやってました。


でもそれだと production の時に上手く動かないので @__x__ のように前後に _ を2個付けるべきなんでしょうか?(一応こうしました)
正しいお作法が分かりません;ω;何かアドバイスがあればお願いしまつorz