Format form fields for bootstrap using rails+nokogiri
- by user1116573
I have the following in an initializer in a rails app that uses Twitter bootstrap so that it removes the div.field_with_errors that rails applies when validation fails on a field but also the initializer adds the help/validation text after the erroneous input field:
require 'nokogiri'
ActionView::Base.field_error_proc = Proc.new do |html_tag, instance|
html = %(<div class="field_with_errors">#{html_tag}</div>).html_safe
form_fields = [
'textarea',
'input',
'select'
]
elements = Nokogiri::HTML::DocumentFragment.parse(html_tag).css("label, " + form_fields.join(', '))
elements.each do |e|
if e.node_name.eql? 'label'
html = %(#{e}).html_safe
elsif form_fields.include? e.node_name
if instance.error_message.kind_of?(Array)
html = %(#{e}<span class="help-inline"> #{instance.error_message.join(',')}</span>).html_safe
else
html = %(#{e}<span class="help-inline"> #{instance.error_message}</span>).html_safe
end
end
end
html
end
This works fine but I also need to apply the .error class to the surrounding div.control-group for each error.
My initializer currently gives the following output:
<div class="control-group">
<label class="control-label" for="post_message">Message</label>
<div class="controls">
<input id="post_message" name="post[message]" required="required" size="30" type="text" value="" /><span class="help-inline"> can't be blank</span>
</div>
</div>
but I need something adding to my initializer so that it adds the .error class to the div.control-group like so:
<div class="control-group error">
<label class="control-label" for="post_message">Message</label>
<div class="controls">
<input id="post_message" name="post[message]" required="required" size="30" type="text" value="" /><span class="help-inline"> can't be blank</span>
</div>
</div>
The solution will probably need to allow for the fact that each validation error could have more than one label and input that are all within the same div.control-group (eg radio buttons / checkboxes / 2 text fields side by side).
I assume it needs some sort of e.at_xpath() to find the div.control-group parent and add the .error class to it but I'm not sure how to do this.
Can anyone help?
PS This may all be possible using the formtastic or simple_form gems but I'd rather just use my own html if possible.
EDIT
If I put e['class'] = 'foo' in the if e.node_name.eql? 'label' section then it applies the class to the label so I think I just need to find the parent tag of e and then apply an .error class to it but I can't figure out what the xpath would be to get from label to its div.control-group parent; no combination of dots, slashes or whatever seems to work but xpath isn't my strong point.