LoginSignup
1
1

More than 5 years have passed since last update.

viewでrenderを繰り返し呼ぶと重い?

Last updated at Posted at 2018-05-11

Railsのviewで、eachを回してる中で繰り返しrenderしているところがあって、体感的に特に遅かったわけでは無いのですが、ファイルの読み込みや検索が繰り返し行われてるんじゃ無いかと気になってベンチを取ってみました。

<% Benchmark.bm 10 do |r|%>
  <% r.report "inline" do %>
    <% 1000.times do%>
    <div><%= Time.zone.now.strftime('%Y-%m-%d %H:%M:%S') %></div>
    <%end%>
  <% end %>

  <% r.report "render" do %>
    <% 1000.times do%>
    <%= render 'root/foobar' %>
    <%end%>
  <% end %>

  <% r.report "read" do %>
    <% erb = File.read(Rails.root.join('app', 'views', 'root', '_foobar.html.erb')) %>
    <% 1000.times do%>
    <%== ERB.new(erb).result(binding) %>
    <%end%>
  <% end %>
<% end %>
# app/views/root/_foobar.html.erb
<div><%= Time.zone.now.strftime('%Y-%m-%d %H:%M:%S') %></div>

結果はこんな感じです。

                 user     system      total        real
inline       0.018214   0.000176   0.018390 (  0.021384)
render       0.709417   0.749956   1.459373 (  1.526002)
read         0.095806   0.000444   0.096250 (  0.097051)

renderはsystemに非常に時間がかかってるので、毎回ファイルを読み込んでいそうです。試しにキャッシュして読み込むメソッドを作ってみた。

# app/helpers/application_helper.rb
  def render_erb_with_cache(path, locals = {})
    erb = Rails.cache.fetch "#{path}@render_erb_with_cache" do
      # ActionView::LookupContextでテンプレートを見つける。
      lookup_context = ActionView::LookupContext.new('app/views')

      # 3番目の引数は`partial`でこれをtrueにするとファイル名に`_`を付与して探します。
      # 返り値はActionView::Template
      template_path = lookup_context.find_template(path, [], true, [], {})
      # sourceアトリビュートで内容が取得可能。
      template_path.source
    end

    # renderする
    render(inline: erb, locals: locals)
  end
1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1