So you heard of Ruby On Rails (RoR), watched a 15 minutes screencast. And you kind of liked it. You tried coding ‘Hello world’, and you said, “Hey, this is easy”. You thought you should push yourself and try out a more complicated stuff, stuff real developers do.

You wanted to create a few standard panels on your home page, because almost every site you visited lately have panels on their homepage. You wanted each panel to have its own header and footer, probably something like this:

  <div class="panel">
    <div class="header">Panel Name</div>
    <div class="body">Some content here....</div>
    <div class="footer">Panel Footer</div>
  </div>

And you did it real fast, you were done with 6 panels, 2 on each column for a 3-column layout in 2 minutes. But… hm… you did not like your codes, because you see a lot of repeated <div> elements.

You remembered Ruby programming language advocates Don’t repeat yourself. You are a smart guy, you found a solution in no time, “Why not create a helper ‘panel’ method?”“. Then you can do something like this in your RHTML template file.

  <% panel (:header => 'Panel header', :footer => 'Panel footer') do %>
       Some content here...
  <% end %>

That surely looks more beautiful than the codes above. You started to love RoR even more, but… when you tried to create the helper method, you bumped into some problems.

   class ControllerHelper
       def panel(options={}, &proc)
           # How to add panel header <div>s?
           
           # Generate content
           yield 

           # How to add panel footer <div>s?          
       end
   end

You were a Java web developer, your first instinct is to find the response outputstream. You found the closest match, 'response.out' but it did not return the template output, instead it passed you a standard output.

You read about render :text or render :inline, you tried them too, but they throwed an error saying that you should not call render statement more than once.

You asked uncle Google for ‘rails response outputstream’ and you tried other questions too, but you could not find an answer.

You were getting frustrated, but you thanked God that people still use Internet Relay Chat (IRC) these days, and you found #rubyonrails channel flooded with people. You asked your question, but no answer, you asked again, and again, no answer. Frustrated, tired, and dehydrated, you started to hallucinate that you probably was a ghost, you saw your own message, but others did not.

It got nasty this time, you started screaming words you did not want your mum to hear, ‘WTF’, @#%@$%^*!!!.

And your did not love RoR anymore.

By luck, fate, chance or whatever it was, you probably found this page, coz there was another guy like you, faced a similar issue, he found a solution, and he shared his solution. He said you probably want to do it this way:

class ControllerHelper
     def panel(options={}, &proc)
          # add panel header to current template IO stream
           concat("<div class='panel'><div class='header'>#{options[:header]}</div><div class='body'>", proc.binding)
           
           # Generate content
           yield 

          # add panel footer to current template IO stream
           concat("</div><div class='footer'>#{options[:footer]}</div></div>", proc.binding)
       end
end

And it worked like magic, you started to read more about ActionView::Helpers::TextHelper#concat, more about Binding, and you started to understand that RoR behaves differently in this aspect, coz the RHTML template file is compiled by ERB library, and concat method helps you to retrieve the RHTML output sting buffer through the ‘Binding’ object and the variable _erbout.

Shortly after, you understood more about Ruby and RoR, and your love for Ruby and RoR started to grow again. You called it a day, a happy man because you found a solution to your problem.

You promised yourself that you would want to share solutions to problems you are facing in the future, just like what that guy did. And you hoped for a better world, a world where less of us have to say words our mum would not like to hear.

5 Comments . Comments Feed . Trackback URI
Wed, 7 Feb 07 07:00 pm . Harro! wrote:

Hey Herry, I know RoR is way cool. But right now I am trying to figure out which commercial organisations would like need it….

Wed, 7 Feb 07 08:55 pm . el raichu wrote:

hmm… maybe you already knew about content_for?

for a quick overview (http://www.microisv.com.ph/blog/flexible-page-layouts-using-ruby-on-rails.html)

or the official api (http://api.rubyonrails.org/classes/ActionView/Helpers/CaptureHelper.html)

Wed, 7 Feb 07 09:31 pm . Herryanto Siatono wrote:

Harro, it will take time. :)

Wed, 7 Feb 07 09:30 pm . Herryanto Siatono wrote:

Thank you Raichu, yeah I’ve been using content_for in my layout file, it’s good stuff, it’s another way to keep your template file clean.

But for a case like I mentioned above, where the panel forms a mini inline-layout, you would find ‘concat’ come in handy.

Wed, 13 Jun 07 11:39 pm . wam wrote:

Hey,

I just think you should rather declare your panel in your helpers file. It gives it a direct access to concat, and panel would rather look like :

def panel
res = “header …”

res += yield
res += “footer”
return res
end

The only change is that you have to call panel this way :

Add Your Comment



(optional)