Format form fields for bootstrap using rails+nokogiri

Posted by user1116573 on Stack Overflow See other posts from Stack Overflow or by user1116573
Published on 2012-05-31T21:06:26Z Indexed on 2012/06/03 10:40 UTC
Read the original article Hit count: 223

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">&nbsp;#{instance.error_message.join(',')}</span>).html_safe
      else
        html = %(#{e}<span class="help-inline">&nbsp;#{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">&nbsp;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">&nbsp;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.

© Stack Overflow or respective owner

Related posts about ruby-on-rails-3

Related posts about validation