How are error_messages_for sorted?

This problem is driving me crazy...

I've implemented the Ruby Cookbook method of user accounts. I've got the following code in my user model...

validates_presence_of :username, :message => "can't be blank" validates_uniqueness_of :username, :message => "is already taken!" validates_length_of :username, :maximum => 21, :message => "must be less than 21 characters" validates_confirmation_of :password,     :if => lambda { |user| user.new_record? or not user.password.blank? } validates_length_of :password, :within => 6..20,     :if => lambda { |user| user.new_record? or not user.password.blank? }validates_presence_of :gender, :message => "must be selected"validates_acceptance_of :tos, :message => "must be accepted by checking the box" validates_format_of :email, :with => /^([^@\s]+)@((?:[-a-z0-9]+\.)+[a- z]{2,})$/i

And the following in my new user add page...

<%= error_messages_for 'user' %> <%= form_tag :action => 'add' %> Desired Username: <%= text_field "user", "username" %><br> Valid Email Address: <%= text_field "user", "email" %><br> Password (6 to 20 characters): <%= password_field "user", "password" %><br> Verify Password: <%= password_field "user", "password_confirmation" %><br> Please Choose a Gender<br><%= radio_button("user", "gender", "m") %>Male                                            <%= radio_button("user", "gender", "f") %>Female <p><%=check_box("user", "tos") %> I am at least 18 years old. I have read and agree to the <%= link_to "Terms Of Service", :controller => "about", :action => "tos" %>.</p> <%= image_submit_tag("signup.gif")%> <%= end_form_tag %>

Here is the problem. If someone submits a form with errors, the error messages are presented in a different order than I would expect. For example, if someone submits a blank form, they get back:

There were problems with the following fields:

Tos must be accepted by checking the box Username can't be blank Gender must be selected Password is too short (minimum is 6 characters) Email is invalid

This doesn't follow the order in the model, the order of the form, or any logical order I can figure out. I really want the errors displayed in the same order that they appear on the form. Any ideas? I did search the group and learned I can step through the errors manually, using error_message_on :user, :username error_message_on :user, :email

But this doesn't seem very agile... if I add a field to the form later, then I'll need to update the error_message_on section too. Why doesn't rails display the errors in the same order as the validations in the model?

[snip]

This doesn't follow the order in the model, the order of the form, or any logical order I can figure out.

That's because the errors are stored in a hash and "the order in which keys and/or values are returned by the various iterators over hash contents may seem arbitrary and will generally not be in insertion order." (Quotation from the Pickaxe book.)

I really want the errors displayed in the same order that they appear on the form. Any ideas? I did search the group and learned I can step through the errors manually, using error_message_on :user, :username error_message_on :user, :email

I agree -- it would indeed be simpler for the user if the errors displayed in the same order as the relevant form elements.

But this doesn't seem very agile... if I add a field to the form later, then I'll need to update the error_message_on section too. Why doesn't rails display the errors in the same order as the validations in the model?

You seem to be suggesting a convention where the order of validation declarations in the model matches the order of form elements in your view. I'm not sure that's optimal...what happens if you have two views of the same model with fields in a different order?

This post and plugin may help you out (though as I write this I can only view the page via Google's cache):

Regards, Andy Stewart