Customize validation output

Does anybody know a good way to completely customize validation
output? I've tried a number of options but can only get partway there.

For example I'd like to style not only the affected form input but
also its label, and provide a message (common to many apps). This has
been problematic, as the input is referenced internally by 'html_tag'
and at that point its associated label is out of scope:

http://edgeguides.rubyonrails.org/active_record_validations_callbacks.html#customizing-the-error-messages-html

I've added the message using this method but can't get at the label.

I've also created an auto-labeling form builder (http://
edgeguides.rubyonrails.org/form_helpers.html#customizing-form-
builders) but the error handling still only grabs the input itself
after the form has been built (i.e., it doesn't view my custom labeled
input as a sort of composite control).

I can accomplish this in the view conditionally by checking
@instance.errors on a per-field basis, but this seems clunky. And if I
do that, doesn't all the validation stuff still fire internally,
burning cycles on something I don't use?

There must be a good way to automate this.

Hi,
Here is a couple of things that I found myself doing for customizing
the error messages:
  1 alter the result of the error_messages_for helper (for example to
use gsub to make some small updates);
  2 redefine the "ActionView::Base.field_error_proc" to your own
procedure;
  3 add some additional YAML code to your locales file to specify the
different error message.

The main problem is with styling adjacent elements, in this case a
label. Or you might want to style a div that encloses an input and its
label.

Hi djangst,

When model validation rules result in errors, those errors are
basically made available to you as an ordered hash where the keys are
symbols of the attribute names and the values are strings/arrays of
the error(s) for the attribute.

So if you had some model foo.rb:

class Foo < ActiveRecord::Base
  validates_presence_of :bar
  ...

  HUMAN_ATTR_NAMES = {
    :bar => "Bar Biz Baz",
    ...
  }

  def self.human_attribute_name(attr, options={})
    HUMAN_ATTR_NAMES[attr.to_sym] || super
  end
  ...
end

and tested in console:

$ ./script/rails console
Loading development environment (Rails 3.0.3)

foo = Foo.create({})

=> #<Foo id: nil, ...

foo.errors.any?

=> true

foo.errors

=> {:bar=>["can't be blank"], ....

Foo.human_attribute_name(:bar)

=> "Bar Biz Baz"

So, if in some controller where you call @foo.create or @foo.save that
results in validation errors, then in the resulting view you could
grab those errors and do whatever you want with them, like:

...
<% if @foo.errors.any? %>
<% @foo.errors.each do |attr, errs| %>
<div ...>
<% attr_label = Foo.human_attribute_name(attr) %>
<% err_msg = (errs.is_a?(Array)) ? errs.join(' and ') : errs %>
  <span ...><%= attr_label %> <%= err_msg %></span>
<% end %>
</div>
<% end %>
...

It sounds like in your case, for each attr in your form, you'd want to
check if that attr had a validation err, and if so render that attr's
error(s) along with the attr's label and form element.

Note also that if you instead are calling @foo.create! or @foo.save!
in your controller, you'd get at that same errors ordered hash via
ActiveRecord::RecordInvalid:

$ ./script/rails console
...

begin ; foo2 = Foo.create!({}) ; rescue ActiveRecord::RecordInvalid => rie ; rie.record.errors ; end

=> {:bar=>["can't be blank"], ....

Cheers,

Jeff