実用性皆無の勉強用でRailsのViewハンドラーを書いてみました。YAMLとERBで記述して、JSONを返すハンドラです。

インストールと使い方

Gemfileにyjを書いてインストールするだけ

使い方はviewファイルを拡張子 json.yjで作成してYAMLとERBでそれっぽく書いていきます。

YAMLがJSONとして解釈されるだけで、内部では MultiJson.dump(YAML.load(source)) を呼び出しています。

こんな感じなレスポンスを返してくれます

patialを使うときは r.(partial: 'partial_template', ...)の形式で呼び出します。内部的にはrenderを呼び出していますが、collectionを指定した場合は、YAMLの配列となるように調整しています。

例えば以下のようなpartialを呼び出すとき、

単体であればこのままJSONで出力すれば良いですが配列の場合は

というようにハイフンとインデントを良い感じに配置したいので、そこを調整しています。

パフォーマンスについて

jbuilderの1.5倍遅いです!w

developmentだと〜3倍程度のパフォーマンスが出ます。以下ベンチマークスクリプトと結果です。

development環境

production環境

ちなみにproductionで1 partialで2.6倍遅いとか言われたので、ERBやYAMLロードのオーバーヘッドが高そうです。

実際stackprofで雑にプロファイリングしてみましたが、ERBがボトルネックになっていそうでした。うむー

jbuilderはオブジェクト経由でハッシュを作成して最後にMultiJson.dumpする方式なので、ERBなどの余計なコストはかからないです。また、yjを作るにあたって

  • モンキーパッチはしたくない
  • N+1 find_template_pathsを避けたい
  • Railsのcollection partial renderingのしくみを使いたい

という無駄なこだわりがあったのですが、ここらへんを解消しつつYAMLのハンドラーで速くするのはちょっと難しかった。

collectionのpartial renderingはArray#join, String#html_safeがかかってくるので、ここをモンキーパッチしないとなると文字列連結で頑張って表現するしかないんですが、yjの場合は一旦JSONに変換してごにょごにょしていて、それも遅さの原因になっていそうです。

ということで実用性皆無のgemが出来上がりましたが、ハンドラー作るに当たってはjbuilderjbやRailsのView周りのコードを読んでとても勉強になりました。