iwantcoding.com
🔥 Daily 👥 Rooms 🏆 Top Log in Sign up

Views & ERB

Rails views are ERB / HAML templates that render the response. Mastering helpers, partials, layouts, and content_for keeps the markup DRY and the controllers thin. Modern Rails pairs the view with Turbo Frames and Stimulus for SPA-feel without leaving the framework.

ERB templates, partials, layouts, Turbo Frames

EXAMPLE
# 1) Layout — wraps every view rendered by a controller
# app/views/layouts/application.html.erb
<!DOCTYPE html>
<html lang='en'>
<head>
  <meta charset='utf-8'>
  <title><%= content_for(:title) || 'Shop' %></title>
  <%= csrf_meta_tags %>
  <%= csp_meta_tag %>
  <%= stylesheet_link_tag 'application', 'data-turbo-track': 'reload' %>
  <%= javascript_importmap_tags %>
</head>
<body>
  <%= render 'shared/nav' %>
  <%= yield :flash %>
  <main class='container'>
    <%= yield %>
  </main>
  <%= render 'shared/footer' %>
</body>
</html>

# 2) Action view — sets the title for the layout
# app/views/orders/index.html.erb
<% content_for :title, 'Orders' %>

<h1>Orders</h1>

# 3) Partials — _underscore prefix, rendered with render
# app/views/orders/_order_row.html.erb
<tr id='<%= dom_id(order) %>'>
  <td><%= link_to order.id, order %></td>
  <td><%= order.customer.name %></td>
  <td><%= number_to_currency(order.total_aud) %></td>
  <td><%= order.status %></td>
</tr>

# Render a single partial
# app/views/orders/show.html.erb
<%= render 'order_row', order: @order %>

# Render a COLLECTION (convention: views/orders/_order.html.erb)
<%= render @orders %>
# Equivalent to:
# <% @orders.each do |o| %><%= render 'order', order: o %><% end %>

# 4) Helpers — define in app/helpers/orders_helper.rb
module OrdersHelper
  def order_status_badge(order)
    color = { 'new' => 'gray', 'paid' => 'green', 'shipped' => 'blue', 'cancelled' => 'red' }[order.status]
    content_tag(:span, order.status, class: "badge badge-#{color}")
  end
end

# Use in any view that the OrdersController renders
# <%= order_status_badge(@order) %>

# 5) Form helpers (form_with) — Rails 7+ uses Turbo by default
# app/views/orders/_form.html.erb
<%= form_with model: order, local: false do |f| %>
  <% if order.errors.any? %>
    <div class='alert'>
      <%= pluralize(order.errors.count, 'error') %> stopped the save:
      <ul>
        <% order.errors.full_messages.each do |m| %>
          <li><%= m %></li>
        <% end %>
      </ul>
    </div>
  <% end %>

  <%= f.label :customer_id %>
  <%= f.collection_select :customer_id, Customer.all, :id, :name %>

  <%= f.label :total_cents %>
  <%= f.number_field :total_cents, min: 0 %>

  <%= f.submit %>
<% end %>

# 6) Turbo Frames — replace a region without a full page reload
# app/views/orders/_card.html.erb
<%= turbo_frame_tag dom_id(order) do %>
  <h3><%= order.customer.name %></h3>
  <%= link_to 'Edit', edit_order_path(order) %>
<% end %>

# When you click the Edit link, Rails fetches the response and replaces
# the frame contents in place. Set the responding controller to render
# the same turbo_frame_tag id.

# 7) Turbo Streams — broadcast list mutations
# app/views/orders/create.turbo_stream.erb
<%= turbo_stream.prepend 'orders' do %>
  <%= render @order %>
<% end %>

# 8) Content blocks and yield
# Layout has  <%= yield :sidebar %>
# Inside a view:
# <% content_for :sidebar do %>
#   <%= render 'orders/sidebar' %>
# <% end %>

# 9) Caching expensive partials
# <% cache @order do %>
#   <%= render 'order_card', order: @order %>
# <% end %>
# Russian-doll caching: a parent cache_key changes when a child does.

# 10) Common pitfalls
# - Business logic in the view (move to model / helper / decorator)
# - N+1 queries — use includes() in the controller; verify with the bullet gem
# - Forgetting Turbo and writing tons of JS
# - Not escaping output — Rails default IS safe, but raw / html_safe disable it
# - Long ERB files; break into partials at the first sign of nesting

Why it matters

Render collections with `render @orders` — it auto-picks the partial named `orders/_order.html.erb` and is heavily optimised. The convention makes view code shorter, prevents per-row partial duplication, and unlocks Russian-doll caching with zero extra config.

Tip: Tweak the snippet with Try it Yourself », then sit the quiz at the bottom of the page.

Example

Example
<%# app/views/posts/show.html.erb %>
<h1><%= @post.title %></h1>
<p><%= @post.body %></p>
Try it Yourself »

Discussion

Loading…