Ajax is frequently used to deliver a richer user experience. So why are error messages so rarely handled properly in Ajax-enabled applications? Handling errors gracefully -- in a way that actually helps the visitor fix the problem -- adds a genuinely high-quality feel. We've already got all the machinery we need. It just takes a little care and attention.
class FoosController < ApplicationController
def update
@foo = Foo.find(params[:id])
respond_to do |format|
if @foo.save
format.html do
flash[:info] = "Your foo has been created."
redirect_to @foo
end
format.js { head :ok }
else
format.html do
flash.now[:warning] = "I could not update the foo."
render :action => :edit
end
format.json do
head :unprocessable_entity, :json => @foo.errors.to_json
end
end
end
end
end
With this controller, you get a solid fallback for standard HTML requests and clean JSON behaviour for Ajax. When something goes wrong on a JSON request, you get back an array of arrays that looks like this:
[
[ "attribute1", "error1", "error2" ],
[ "attribute2", "error3" ]
]
Think of the things you can do with that kind of structured feedback:
new Ajax.Request('/foo.json', {
method: 'PUT',
parameters: {
authenticity_token: window._token,
"foo[subject]": $F('foo_subject'),
"foo[body]" : $F('foo_body')
},
onSuccess: function(transport) {
// This is Web 2.0: celebrate with a yellow highlight.
},
onFailure: function(transport) {
var errors = transport.responseJSON;
errors.each(function(error) {
var attribute = error.shift();
var messages = error.join(", ");
var errorMessage = attribute + " " + messages;
var inputNode = $("foo_" + attribute);
if(inputNode) {
// Show that something is wrong with this field.
inputNode.addClassName("error");
// Do something better than an alert box. Alert boxes suck.
alert(errorMessage);
}
});
}
});