Capturing Haml Blocks

Let's suppose you have some code like that in a view:

= @user.editable_field_for 'birth_date', field_class: 'datepicker' do |value|
  = value.try(:strftime, '%d/%m/%Y')
editable_field_for is a method inside a decorator and you need to evaluate the given block.

How would you write this method? That was my first try:

def editable_field_for field_name, options = {}, &block
  capture_haml do
    haml_tag :span, class: 'inline-editable' do
      haml_concat block.call(self.send(field_name))
    end
  end
end

Call the block passing field's value as argument, seems obvious? But it does not work.

After some hard time I found the solution:

1
2
3
4
5
6
7
def editable_field_for field_name, options = {}, &block
  capture_haml do
    haml_tag :span, class: 'inline-editable' do
      haml_concat capture_haml(field_value, &block)
    end
  end
end

We need to capture the block (line 4) using capture_haml to get it as string, then, we concatenate into the buffer.

In this example, I am passing field_value as argument to the block (and receiving it as value in the view), but you can remove it if you don't need.

Note we are using capture_haml in two different ways, with and without a block. Before this issue, I just knew the first one, as explained in this post (in portuguese only).

That is it.

Written on November 6, 2015

Share: