Showing posts with label ajax. Show all posts
Showing posts with label ajax. Show all posts

Tuesday, 5 February 2008

Handling Errors in Ajax & Rails

Note: The RichText blog has moved to www.ricroberts.com

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



Digg Technorati del.icio.us Stumbleupon Reddit Blinklist Furl Spurl Yahoo Simpy

Please also visit the Swirrl blog

Saturday, 23 September 2006

let's get modal

Note: The RichText blog has moved to www.ricroberts.com

UPDATE 12 July 07: Check out this more recent post for more info on modal dialogs.

In the Ruby On Rails project on which I'm currently working, I felt the need to introduce the concept of a modal dialog box. This is a common requirement in traditional client-applications, in order to restrict a user's actions to a certain area of the screen. However, until the advent of Web 2.0 it has been tricky implement in internet-based applications.

I tried a few different approaches, but finally settled on using the Xilinus Prototype Window javascript libraries to help me out.

A bit of background...

In my project, I orginally had a table which contained links to allow the user to edit the (often complex) contents of some of the table-cells. The links would causethe user to be navigated away from the page, and so after they had finished doing their editing they would have to navigate back. This is all very well, apart from the fact that if we wanted the site to remember other values that the user had entered on the first page, it meant storing hoards of things in the session. I stuck with this approach for a while, but the more functionality I added to the page, the more work I had to put into maintaining state in the session. Something had to change!

My solution

1. First download the Prototype Window libraries from here. (I used version 0.96.2).

2. The download zip-file contains a bunch of folders. Put the window.js file from the javascripts folder into your rails project's public/javascripts folder. (You will also need the prototype.js file, but this should already be there for you if you generated your project from a skeleton). The stylesheets folder in the zip-file contains all the different themes that are demonstrated on the xilinus prototype window samples page. The styles that you want to use need to go into your rails project's public/stylesheets folder. (I made a window subfolder to keep things tidier).

3. So that your views can use the prototype window javascript, put a javascript include tag in the head of the appropriate layouts file. For the sake of this example, put it in the application.rhtml layout file.

<%= javascript_include_tag "prototype", "effects", "window" %>
Also put in a stylesheet link to the style of modal dialog log you want.
<%= stylesheet_link_tag "/stylesheets/window/default" %>
We're going to use some javascript later, so put a content_for_page_scripts tag in the head of the layout too.
<script type="text/javascript"><%=@content_for_page_scripts %></script> 

4. In the view from which you wish to launch the modal dialog, we need some javascript. Write a function, and put it inside a content_for page_scripts block. Here, the function launches a modal dialog containing the web page at the url passed in.
<% content_for("page_scripts") do -%>

function show_Array_Window(myUrl)
{
  win = new Window('window_id', {title: "Array", width:300, height:500, url:myUrl});
  win.setDestroyOnClose();
  win.showCenter();
}

<% end -%>

5. Now set up a link for the user to click on, and set the onclick event to the function we just wrote. In the example below, we're building up a table with a link to a different object in each row's cell. (If you just want a permanent link to a single modal dialog, you dont need to go to the trouble of building up a dynamic onclick string).
<table>
  <% for i in 0...@my_array.length do %>
    <tr>
      <td>
        <%=
          # other code here if you like
          "<a href = \"#\" onclick='show_Array_Window(
\"" + url_for(:controller => 'my_controller',
:action => 'my_Action', :id => i) + "\")'>
Go Modal!</a>"
        %>
      </td>
    </tr>
  <% end %>
</table>

6. You can now do whatever you want in the page that's shown. In my case, this involved allowing the user to edit the complex data structure that was represented by the object in the table.

... and that's it.

The advantage of using the Xilinus Prototype Window libraries over other modal dialog approaches like lightbox gone wild is that because you just point the dialog to a url, the page that is shown inside can include its own javascript. This allows you to do ajax stuff inside your dialog like it was any other rails page. (I wont go into the whole ajax thing here).



Digg Technorati del.icio.us Stumbleupon Reddit Blinklist Furl Spurl Yahoo Simpy

Please also visit the Swirrl blog