gettext/rails が動かない
結論から言うと、Ruby の cgi の仕様と、Rails の cgi の仕様がミスマッチを起こしているようです。Ruby のバージョンアップ(1.8.6-p26以上)をすることで解決できます。Rubyのバージョンアップなんてやだよ!な人は原因に関しては続き参照してしかるべき対処を。
rescue_action_locally を呼び出しているところで、render_file を呼び出しているわけだが、再度Exceptionが投げられてしまう。
You have a nil object when you didn't expect it! You might have expected an instance of ActiveRecord::Base. The error occurred while evaluating nil.[] /usr/local/lib/ruby/1.8/cgi.rb:1166:in `[]' /usr/local/lib/ruby/gems/1.8/gems/gettext-1.10.0/lib/gettext/locale_cgi.rb:26:in `system' /usr/local/lib/ruby/gems/1.8/gems/gettext-1.10.0/lib/gettext/locale.rb:88:in `system' /usr/local/lib/ruby/gems/1.8/gems/gettext-1.10.0/lib/gettext/locale.rb:96:in `default' /usr/local/lib/ruby/gems/1.8/gems/gettext-1.10.0/lib/gettext/rails.rb:276:in `render_file'
該当は、gettext/rails で再定義しているrender_fileのここ。
[locale.to_general, locale.to_s, locale.language, Locale.default.language].each do |v|
ここでqueryやheaderに何もLocale情報を渡さなかった場合に local.default が呼び出されているわけだが、locale.rb には
def default @@default ? @@default : system end
とある。しかし、ここは問題がなさそうで、local_cgi.rb の
if ret = cgi_["lang"] and ret.size > 0
が例外発生元。cgi_["lang"] が悪いらしい。cgi.rb を見ると、
def [](key) params = @params[key] value = params[0] ...
となっており、value = params[0] が The error occurred while evaluating nil.[] を発生させている。ん?と思って、cgi.rb をよく読む。こんな記述がある。
# For instance, suppose the request contains the parameter # "favourite_colours" with the multiple values "blue" and "green". The # following behaviour would occur: # # cgi.params["favourite_colours"] # => ["blue", "green"] # cgi["favourite_colours"] # => "blue" # # If a parameter does not exist, the former method will return an empty # array, the latter an empty string. The simplest way to test for existence # of a parameter is by the #has_key? method.
つまり、cgi["lang"]で例外が発生する方がおかしい。まず、Rails 1.2.3 と 2.0.2 で
puts cgi.has_key?("lang") puts cgi["lang"]
をして、langキーがないときに、Rails 2.0.X でのみnil例外が発生することを確認。なんでやねん!、というわけで、Railsデバッグ開始。どうも、Rails 2.0 でQueryExtensionによるinitizlie_query()が上書きされているのがあやしい。@params を初期化する重要なメソッド。
Rails 2.0 による initialize_query()
def initialize_query # Fix some strange request environments. env_table['REQUEST_METHOD'] ||= 'GET' # POST assumes missing Content-Type is application/x-www-form-urlencoded. if env_table['CONTENT_TYPE'].blank? && env_table['REQUEST_METHOD'] == 'POST' env_table['CONTENT_TYPE'] = 'application/x-www-form-urlencoded' end @cookies = CGI::Cookie::parse(env_table['HTTP_COOKIE'] || env_table['COOKIE']) @params = {} end
で、cgi.rb の initialize_query()
def initialize_query() if ("POST" == env_table['REQUEST_METHOD']) and %r|\Amultipart/form-data.*boundary=\"?([^\";,]+)\"?|n.match(env_table['CONTENT_TYPE']) boundary = $1.dup @multipart = true @params = read_multipart(boundary, Integer(env_table['CONTENT_LENGTH'])) else @multipart = false @params = CGI::parse( case env_table['REQUEST_METHOD'] when "GET", "HEAD" if defined?(MOD_RUBY) Apache::request.args or "" else env_table['QUERY_STRING'] or "" end when "POST" stdinput.binmode if defined? stdinput.binmode stdinput.read(Integer(env_table['CONTENT_LENGTH'])) or '' else read_from_cmdline end ) end @cookies = CGI::Cookie::parse((env_table['HTTP_COOKIE'] or env_table['COOKIE'])) end
ん、GETの挙動が違う。。cgi.rb の CGI::parse では、Hash.new([].freeze)で初期化しているハッシュなのでキーがない場合は空の配列を返す。Rails 2.0のほうは {} で初期化しているだけなので、cgi["key"] すると必ず例外が起こるようだ。Railsが悪いように見える。
で、Rails と GetText/Rails のどっち直そうかなぁと思ったところでググる。
http://ko.meadowy.net/~nay/?Rails2.0.1%A5%E1%A5%E2
う。おおばさん。
GetText で 500 Internal Server Error
が出た。むとう様に情報をいただいて解決。Ruby 1.8.6 p26 より前で出る現象だった。Ruby のバージョンアップで解決。
* http://d.hatena.ne.jp/craccho/20071210
* http://zargony.com/2007/07/29/using-ruby-gettext-with-edge-rails/
あれ、1.8.6-p26 で解決するのかい。ここまできたら、直したやつみないと気が済まないので、http://svn.ruby-lang.org/cgi-bin/viewvc.cgi/tags/v1_8_6_26/lib/cgi.rb?revision=12340&view=markup を参照すると、
def [](key) params = @params[key] return '' unless params
ruby-dev(http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-dev/30740)にはエラーになるとあるんだが。@params をちゃんと Hash.new([].freeze)でキーが存在しない場合のデフォルトを与えたHashにしてあげればエラーにならない気がする。cgi.params["key"] = nil の場合は想定してないのかな?
まぁ、うだうだいってても先に進まないので、とりあえず、Ruby 1.8.6-p26以降にする、という形にした。