Build Robust & Production Quality Applications - Lesson 1: Custom Form Builders
05 Feb 2015Let's say we have a Todo's app, where we allow our users to create a new todo. We also want to show errors when validation errors occur:
#new.html.haml
%section.new_todo
%h3 Add a new todo
= form_for @todo do |f|
= f.label :name, "Name"
= f.text_field :name
= f.label :description, rows: 6
%br
= f.submit "Add This Todo"
The issue with this code above is that it is not pulling in the errors on the Todos object.
We could:
#new.html.haml
%section.new_todo
%h3 Add a new todo
= form_for @todo do |f|
if@todos.errors?
= f.label :name, "Name"
= f.text_field :name
...but this is cumbersome to do for each form.
Lets create a helper called MyFormBuilder that will customize the label:
class MyFormBuilder < ActionView::Helpers::FormBuilder
def label(method, text = nil, options = {}, &block)
errors = object.errors[method.to_sym]
if errors
text += " <span class =\"error">#{errors.first}</span>" #pull the first error from the errors object (an array)
end
super(method, text.html_safe, options, &block) #delegates control back to the custom form builder
end
end
Update new.html.haml, make sure you add "MyFormBuilder" to your form_for block:
%section.new_todo
%h3 Add a new todo
= form_for @todo, builder: MyFormBuilder do |f|
= f.label :name, "Name"
= f.text_field :name
= f.label :description, rows: 6
%br
= f.submit "Add This Todo"
Alternate Option: my_ form_ for helper
This is still somewhat repetitive. Let's create a my_ form_ for helper. We can manually merge in the myformfor rather passing in the MyFormBuilder:
app/helpers/my_form_builder.rb
module ApplicationHelper
def my_form_for(record, options = {}, &proc) #takes 3 arguements
form_for(record, options.merge!({builder: MyFormBuidler}), &proc)
end
end
Update the new.html.haml
%section.new_todo
%h3 Add a new todo
= my_form_for @todo do |f|
= f.label :name, "Name"
= f.text_field :name
= f.label :description, rows: 6
%br
= f.submit "Add This Todo"
Custom Form Builders in The Wild!
1. Formtastic
- You can use semantic form_ for
2. Simple_form (creators of devise)
- allows integration with Twitter Bootstrap & Zurb Foundation 3
- is not best for those with alot of customization
- has default mapping - which is not the best for complex forms
3. BootstapForm
- minimal dsl
- similar flow/syntax to Rails