Partials and Helpers
The review card on the book page and the review card on a member's profile should look identical. So should the book form on the "new" and "edit" pages. Views have two tools for not repeating yourself: partials for chunks of HTML, and helpers for small bits of Ruby logic.
The rule
Repeat HTML → a partial; repeat logic → a helper.
A partial is a template whose file name starts with an underscore:
<%# app/views/reviews/_review.html.erb %>
<article class="review">
<p><%= stars(review.rating) %> by <%= review.member.name %></p>
<p><%= review.body %></p>
<small><%= time_ago_in_words(review.created_at) %> ago</small>
</article>Render it without the underscore:
<%= render "reviews/review", review: @review %> <%# one, passing a local %>
<%= render @book.reviews %> <%# a whole collection %>
<%= render @review %> <%# one record, by convention %>render @book.reviews looks at the class, finds reviews/_review.html.erb, and renders it once per review with a local variable named review. If the collection is empty it returns nil, so <%= render(@book.reviews) || "No reviews yet" %> handles both cases.
Inside a partial, use locals (review), not instance variables (@review). Then the partial works wherever it is rendered.
A helper is a method available in every view. Rails ships many:
<%= link_to "Edit", edit_book_path(@book) %>
<%= number_to_currency(@book.price) %> <%# $12.50 %>
<%= pluralize(@book.reviews.size, "review") %> <%# 1 review, 3 reviews %>
<%= truncate(review.body, length: 80) %>
<%= time_ago_in_words(review.created_at) %>Your own go in app/helpers:
# app/helpers/reviews_helper.rb
module ReviewsHelper
def stars(rating)
"★" * rating + "☆" * (5 - rating)
end
endThe shortcut
Look for the same thing twice. Twice the same markup → cut it into a partial, turn @ variables into locals. Twice the same formatting call chain → a helper method.
Spot the repeat
new.html.erbandedit.html.erbcontain the same form.
The trap is a partial that reads @book directly. It silently depends on whichever controller rendered it, and breaks on a page that uses another name.
Drills
Answer fast — trust the rule.
What is the file name for a partial rendered with render "books/card"?
Inside reviews/_review.html.erb, what does <%= render @book.reviews %> provide for each item?
Which built-in helper turns 3 into "3 reviews" and 1 into "1 review"?
A partial should work on several pages. What should it read its data from?
Remember
- Repeat HTML → a partial; repeat logic → a helper.
- Shortcut: same thing twice → extract it; @ variables become locals.
- Trap: partials that depend on a controller's instance variables.
