Custom Error Message Display with Multiple Models 1
The Problem
As you probably know, when a model fails validation, the errors can be displayed at the top of the form by including this little snippet:
<%= error_messages_for("model") %>
However, this only accepts one model as an argument. What to do if your form updates more than one? I have a checkout form that creates an order, and also creates associated user, address and shipping_address models. The easiest solution is to do this:
<%= error_messages_for("order") %>
<%= error_messages_for("address") %>
<%= error_messages_for("shipping_address") %>
<%= error_messages_for("user") %>
However, this results in up to 4 big red error boxes - not exactly user-friendly.
The Solution
So, custom helpers to the rescue. In the helper file for the basket (cart) controller, I defined this:
def error_messages_for_order
errors = []
for object_name in %w{user address shipping_address order}
object = instance_variable_get("@#{object_name}")
unless object.errors.empty?
object.errors.full_messages.each { |error| errors << error}
end
end
unless errors.empty?
content_tag("div",
content_tag(
"h2",
"#{pluralize(errors.size, "error")} prevented this order from being completed"
) +
content_tag("p", "There were problems with the following fields:") +
content_tag("ul", errors.collect { |error| content_tag("li", error) }),
"id" => "errorExplanation", "class" => "errorExplanation"
)
end
end
This works in 2 stages. First it goes through an array of the model names and appends their error messages to the errors array. Then, if there are any errors, it prints them out in a nicely-formatted div - adapted from the code in the original "error_messages_for" helper supplied with Rails.
If you wanted to go further and make this helper more versatile, you could define it in application_helper.rb to make it available to all views, and you could pass the array of model names as an argument rather than hard-coding it. You could even replace the default "error_messages_for" helper entirely by defining your custom helper with the same name.
Nil Error Messages
Another tip related to this - if you have associations in your application, and you want to validate the associated models when saving, you do something like this:
validates_associated :user
validates_associated :address
However, this causes messages like "user is invalid" to appear in the error messages for the order model. Not exactly informative, especially when we are going to display the actual error messages for the user model as well.
So just set the errors to nil, and these messages will disappear:
validates_associated :user, :message => nil
validates_associated :address, :message => nil
Trackbacks
Use the following link to trackback from your own site:
http://blog.wilf.me.uk/trackbacks?article_id=custom-error-message-display-with-multiple-models&day=04&month=03&year=2006
Just FYI, the default errormessagesfor method supplied by Rails does exactly what your custom one does.
<%= errormessagesfor :order, :address, :shipping_address %>