Railsで生成するViewの中に作成したJavaScriptでJSONデータを処理する事に結構はまりました。理解してみると何とも単純なことではまっていたと言うことがわかるのですが、初めてのことなのでずいぶん時間がかかりました。
そもそも事の発端は、JavaScriptで作成されたライブラリィでグラフを表示したいと言うことが目的でした。サンプルソースでは問題なく動くけれども、Railsアプリではグラフが表示できない…。
試行錯誤した結果問題となっていたのは以下のことでした。
- JavaScriptが動作するイベントが発火しないともちろん動作しない。
- RailsのViewではテンプレート変数でJSONデータを受け渡しできるけれども、このときJavaScriptでevalする必要はない。
- RubyのHash#to_jsonで生成した文字列をそのまま渡すと動作しない。
それぞれきわめて単純なことですが、なにぶん初めてのことなのですべてが複合的に絡み合っていて解きほぐすのに時間がかかりました。
1.JavaScriptが動作するイベントが発火しないともちろん動作しない。
これはサンプルソースなどではもちろんさらっと書いてあるのですが、自分で動作させるときには忘れてしまってそもそもJavaScriptが動作していない事に気づかず明後日の方向へ進んでしまうことがありそうです。
今回は単純にbodyタグでonloadイベントをコールするようにしました。
[sourcecode language="JavaScript"]
... … <script type="text/javascript">// <![CDATA[ … // ここでイベントに対応するメソッドを作成 function doOnLoad() { … }
// ]]></script>
<!-- イベントの発火 --> body onload="doOnLoad();" [/sourcecode]
2.RailsのViewではテンプレート変数でJSONデータを受け渡しできるけれども、このときJavaScriptでevalする必要はない。
これはそのものずばりで、ずっと JavaScript のevalメソッドをコールしていましたが、テンプレート変数を使用する場合は必要ないようです。もっとも、Ajaxでコントローラーから適宜JSONデータを受信する場合は異なるのかもしれませんが、今のところちょっとわかりません。
3.RubyのArray#to_jsonで生成した文字列をそのまま渡すと動作しない。
これが一番はまりました。データをハッシュとして作成後、それぞれをArrayに詰めてto_jsonメソッドでJSONデータを作成しました。ところが、一見正しく見えるそれらの文字列が実は正しくないと言うことに気づくまでに時間がかかりました。
具体的には、下記のJSONデータは正しくなくJavaScriptでは処理が行われません。
[sourcecode language="JavaScript"] function doOnLoad() { ... // Railsでは次のようにrawメソッドを指定してテンプレート変数を取得 // var data = "";
// ブラウザでは下記のようにデータがセットされた状態で表示 var data = "[{item:"007",value:"17674"},{item:"031",value:"5983"}]"; ... } [/sourcecode]
一方こちらの場合は処理が行われます。
[sourcecode language="JavaScript"] function doOnLoad() { ... // Railsでは次のように raw メソッドを指定してテンプレート変数を取得 // var data = "";
// ブラウザでは下記のようにデータがセットされた状態で表示 var data = "[{item:"007",value:"17674"},{item:"031",value:"5983"}]"; ... } [/sourcecode]
この違いに気づくのにいろいろと試行錯誤しました。何が違うかというと、ブラウザでソース表示を行った際に見える内容で、上の例ではダブルクオートがエスケープされていません。一方下の例ではダブルクオートはエスケープされています。
(当初は raw メソッドを使用していなかったためダブルクオートが \" にサニタイズされてしまっていました。raw メソッドを利用することも必須です。)
またコントローラーの処理も以下のように変更する必要がありました。
[sourcecode language="Ruby"]
もともと
s = ledger_array.to_json
ダブルクオートをエスケープ
s = ledger_array.to_json.gsub(/"/,"\"") [/sourcecode]
このようにすることでJSONデータをJavaScriptで読み込ませることができるようになりました。