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