実務では絶対に使わないけどrails/jbuilderのpartialレンダリングを無理矢理早くする方法。

partialでviewを使いまわしたい場合、特に1件のときはオブジェクト、複数件は配列を返したい場合、通常は以下のように書きます。

が、これはN+1 partial renderingが発生します。100件くらいの数値配列を出すだけでも遅いです。ログは以下のようにRenderedがたくさん表示されます。

これはpartial!を使うと、collectionのパーシャルレンダリングとして扱われず、renderを複数回呼び出した結果をjbuilder内で連結しており、処理の重いfind_template_pathsがN+1回分呼びだされるためです。

jbuilderファイル内でrenderを直接呼び出すとcollectionのパーシャルレンダリングとして扱われるのでfind_templateも1回だけです。が、オブジェクトの文字列が単純に連結されてしまうので、カンマで無理矢理連結させて配列にした上でJSON.loadすればjbuilderのattibutesに配列としてセットされることになります。

gsubでかなり雑に置換しているのが微妙ですが、これだけでもある程度の高速化が見込めます。

ベンチマーク

以下のスクリプトでベンチマークを取りました。

app/views/api/hoge/slow.json.jbuilder

app/views/api/hoge/fast.json.jbuilder

これをproductionで起動してエンドポイントにアクセスしてベンチマークを取ったところ、2倍くらい性能差が出ました。

stackprofをとったら以下のようになりました。これがpartial!を使ったバージョン

こちらがrenderとgsubでごにょごにょしたバージョン

やはり、find_template_pathsがボトルネックになっています。