【 jbuilder 】部分テンプレートが遅いの如何せん

マッチングアプリ「CoupLink」の開発担当をしている横山です。

CoupLinkではフロントサイドをVue, バックエンドをRailsで運用しており、サーバー間はjsonでやり取りをしています。

Railsでjsonレスポンスを作成するためのGemとして「jbuilder」を採用しているのですが、その中で使われているpartial template (部分テンプレート) が非常に重たい、という問題を聞いたことがある方もいらっしゃるのではないでしょうか。

100.times do |i|
  json.partial! 'api/no_data'  # no_dataには何も記述していない
end

例えば、上記のように中身の空っぽな ‘no_data’というファイルを100回呼び出すだけでも、応答速度は平均約1000ms ほどでした。(ローカルPCで試しているので、単に性能の問題か…あるいはDockerとの相性の問題か…。どちらにせよ、大分時間が掛かっています。)

そこで、こちらの暫定的な解決策として、partial template をメソッドで置き換えることにしました。

そもそも、json.partial! メソッドの返り値は テンプレートで定義されているデータのハッシュ(のようで厳密には文字列)です。

ですので、テンプレートと同じ内容のハッシュを返すメソッドを用意してあげれば、partial templateに取って代わることが出来ます。

json.merge! メソッドは、ハッシュをJSON文字列のデータに変換して追加してくれます。これをハッシュを返すメソッドに対して使用してあげればいいわけです。

def user_info_hash(user)
  {
    id: user.id,
    name: user.name
  }
end 
----------------------------
user = User.find(1)
json.user_info do
  json.merge! user_info_hash(user)
end

=> {"user_info": { "id": "1", "name": "アリス"} }

このメソッドは、ヘルパーメソッドとして定義したり、あるいは新たにSerializerという専用のディレクトリを作って、そこに配置しても良さそうです。

本番環境の運用では、約300msほど応答速度を短縮できました。デカい…

今回は以上になります。同じケースで困っている方がいたら、是非この方法も検討してみてください。