How to Distinguish a User-Aborted AJAX Call from an Error

Let’s say you’re writing a LOLcats app and you want to be all user-friendly and show an adorable little kitty-cat error message whenever an AJAX call fails. So you write an error handler using your favorite cross-browser library (mine is jQuery), something like this:

  $.ajax( { url: "someUrl", success: function() {
    // do something impressive with the results
  }, error: function() {
    showError("Ohs noes. Tell me when you fix your AJAX.");
  } } );

But you start using your app and you notice that your error message also appears when you navigate away from the page before an AJAX call has finished, or when you hit Escape to cancel the AJAX call. That kind of sucks—it looks ugly to have the error message appear when there really was no error.

I did a little looking around and found what looks like a cross-browser-friendly way to tell if an error really occurred or if something else happened, like the user navigating away or hitting Escape.

The trick is to check the response headers in the XMLHttpRequest object. If there are no response headers (null or empty string, depending on the browser), the server did not respond yet. That means the user aborted.

Here’s a function that takes an XMLHttpRequest and tells you if the user aborted it.

  /**
   * Returns true if the user hit Esc or navigated away from the
   * current page before an AJAX call was done. (The response
   * headers will be null or empty, depending on the browser.)
   *
   * NOTE: this function is only meaningful when called from
   * inside an AJAX "error" callback!
   *
   * The 'xhr' param is an XMLHttpRequest instance.
   */
  function userAborted(xhr) {
    return !xhr.getAllResponseHeaders();
  }

And here is the updated application code to call this new function. You can easily adapt this to another JavaScript library than jQuery:

  $.ajax( { url: "someUrl", success: function() {
    // do something impressive with the results
  }, error: function(xhr, textStatus, errorThrown) {
    if (!userAborted(xhr)) {
      showError("Ohs noes. Tell me when you fix your AJAX.");
    }
  } } );

Oh, did that “textStatus” and “errorThrown” catch your eye? I already looked at those. You can’t use them to tell if the user aborted. They return the same values whether the user aborted or the server returned with an error. (I only tested a 500 error.)

How to Put Rewrite Rules in Your Ruby Code, Not Your Web Server

Need to put some URL rewrite rules in your Rails app? Not too crazy about writing Apache mod_rewrite rules? Prefer writing Ruby code?

Refraction to the rescue.

Refraction is a new Rails plugin from Josh Susser and Pivotal Labs that helps you easily implement URL rewrites in Ruby, rather than writing the rules in web-server-specific lingo. Your code gets called by Rack, although you don’t need to know anything about Rack to write rewrite rules.

Here’s an example. Let’s say you want to duplicate Twitter’s /@username routes (did you know Twitter supports URLs like that?) but have found as I did that routes.rb doesn’t seem to work with a “@:username” rule. Instead, create a RESTful UsersController and then put this in your refraction_rules.rb file:

Refraction.configure do |req|
  # rewrite /@username as /users/username
  if req.path =~ %r{/@(.+)}
    req.rewrite! :path => "/users/#{$1}"
  end
end

The notes in the blog post (see link above) mention that there is already a Rack rewrite plugin called Rack::Rewrite but “Rack::Rewrite only really gives you access to the request URI, whereas Refraction appears to give the entire request object… that can be much more useful for determining where to send someone.”