Wednesday, October 3, 2007

Persisting variables between partial calls

In Rails, there are times when you need to preserve the value of a variable across partial renderings. For example, you want a partial to render a row of a table with numbered rows. How do you do that?

Store the value in an instance variable:

<tr>
  <td><%= @row_id = (@row_id || 0) + 1 %></td>
</tr>

The variable will be preserved while the page is being rendered, in an instance of a dynamically created class, subclassed from ActionView::Base (as of Rails 1.1.6 that happened in ActionController::Base.initialize_template_class).

The same variable will be available inside the corresponding helper, since the helper is included as a module of that dynamically created class. So code like the one shown above may be moved to a helper.

Use the trick wisely, though! A variable seen by different files is almost a global variable.

3 comments:

Ryan Bates said...

Alternatively you can use the :locals option to pass variables.

For example, if you need to number the rows, use each_with_index when performing the loop. This way you don't have to keep track of a second counter variable, just pass the index to the partial.

That said, keeping an instance variable definitely has its uses. The "cycle" helper method is a great example of this.

Radarek said...

For "@row_id = (@row_id || 0)" there is idiom in Ruby: @row_id ||= 0.

Romulo said...

Thanks, Ryan.

The cycle method is exactly what I've been investigating before coming up with this post.