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):

http://www.railtie.net/articles/2006/01/26/enhancing_rails_errors

Regards,
Andy Stewart