Improving debugging for AJAX and RJS
Posted by Richard White Fri, 21 Apr 2006 14:21:00 GMT
The one major thing that was lost in the shift to RJS templates was the default Rails debugging output when something went awry. Often times things would just fail silently and leave you sitting there with only the loading spinner to comfort you. Most of the problems people have reported since the switch to RJS are solved as soon as they look in the log and notice the syntax error that is causing all the problems.
I was originally pointing people to this code snippet that embeds Prototype AJAX requests and responses into the page. That script however was always escaping the HTML in the request and responses, which while generally a good idea, is annoying when Rails responds the standard error page. I found it tedious to look at the HTML code for the error page when all I really want is to see it rendered. Therefore I embedded the following in the bottom of any page I wished to debug:
<div id='debug'></div>
<script type="text/javascript">
Ajax.Responders.register({
onCreate: function(request, transport) {
$('debug').innerHTML = '<p><strong>' + request.url + '</strong></p>';
},
onComplete: function(request, transport) {
if (transport.responseText.match(/<html>/) != null) {
$('debug').innerHTML = transport.responseText;
} else {
$('debug').innerHTML = '<p><strong>' + request.url
+ '</strong></p><pre>' + transport.responseText.escapeHTML()
+ '</pre>';
}
}
});
</script>
The major addition here that if an <html> tag is found in the response it displays the response inline and does not escape it. This is invaluable since it means you get a legible error page when something goes wrong. I took this one step further. I created a debug a partial (shared/debug.rhtml) which I included (render :partial => ‘shared/debug’) at the bottom of my application/layout.rhtml. This allowed me to have a link on every page that I could use to toggle the display of debug information.
shared/debug.rhtml
<style type="text/css">
#debug-container {
clear:both;
margin-top: 15px;
}
#debug {
background: #ffd;
border: solid 1px #999;
padding: 5px;
margin-top: 15px;
overflow:auto;
}
#debug p {
margin: 0;
}
</style>
<div id="debug-container">
<% if params[:debug] == "true" %>
<strong><p><strong><%= link_to "Debug ON", :debug => false %></strong></p></strong>
<div id='debug'></div>
<script type="text/javascript">
Ajax.Responders.register({
onCreate: function(request, transport) {
$('debug').innerHTML = '<p><strong>' + request.url + '</strong></p>';
},
onComplete: function(request, transport) {
if (transport.responseText.match(/<html>/) != null) {
$('debug').innerHTML = transport.responseText;
} else {
$('debug').innerHTML = '<p><strong>' + request.url
+ '</strong></p><pre>' + transport.responseText.escapeHTML()
+ '</pre>';
}
}
});
</script>
<% else %>
<p><strong><%= link_to "Debug OFF", :debug => true %></strong></p>
<% end %>
</div>
While I’ve obviously tailored this solution for Rails you could easily use it on any application that relies on Prototype for its AJAX calls. If you want to check out a working debug go to ajaxscaffold.com where the debug toggle is at the bottom of every page. Enjoy!
Since this a more generally applicable post then I usually write I ask that you take a moment to Reddit and/or Digg it.
I’ve recently discovered the ‘Firebug’ extension for Firefox which I’ve found invaluable in debuging my RJS stuff. You just turn on the XmlHttpRequest option and presto in your firebug pane you have access to the request and the response for all your ajax calls, where you can see the error output nicely.
Chris: I had firebug installed at one point, I really should put it back on. I know that I removed it b/c firebug + web developer w/ live css editing on + multiple ajax heavy sites open = FF death :(
Richard, thank you for this useful code. It really makes my work easier