How to make a custom form builder in Rails
A Form builder is a great way to remove repetative code from your form views or to include some custom code into the existing helpers.
I wanted to change how I displayed error information in my forms and decided to do it in a form builder and this is how.
Overview
There are two common ways of displaying error information, in an error block at the top of the page via error_messages_for :model or inline above or below the field using error_message_on :model, :field
When using error_message_on :model, :field I find that I always have to use the :prepend_text to get the error message to display nicely. So my error handling always looks like this:
<%= error_message_on :user, :name, :prepend_text => 'Name ' %>
<%= form.text_field :name %>
and the form is displayed as:
Name
Name can’t be blank
I then thought that the label is already displaying the “prepend_text” so why not inline the error message directly after the label. With a custom form builder (code below), my code just looks like this and the errors will still be displayed:
<%= form.text_field :name %>
and the form is displayed as:
Name can’t be blank
The code
This form builder is going to be very simple because I’m only changing the handling of the label helper but the concepts carry through to any of the form helpers you want to extend.
Because I need to get to the errors object on the model, I had to bring in some repeat code from the label_tag helper. The default Rails form builder can be found in [rails/gem path]/actionpack/lib/action_view/helpers/form_helper.rb starting just after line 700.
Unfortunately the FormBuilder seems to be undocumented so you won’t find documentation in the Rails API docs.
I’ve written comments throughout the code to explain what I’ve done.
[lib/error_form_builder.rb]
#Adds error message directly inline to a form label
#Accepts all the options normall passed to form.label as well as:
# :hide_errors - true if you don't want errors displayed on this label
# :additional_text - Will add additional text after the error message or after the label if no errors
def label(method, text = nil, options = {})
#Check to see if text for this label has been supplied and humanize the field name if not.
text = text || method.to_s.humanize
#Get a reference to the model object
object = @template.instance_variable_get("@#{@object_name}")
#Make sure we have an object and we're not told to hide errors for this label
unless object.nil? || options[:hide_errors]
#Check if there are any errors for this field in the model
errors = object.errors.on(method.to_sym)
if errors
#Generate the label using the text as well as the error message wrapped in a span with error class
text += " <span class=\"error\">#{errors.is_a?(Array) ? errors.first : errors}</span>"
end
end
#Add any additional text that might be needed on the label
text += " #{options[:additional_text]}" if options[:additional_text]
#Finally hand off to super to deal with the display of the label
super(method, text, options)
end
end
Using your custom form builder
If you want to use your custom form builder for a single form, include this in your form declaration:
<% end %>
If you want to make your custom form builder the default builder for your project, you can add the following line to your config/environment.rb file:
If you have any questions on how this works, feel free to ask in the comments.

Cool technique, I’ve been meaning to play around with some custom form builders to be more DRY. Also, in the first above code snippet it should be “class ErrorFormBuilder < ActionView::Helpers::FormBuilder” ().
Thanks Ben, got mixed up when fixing > & < - I’ve fixed it in the code.
[...] How to make a custom form builder in Rails [...]
Handy article. Thanks Andrew.