DEV Community

Tsubasa Namatame
Tsubasa Namatame

Posted on

[Rails] Comparing the Performance of ViewComponent and Partial

There's a lot of information out there about Rails' partial, with some claiming it degrades performance, while others argue that in production environments the impact isn't significant. There are also views suggesting that using view_component can enhance performance, but again, opinions vary. I was unsure which information was accurate, so I decided to conduct some measurements.

Testing Methodology

  • Output the same content using direct coding, partial, partial with collection, and view component
  • Measure performance in a development environment
  • Measure performance in a production environment

Environment Setup

$ ruby -v
ruby 3.0.0p0 (2020-12-25 revision 95aff21468) [x86_64-linux]
$ rails -v
Rails 6.1.3.1
Enter fullscreen mode Exit fullscreen mode
# Gemfile
gem "view_component", require: "view_component/engine"
Enter fullscreen mode Exit fullscreen mode
$ bundle install
$ rails g controller samples vanilla partial partial_collection view_component
$ rails g model sample name:string
$ rails db:migrate
Enter fullscreen mode Exit fullscreen mode
# app/controllers/samples_controller.rb
class SamplesController < ApplicationController
  before_action :build_samples
  def vanilla
  end

  def partial
  end

  def partial_collection
  end

  def view_component
  end

  def build_samples
    @samples = Sample.all
  end
end
Enter fullscreen mode Exit fullscreen mode
# db/seed.rb
100.times do |n|
  Sample.create!(name: "user#{n}")
end
Enter fullscreen mode Exit fullscreen mode
$ rails db:seed
Enter fullscreen mode Exit fullscreen mode

vanilla

# app/views/samples/vanilla.html.erb
<% @samples.each do |sample| %>
  <p><%= sample.name %></p>
<% end %>
Enter fullscreen mode Exit fullscreen mode

partial

$ touch app/views/samples/_hoge.html.erb
Enter fullscreen mode Exit fullscreen mode
# app/views/samples/_hoge.html.erb
<p><%= hoge.name %></p>
Enter fullscreen mode Exit fullscreen mode
app/views/samples/partial.html.erb
<% @samples.each do |sample| %>
  <%= render 'hoge', hoge: sample %>
<% end %>
Enter fullscreen mode Exit fullscreen mode

partial(collection)

# app/views/samples/partial.html.erb
<%= render partial: 'hoge', collection: @samples, as: 'hoge' %>
Enter fullscreen mode Exit fullscreen mode

view_component

$ rails g component Hoge hoge
Enter fullscreen mode Exit fullscreen mode
# app/components/hoge_component.rb
class HogeComponent < ViewComponent::Base
  def initialize(hoge:)
    @hoge = hoge
  end
end
Enter fullscreen mode Exit fullscreen mode
# app/components/hoge_component.html.erb
<p><%= @hoge.name %></p>
Enter fullscreen mode Exit fullscreen mode
# app/views/samples/hoge_component.html.erb
<% @samples.each do |sample| %>
  <%= render(HogeComponent.new(hoge: sample)) %>
<% end %>
Enter fullscreen mode Exit fullscreen mode

https://github.com/nyshk97/partial-view-components

Measurements

Accessed samples/vanilla, samples/partial, and samples/view_component, and checked the following parts of the log.

Image description

Local Environment

Accessed each 5 times and recorded the median value.

Result
vanilla 8.7ms
partial 23.3ms
partial_collection 8.5ms
view_component 9.2ms

Production

Accessed each 11 times and recorded the median value.
The server used was Heroku.

Result
vanilla 5.3ms
partial 10.7ms
partial_collection 4.45ms
view_component 5.55ms

Summary and Thoughts

  • In both local and production environments, using view_component with each loop offers about twice the performance compared to partial.
    • Conversely, if calling partial 100 times only doubles the time, perhaps there's no need to be overly concerned with calling it 5 or 10 times?
    • In this test, the same partial was called 100 times, but the result might differ if different partials are called.
  • In both local and production environments, partial_collection performed better than direct coding.
    • With direct coding, the execution is linear without considering the number of items. In contrast, using render collection seems to perform better in terms of string generation cost, as it counts the number of items first and then

Top comments (0)