Block level helpers in Ruby on Rails

Web developer often comes to a situation where he needs to “decorate” a block of a page. There is a simple solution and simple and elegant solution.
Helpers concept in Ruby on Rails is very powerful and will be used to do the trick.

Imagine, you want to create a rounded box helper similar to Nifty Corners (http://www.html.it/articoli/nifty/index.html), but you do not want to use javascript. So, a handy helper needs to be created.
The principle of the Nifty Corners trick is adding few b tags before content, few b tags after it and few lines to CSS.

<div id="container">
<b class="rtop">
  <b class="r1"></b> <b class="r2"></b> <b class="r3"></b> <b class="r4"></b>
</b>
<!--content goes here -->
<b class="rbottom">
  <b class="r4"></b> <b class="r3"></b> <b class="r2"></b> <b class="r1"></b>
</b>
</div>

and modification of CSS

.rtop, .rbottom{display:block}
.rtop *, .rbottom *{display: block; height: 1px; overflow: hidden}
.r1{margin: 0 5px;}
.r2{margin: 0 3px;}
.r3{margin: 0 2px;}
.r4{margin: 0 1px; height: 2px;}
.r1, .r2, .r3, .r4 {background-color:red;}
.cont{background-color:red;}

Easy solution

The easy solution uses two helpers. One to put before the content and one to put it after. So, the view could look like:

...
<%= round_box_start %>
content
<%= round_box_end %>
...

Well, it does not look good. So, what about the other solution?

Easy and elegant solution

We will create a block level helper. The view will look much better.

...
<% round_box do %>
content
<% end %>
...

Now, let’s create the helper:

def round_box(&block)
  b = '<div id="container"><b class="rtop"><b class="r1"></b><b class="r2"></b><b class="r3"></b><b class="r4"></b></b><div class="cont">'
  e = '</div><b class="rbottom"><b class="r4"></b> <b class="r3"></b> <b class="r2"></b> <b class="r1"></b></b></div>'
 
  # Get the data from the block 
  data = capture(&block)
 
  res = b + data + e
 
  # Use concat method to pass text back to the view 
  concat(res, block.binding)
end

Good, but works only for red boxes. How to pass another color? Simply:

...
<% round_box(color) do %>
content
<% end %>
...

and in helper

def round_box(color, &block)
  b = '<div id="container"><b class="rtop"><b class="r1"></b><b class="r2"></b><b class="r3"></b><b class="r4"></b></b><div class="cont">'
  e = '</div><b class="rbottom"><b class="r4"></b> <b class="r3"></b> <b class="r2"></b> <b class="r1"></b></b></div>'
 
  # Get the data from the block 
  data = capture(&block)
 
  res = b + data + e
 
  # Use concat method to pass text back to the view 
  concat(res, block.binding)
end

Final implementation of the colored box is left as a homework :o)

5 Responses to “Block level helpers in Ruby on Rails”

  1. Ryan Bates Says:

    Thanks for posting this. Blocks in helpers is something many people struggle with.

    An alternative to this is to render a partial as a layout. This way you don’t have to put the HTML in ruby strings. See this: http://pastie.caboo.se/188186

    I haven’t tried it, but you could probably pass a :locals hash to specify the color.

  2. Raju Says:

    Thanks for posting this. Great advice.

    @Ryan Bates – I was trying something similar to what you put up on pastie, and locals work just fine. There is the advantage you mentioned in that you don’t have to put HTML code as Ruby Strings.

    render :layout => ‘shared/sidebar’, :locals => { :links => side_links }

    [From The example i was working on]

  3. Roman Mackovcak Says:

    Guys, thanks for your comments. You are right. My example was not perfect. Nevertheless, you made it a valuable post with your additions.

  4. mike nicholaides Says:

    Or, you can just use Better Partials:
    http://www.railsjedi.com/posts/22-Better-Partials-Plugin-for-Ruby-on-Rails

  5. Aladdin With A Lamp » 『Ruby on Rails』|很好很好的资料! Says:

    […] Block level helpers in Ruby on Rails […]