Rails Partials and Collections — Reusable View Rendering
In this tutorial, you will learn about Rails Partials and Collections. We cover key concepts, practical examples, and best practices to help you master this topic.
Rails partial collections render an array of objects using a shared partial template, supporting collection Caching, spacer templates, and automatic counter variables.
What You'll Learn
By the end of this tutorial, you'll render partial collections, use collection caching, implement spacer templates, group collection items, and optimize collection rendering.
Why Collections Matter
Rendering collections with partials is more efficient than manual iteration. Collection caching with :cached option dramatically reduces rendering time for repeated views.
Real-World Use
A product listing page renders @products collection with cached partials. The first request renders 50 products, but subsequent requests serve cached fragments without re-rendering.
Collections Path
flowchart LR
A[Rails Views] --> B[Partials Collections]
B --> C[Render Collection]
B --> D[Collection Caching]
B --> E[Spacer Templates]
B --> F[Grouping]
B --> G{You Are Here}
style G fill:#f90,color:#fff
Basic Collection Rendering
Render a collection with a partial.
<%# views/products/index.html.erb %>
<h1>Products</h1>
<!-- Full syntax -->
<%= render partial: "product", collection: @products %>
<!-- Shorthand (infers partial name from model) -->
<%= render @products %>
<!-- With locals -->
<%= render partial: "product", collection: @products, locals: { show_price: true } %>
<!-- With a different variable name -->
<%= render partial: "product", collection: @products, as: :item %>
Counter and Iteration Variables
Access collection metadata in partials.
<%# views/products/_product.html.erb %>
<tr class="<%= product_counter.even? ? "even" : "odd" %>">
<td><%= product_counter + 1 %></td>
<td><%= product.name %></td>
<td><%= number_to_currency(product.price) %></td>
<td>
<% if product_iteration.first? %>
<span class="badge bg-primary">New</span>
<% end %>
<% if product_iteration.last? %>
<span class="badge bg-info">Last</span>
<% end %>
</td>
</tr>
Collection Caching
Cache each partial fragment individually.
<%# views/products/index.html.erb %>
<h1>Products</h1>
<!-- Cache each product partial -->
<%= render partial: "product", collection: @products, cached: true %>
<!-- Or with the shorthand -->
<%= render @products, cached: true %>
<%# views/products/_product.html.erb %>
<% cache product do %>
<div class="product-card">
<%= image_tag product.thumbnail if product.thumbnail.attached? %>
<h3><%= link_to product.name, product %></h3>
<p><%= number_to_currency(product.price) %></p>
<%= render "reviews/summary", product: product %>
</div>
<% end %>
Spacer Templates
Add separators between rendered items.
<%# views/products/index.html.erb %>
<%= render partial: "product", collection: @products, spacer_template: "product_separator" %>
<%# views/products/_product_separator.html.erb %>
<hr class="product-divider">
Empty Collections
Handle empty collections gracefully.
<%# views/products/index.html.erb %>
<%= render @products, cached: true %>
<% if @products.empty? %>
<div class="empty-state">
<h2>No products yet</h2>
<p>Be the first to add a product!</p>
<%= link_to "Add Product", new_product_path, class: "btn btn-primary" %>
</div>
<% end %>
Common Mistakes
1. Forgetting Cached: True for Large Collections
Rendering 100+ items without caching creates slow pages. Always use cached: true.
2. Overriding As Without Updating Counter Variable
Render with as: :item changes the counter to item_counter. Update references accordingly.
3. Using Each Instead of Render Collection
Manual iteration with each cannot use collection caching.
4. Missing Cache Keys
cached: true requires each partial to have a cache block around its content.
5. Not Handling Empty Collections
Render returns empty string for empty collections. Explicit empty state is better UX.
Practice Questions
1. How do you render a collection with cached partials?
<%= render partial: "product", collection: @products, cached: true %>
2. What are counter variables in collection partials?
model_counter (0-indexed position) and model_iteration (with first?, last?, etc.).
3. What is a spacer template?
A partial rendered between each element in a collection.
4. How does cached: true speed up rendering?
It caches each partial fragment individually by its cache key. Cached items skip rendering.
5. Challenge: Render a cached product grid with spacer.
<%= render partial: "product_card", collection: @products, cached: true, spacer_template: "grid_gap" %>
<% if @products.empty? %>
<p>No products available.</p>
<% end %>
FAQ
Mini Project: Cached Product Grid
Build a product grid with collection caching.
<%# products/index.html.erb %>
<div class="product-grid">
<%= render partial: "product_tile", collection: @products, cached: true %>
</div>
<%# products/_product_tile.html.erb %>
<% cache product_tile do %>
<div class="tile">
<%= link_to product_path(product_tile) do %>
<%= image_tag product_tile.thumbnail if product_tile.thumbnail.attached? %>
<h4><%= product_tile.name %></h4>
<p><%= number_to_currency(product_tile.price) %></p>
<% end %>
</div>
<% end %>
What's Next
Rails Models Deep Rails ActiveRecord Deep Rails Views Deep
Built by the developers of DodaTech
Doda Browser, DodaZIP & Durga Antivirus Pro