Custom Error Message Display with Multiple Models 1

Posted by James Wilford Sat, 04 Mar 2006 11:09:00 GMT

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

Comments

Leave a comment

  1. Joel Watson about 1 year later:

    Just FYI, the default errormessagesfor method supplied by Rails does exactly what your custom one does.

    <%= errormessagesfor :order, :address, :shipping_address %>

Comments