RJS Templateが描画されない問題
Ruby on Railsの習熟がてら、簡単なBBSを作ってみたんですよ。で、せっかくだからプレビューをAJAXで出そうぜ、などと思い立った。
# # app/controllers/entries_controller.rb # def preview @entry = Entry.new(params[:entry]) render :update do |page| page.replace_html 'preview', :partial => 'preview' page.visual_effect :highlight, 'preview' end end
これはご機嫌に動いてくれた。画面遷移なしに、かっこいいエフェクトつきでプレビューが表示されるのだ。イカス。
ところで、ここではinline RJSにしているが、RJSがある一定以上の大きさになると、*.rjsといった名前のテンプレートファイルに切り出すのが一般的である。そんなわけで、切り出してみた。
# # app/controllers/entries_controller.rb # def preview @entry = Entry.new(params[:entry]) end
# # app/views/entries/preview.rjs # page.replace_html 'preview', :partial => 'preview' page.visual_effect :highlight, 'preview'
動かないんだ、これが。
FireBugでレスポンスを見てみたが、どちらのケースでも同じ内容を返しているように見える。なぜinlineで動くものがテンプレート化すると動かないのか、さっぱりわからない。
結論から言うと、見ているところが違った。レスポンスヘッダが変わっている。Content-Typeが、inlineだとtext/javascriptなのに、テンプレートだとtext/htmlになっている。text/javascriptでないと動かないのだ。そりゃそうだ。
この原因は、日本語環境向け設定にある。Railsを日本語環境で使う場合、app/controllers/application.rbにちょっとした細工を行うのが普通だ。
before_filter :set_charset def set_charset headers['Content-Type'] = 'text/html; charset=UTF-8' end
ここで、使用する文字コードをUTF-8にしたいがためにContent-Typeヘッダを設定している。この方法は、かのAWDwR本で紹介されているので、まったく同じ実装を行っている人は多いはず。ところが、どうやらRailsは設定値を動的に変えているらしく、この実装だとせっかくRailsが裏で調整した設定を台無しにしてしまう。
そこで、対処。
before_filter :set_charset def set_charset content_type = headers['Content-Type'] || 'text/html' if /^text\// === content_type headers['Content-Type'] = "#{content_type}; charset=UTF-8" end end
基本的にRails任せにしておいて、テキスト形式(text/*)である場合のみ文字コードの設定を追加で行う。これで無事動くようになった。
参考サイトはこちら。
ありがちな問題に思えるのに、なかなか情報が見つからなくて苦戦した・・・。
2007/08/14 追記
こちらのサイトによると、Ruby-Gettext-Packageを使ってローカライズしている場合は、そのパッケージ側で文字コードの設定を実施するそうである。この場合、"Content-Type"の置き換え処理はまるまる不要になる。