Dec 26, 2011

Formatting Rails Errors for Twitter Bootstrap

I'm using Twitter's Bootstrap toolkit for the layout in a proof of concept application I'm working on.  So far my general impression is that I really like Bootstrap but there are a few obstacles to making it play nice with Rails.

One of those obstacles is that Rails formats fields with errors quite a bit differently than Bootstrap's CSS expects.  Below I describe a possible solution.  I'm not 100% sure this is the best approach but it seems to work well and I'm currently working on a proof of concept app that will be thrown out in several weeks so there's little risk if I'm wrong.

Rails default formatting looks like this...

<!-- without error -->
<div class="clearfix">
<label for="bar">Bar</label>
<div class="input">
<input id="foo_bar" name="foo[bar]" size="30" type="text">
</div>
</div>
<!-- with error -->
<div class="field">
<div class="field_with_errors">
<label for="foo_bar">Bar</label>
</div><br>
<div class="field_with_errors">
<input id="foo_bar" name="foo[bar]" size="30" value="" type="text">
</div>
</div>

Bootstrap's CSS expects this....

<!-- without error -->
<div class="clearfix">
<label for="bar">Bar</label>
<div class="input">
<input id="foo_bar" name="foo[bar]" size="30" type="text">
</div>
</div>
<!-- with error -->
<div class="clearfix error">
<label for="bar">Bar</label>
<div class="input error">
<input id="foo_bar" name="foo[bar]" size="30" value="" type="text">
<span class="help-inline"></span>
</div>
</div>

The solution I've arrived at is to first remove the "field_with_errors" div.  This is done by setting the field_error_proc to simply return the html passed in without wrapping it.

# ./config/environment.rb
ActionView::Base.field_error_proc = Proc.new {|html, instance| html }
view raw environment.rb hosted with ❤ by GitHub

The next step was to create a FormBuilder subclass with the desired functionality.  The example below only demonstrates the 'text_field' method.  In practice I'll have to create a separate method for each Bootstrap form element I want to use in my application.

# ./app/helpers/boot_strap_form_builder.rb
class BootStrapFormBuilder < ActionView::Helpers::FormBuilder
def text_field(method, options={})
t = @template
t.content_tag(:div, :class => "clearfix#{' error' unless @object.errors[method].blank?}") {
t.concat(t.label_tag method)
t.concat(t.content_tag(:div, :class => "input#{' error' unless @object.errors[method].blank?}") {
t.concat(super method)
if @object.errors[method].present?
t.concat(t.content_tag(:span, options[:help_text], :class => 'help-inline'))
end
})
}
end
end

Then to use the custom form builder I'd do somthing like this....

<%= form_for(@foo, :builder => BootStrapFormBuilder) do |f| %>
<%= f.error_explanations %>
<%= f.text_field :bar %>
<%= f.submit %>
<% end %>
view raw _form.html.erb hosted with ❤ by GitHub

I realize this wasn't exactly a detailed explanation of a solution but hopefully I managed to get the gist of the idea across.


No comments: