Using ruby-gettext with Edge Rails
The more I read about the various new features coming up in Rails 2.0, the more I couldn't resist... and finally, a few days ago, I switched over to Edge Rails with my current project.
Switching to Edge Rails was easily done, however after fireing up /script/server
and doing the first request, I was presented with a 500 Internal Server Error.
DISPATCHER FAILSAFE RESPONSE (has cgi) Sun Jul 29 12:43:56 +0200 2007
Status: 500 Internal Server Error
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/lib64/ruby/1.8/cgi.rb:1165:in '\[]'
/usr/lib64/ruby/gems/1.8/gems/gettext-1.10.0/lib/gettext/locale_cgi.rb:26:in 'system'
/usr/lib64/ruby/gems/1.8/gems/gettext-1.10.0/lib/gettext/locale.rb:88:in 'system'
/usr/lib64/ruby/gems/1.8/gems/gettext-1.10.0/lib/gettext/locale.rb:96:in 'default'
After some time of debugging, it turned out to be ruby-gettext, which I use for I18N, that causes a NoMethodError on each request during init-gettext.
What happened here is, that ruby-gettext tries to figure out the current visitor's language by looking for an URL parameter or a cookie named lang or the HTTP Accept header. Looking for the URL parameter seems to be the problem in this case. Locale::SystemCGI.system
calls cgi["lang"]
to look for the URL parameter, but CGI#[]
raises a NoMethodError, because the @params
hash does not contain a key named lang. Here are the first few lines of CGI#[]
(starting at line 1163 in cgi.rb):
def [](key) # cgi.rb:1163
params = @params[key] # nil gets assigned to params
value = params[0] # raises NoMethodError, because params is nil
if @multipart
if value
return value
The solution
The problem could be fixed by patching cgi.rb of the ruby standard library or locale_cgi.rb of ruby-gettext (like somebody with a similar problem suggested in this mail). However this isn't usually applicable on production servers. Instead, you can work around this problem by modifying CGI#[]
from within your rails application temporarily, until the bug is fixed.
With Edge Rails, you don't place your own statements in config/environment.rb anymore. Instead, you can write an initializer file and place it into config/initializers. For ruby-gettext, I created config/initializers/gettext.rb, which contains:
require 'gettext/rails'
To work around the above problem, add the following code to your gettext initializer, right after the require statement:
class CGI
module QueryExtension
alias index_without_fix :[]
def [] (key)
return nil unless @params[key]
index_without_fix(key)
end
end
end
This modifies CGI#[]
to return nil if the requested param does not exist.
Update (2007-10-20): The above problem was fixed in Ruby 1.8.6-p26.
Finally, my application runs with Edge Rails and I can now start to explore all the new stuff (and probably do a lot of refactoring to use those features).
New-style .html.erb templates
Update (2007-07-31): Ruby-gettext is currently unable to recognize new-style .html.erb template files (since it doesn't know that .erb files should be parsed by GetText::ErbParser
). I reported this to Masao, the author of ruby-gettext (so it'll be probably fixed in future versions). Since then, you can work around it by modifying your lib/tasks/gettext.rake like this:
require 'gettext/utils'
# Tell ruby-gettext's ErbParser to parse .erb files as well
# See also https://zargony.com/2007/07/29/using-ruby-gettext-with-edge-rails
GetText::ErbParser.init(:extnames => ['.rhtml', '.erb'])
desc 'Update pot/po files'
task :updatepo do
GetText.update_pofiles('messages', Dir.glob("{app,lib}/**/*.{rb,rhtml,erb,rjs}"), 'MyApp')
end
desc 'Create mo-files'
task :makemo do
GetText.create_mofiles(true, 'po', 'locale')
end
Update (2007-08-01): Masao pointed out, that it's better to use the GetText::ErbParser.init method rather than overriding ErbParser. Thanks Masao.
Update (2008-02-25): .erb files are now parsed by default, so the above fix isn't necessary anymore. Scanning .erb files was added on July 31, 2007 and is included in ruby-gettext 1.90.0 which was released on Feb 02, 2008.