Using Blocks in your Helpers
July 5th, 2007
Helpers are a great way to keep your views DRY. Sometimes, however, it's difficult to make a particular helper flexible enough for reuse. You may have common parts with varying content. Rather than ending up with a bunch of slightly altered helpers, try using blocks to clean things up.
For example, I use this markup a lot:
<div class="field">
<label for="person_name">Name</label>
<%= text_field :person, :name %>
</div>
Now, I could create a helper to do this giving me the following:
<%= form_field :text, :person, :name %>
I would have the helper figure out that I need a 'text' field with the person's name showing. The problem comes when I need to add a new field. I don't want to have to alter my helper each time I want to use a new field.
So - how about this:
<% form_field "Name" do %>
<%= text_field :person, :name %>
<% end %>
Much better! Here I can add any type of field I want or add additional information if needed but still managing to removing repetition of the common wrapper.
Here's the helper code:
def form_field(label, &proc)
concat("<div class=\"field\"><label>#{label}</label>", proc.binding)
yield
concat("</div>", proc.binding)
end
Now, this may look slightly odd. Because we are within a code block, we cannot simply return a string of content. Instead, the output must be appended to the view output. proc.binding gives us the context outside of our code block. The concat helper is used to append our content the output buffer in the correct context. The best way I've heard it explained is to think about 'proc.binding' as the actual HTML and the first argument as the content you want to append to it.
For more inspiration, check out the Rails form helpers.
1 Response to “Using Blocks in your Helpers”
Sorry, comments are closed for this article.

July 6th, 2007 at 02:11 PM
Stephen,
This is a great tutorial on using Blocks in your helpers, I'm always stumbling on the 'proc.binding' step.
The example you've given here would also make a great tutorial on extending FormBuilder, which would allow you to do something like this in your view:
<% form_for :person, :builder => LabelFormBuilder do |f| %> <%= f.text_field :name %> <%= f.textfield :emailaddress %> <% end %>
The FormBuilder would then wrap the text_field method to add your formatting, such as the div and label tags.