Handling Errors in Ajax And Rails 2

Posted by Ric Tue, 05 Feb 2008 16:27:00 GMT

A while ago, I was wondering how I should deal with errors that are encountered in rails controllers, while processing an Ajax request. I played around with some alternatives and eventually came up with one that has been working great for a few months, so I thought I’d share it.

You’ve probably all heard of overriding ‘rescue_action_in_public’ in your ApplicationController to deal with errors. (See simple example below).

def rescue_action_in_public(exception)
  # render the error page.
  render :file => "public/error.html"
end

This works great in regular methods, but what if something happens in an ajax request?

If you take no action, then the controller will fail ‘silently’ (well, some stuff appears in the log, but the user is unaware).

The way I got around this was to add a method to the ApplicationController, similar to that below (irrelevant code stripped out, so apologies if this code has a typo!).

  def perform_ajax_action

    if block_given?
      begin
        if (request.xhr?)
          yield
        else
          raise RuntimeError.new('Not in an ajax request!')
        end
      rescue Exception => error
        logger.error("#{Time.now}: Error performing ajax action: #{error.inspect}")
        logger.error(error.backtrace.join("\n"))
        ajax_aware_redirect_to "/error.html"
      end      
    else
      logger.error("perform_ajax_action called with no block!");
      ajax_aware_redirect_to "/error.html"
    end

  end

(You were probably wondering what this ‘ajax_aware_redirect_to’ business is all about. It’s just another method in the ApplicationController which helps with redirecting during ajax processing. It looks a bit like this: Again, irrelevant stuff removed.)

  def ajax_aware_redirect_to(options = {}, *parameters_for_method_reference)
    if request.xhr?
      render :update do |page| 
        page.redirect_to( options, *parameters_for_method_reference) 
      end
    else
      redirect_to( options, *parameters_for_method_reference)
    end
  end

Now, in order to get this to catch your errors, you need to add an :around_filter to your controller. e.g.

class MyController < ApplicationController

  around_filter :my_around_filter, :only => [:my_action]

  # controller code here....

  def my_around_filter
    perform_ajax_action do
      # do other useful stuff here if you like.
      # in an 'around filter' yield calls the method wrapped in the filter
      yield
    end
  end
end
Trackbacks

Use the following link to trackback from your own site:
http://www.ricroberts.com/trackbacks?article_id=handling-errors-in-ajax-and-rails&day=05&month=02&year=2008

Comments

Leave a comment

  1. jorrel about 12 hours later:

    um can you just modify the rescue_action_in_public hook?

    I mean:
    def render_action_in_public(exception)
    respond_to do |format|
    format.html { render :file => “public/error.html” }
    format.js do
    render :update do |page|
    page.redirect_to “public/error.html”
    end
    end
    end
    end

  2. Ric about 17 hours later:

    Thanks jorrel.

    I hadn’t thought of using repsond_to.

    I think what you’ve suggested will work for capturing any errors in ajax calls.

    My way has the potential benefit/downside (depending on which way you look at it) of restricting the method with the filter to only be callable by ajax.

    I think I’ll consider this some more. Thanks for the ideas.

Comments