How To Render A Collection with Partials

Aug 15, 2006

A common task in Rails apps is to display a collection of database records in tabular form. While the most straight forward way to do this is just to iterate over your collection with a for .. in loop there is an easier and cleaner way with partials.

So let’s say you’re tracking gophers and keeping your records in a database table called appropriately, gophers, because following Rails conventions makes things easier. So before considering using partials you might do something like this:

In the controller:

@gophers = Gopher.find(:all)

In the view:

<table>
  <tr>
    <th>Color</th>
    <th>Weight</th>
  </tr>
  <% for gopher in @gophers %>
  <tr>
    <td><%= gopher.color %></td>
    <td><%= gopher.weight %></td>
  </tr>
  <% end %>
</table>

So while not messy in this simple case, as you need to include more complicated display logic it will begin to get messy and hard to look at. A common solution is just to extract the entire table out into a partial, which is nothing more than adding a new file and a copy/paste. But Rails allows you do something special when you render a partial and want to pass a collection as the local variable.

So first let’s change our view to this:

<table>
  <tr>
    <th>Color</th>
    <th>Weight</th>
  </tr>
  <%= render(:partial => "gopher_list", :collection => @gophers) %>
</table>

Next let’s add file called _gopher_list.rhtml for our partial.

<tr>
  <td><%= gopher_list.color %></td>
  <td><%= gopher_list.weight %></td>
</tr>

The important thing to note is that one, our for loop is gone, and two, we have to call our local variable the same name as the partial. In this case, it’s “gopher_list”. This isn’t spelled out very clearly in the Rails docs and can cause some headaches if you miss it.

The nice thing is that now Rails will just render our partial for each gopher object rather than us having to worry about iterating over it ourselves. And if you have to display this table list in many places you’ll save a ton of time through using a single partial.