You have two options that I can come up with with my head:
Rewrite ActionView :: Base.field_error_proc
In one situation, I rewrote ActionView :: Base.field_error_proc (it has rails on it). Using a bit of nokogiri, I changed proc to add error messages to the data-error attribute of the input / textarea element, instead of wrapping them in an error div. Then he wrote a little javascript using jquery to wrap all the inputs and their labels on the document. If there is error information related to the input / textarea, it is passed to the wrapper div.
I know that this solution depends on javascript and may or may not have a graceful digression, but it works fine in my situation, as it is for a web application, not a public site. I feel good requiring javascript in this script.
# place me inside your base controller class ActionView::Base.field_error_proc = Proc.new do |html_tag, object| html = Nokogiri::HTML::DocumentFragment.parse(html_tag) html = html.at_css("input") || html.at_css("textarea") unless html.nil? css_class = html['class'] || "" html['class'] = css_class.split.push("error").join(' ') html['data-error'] = object.error_message.join(". ") html_tag = html.to_s.html_safe end html_tag end
Create your own ActionView :: Helpers :: FormBuilder
You can also get more or less the same effect by overriding the text_field method so that it always returns wrapped input. Then, using the object variable, access the error hash and add all the necessary error information to the shell. It does not require javascript and works beautifully, but in the end I prefer the first approach, because I consider it more flexible. If, however, I worked on a public site, I would use this approach.
In addition, FYI, it was convenient for me to override the check_box and radio_button methods so that they always return an input with an associated label. There are many interesting things you can do with the special FormBuilder.
# place me inside your projects lib folder class PrettyFormBuilder < ActionView::Helpers::FormBuilder def check_box(field, label_text, options = {}) checkbox = super(field, options) checkbox += label(field, label_text) @template.content_tag(:div, checkbox, :class => "wrapper") end end
The above example shows how to wrap check_box, but it more or less matches the text box. As I said, use object.errors to access error hashing, if necessary. This is just the tip of the iceberg ... there is a ton that you can do with custom FormBuilders.
If you are on the path to creating a custom form template, you might find it helpful to modify the above ActionView :: Base.field_error_proc so that you don't get double wrapped fields when errors occur.
ActionView::Base.field_error_proc = Proc.new do |html_tag, object| html_tag # return the html tag unmodified and unwrapped end
To use the form constructor, specify it in a call to the form_for method or put the following in the application helper:
Often my decisions end up using some combination of each to achieve the desired result.