Rendering Collections in Rails

Joël Quenneville

Partials are a great way to break down complex view into more manageable chunks as well as keeping view code DRY. However, rendering a partial for each item in a collection looks ugly:

<% @user.comments.each do |comment| %>
  <%= render partial: 'comments/comment', locals: { comment: comment } %>
<% end %>

Partial paths

Luckily, Rails gives us this beautiful shorthand syntax:

render @user.comments

How does this magic work? Under the hood, render calls to_partial_path on each of our objects to determine which partial to render. Models that inherit from ActiveRecord::Base will return a partial name based on the model’s name by default. For example:
# => 'users/user'

You can override this:

class User < ActiveRecord::Base
  def to_partial_path


This works with plain old Ruby objects too. Here’s a Null Object Pattern example:

class Guest
  def name

  def to_partial_path

@dashboard.users_online is a mix of ActiveRecord User objects and non-persisted Guest objects:

  <h1>Users online:</h1>
  <%= render @dashboard.users_online %>

The same partial is used for both guests and registered users:

  <%= %>

Heterogeneous collections

It gets even better. The objects in the collection can be of different types, each with their own partial.

@user.favorites can contain any combination of Article, Comment, and Image objects:

<h1><%= %>'s Favorites</h1>
<%= render @user.favorites %>


<h1><%= %></h1>
<p><%= article.content %></p>


  <div class="comment">
   <em>Last updated: <%= comment.updated_at %></em>
   <p><%= comment.content %></p>


  <h1><%= image.title %></h1>
  <%= image_tag image.url %>

The beauty of this polymorphic approach is that we don’t have to write any conditional code. As long as all the objects in the collection define to_partial_path, it all just works.

What’s next

If you found this useful, you might also enjoy: