Question

I'm working on a Sinatra app and want to write my own form helpers. In my erb file I want to use the rails 2.3 style syntax and pass a block to a form_helper method:

<% form_helper 'action' do |f| %>  
  <%= f.label 'name' %>  
  <%= f.field 'name' %>  
  <%= f.button 'name' %>  
<% end %>    

Then in my simplified form helper I can create a FormBuilder class and yield the methods to the erb block like so:

module ViewHelpers  
  class FormBuilder  
    def label(name)
      name  
    end  
    def field(name)
      name  
    end  
    def button(name)
      name  
    end  
  end  
  def form_helper(action) 
    form = FormBuilder.new 
    yield(form)  
  end  
end    

What I don't understand is how to output the surrounding <form></form> tags. Is there a way to append text on only the first and last <%= f.___ %> tags?

Was it helpful?

Solution

Rails has had to use some tricks in order to get block helpers to work as wanted, and they changed moving from Rails 2 to Rails 3 (see the blogposts Simplifying Rails Block Helpers and Block Helpers in Rails 3 for more info).

The form_for helper in Rails 2.3 works by directly writing to the output buffer from the method, using the Rails concat method. In order to do something similar in Sinatra, you’ll need to find a way of writing to the output from your helper in the same way.

Erb works by creating Ruby code that builds up the output in a variable. It also allows you to set the name of this variable, by default it is _erbout (or _buf in Erubis). If you change this to be an instance variable rather than a local variable (i.e. provide a variable name that starts with @) you can access it from helpers. (Rails uses the name @output_buffer).

Sinatra uses Tilt for rendering templates, and Tilt provides an :outvar option for setting the variable name in Erb or Erubis templates.

Here’s an example of how this would work:

# set the name of the output variable
set :erb, :outvar => '@output_buffer'

helpers do
  def form_helper
    # use the new name to write directly to the output buffer
    @output_buffer << "<form>\n"

    # yield to the block (this is a simplified example, you'll want
    # to yield your FormBuilder object here)
    yield

    # after the block has returned, write any closing text
    @output_buffer << "</form>\n"
  end
end

With this (fairly simple) example, an Erb template like this:

<% form_helper do %>
  ... call other methods here
<% end %>

results in the generated HTML:

<form>
  ... call other methods here
</form>
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top