Tips on doing view work

This article is quite old.Time flies when you're having fun. I've been writing for my blog for a long time. Stuff changes fast, especially in the Ruby world. That's why I've put this warning on old posts. The article might still be valid, though.

Surrounding something with a div, conditionally.

A problem I keep running in to, especially with Haml, is how to render Ajax requests. Say you have a partial on your page which is something dynamic, like a feedback form. Here you might want to replace this partial with an updated version of that same partial. When making an ajax request, you specify the id of the element you wish to update. But when the element is created inside the partial, it gets rendered double.

#feedback
  = remote_form_for(@feedback ||= Feedback.new, :url => @feedback, :update => 'feedback') do |f|
    = f.input_field :message
    = submit_tag

will result after the button is pressed:

<div id="feedback">
  <div id="feedback">
    <form>etc
  </div>
</div>

One solution is to create the div outside of the partial, but that would make the partial less self sufficient. Since I am a big fan of self sufficient partials, I'd want to just render the partial, and never to care about any div's around it.

An ugly solution, especially when using Haml, is to dynamically create the open and close tags:

= '<div id="feedback">' unless request.xhr?
- remote_form_for(etc)
= '</div>' unless request.xhr?

My solution is a small helper, resulting in this view-code:

= content_for_ajax_request(:id => 'feedback') do
  = remote_form_for(etc)

Which requires this helper:

def content_for_ajax_request(options = {}, &block)
  c = capture_haml { yield }
  request.xhr? ? c : content_tag(:div, c, options)
end

The only minor problem is, that it screws up the indentation, but I'm not being picky this time.

When you're not using Haml, but ERB, just use this:

def content_for_ajax_request(options = {}, &block)
  c = capture { yield }
  request.xhr? ? c : content_tag(:div, c, options)
end

Naturally, you can change the condition, if you'd like.

def div_if(condition, options = {}, &block)
  c = capture { yield }
  condition ? c : content_tag(:div, c, options)
end

This is exactly why I like Ruby so much. Using blocks can make your code so much sweeter...

comments powered byDisqus