I’m working through Agile Web Development with Rails, 4th Edition. Overall, the book is well written–readable, nice depth and breadth, great example (ecommerce site)–and I would recommend it highly; however,  Chapter 11, adding Ajax support to the cart, has given me hell.

I spent hours working through the example a couple times, diffing my source against the source code provided, starting and restarting the server, trying multiple browsers (Safari, Firefox, Chrome), grepping for errors,  and googling. Finally, I arrived at the solution:

To remedy this problem, I updated my public/javascripts/prototype.js file from the prototype download page. At the time of writing, that was http://prototypejs.org/assets/2010/5/13/prototype.js

Debugging

Here are the steps I followed to track down the problem.

First, I noticed that the page was refreshing everytime I pressed an “Add to Cart” button. I made sure the necessary files were in place and the javascript input was defined for the create method I was Ajaxifying. To ensure the button was properly defined, I viewed source and ensured the element had an attribute data-remote=”true”. Despite proper HTML and Ruby, the development.log showed that I was still retrieving the page as HTML instead of JavaScript

Started POST "/line_items?product_id=3" for 127.0.0.1 at Sun Jul 18 21:06:41 -0500 2010 Processing by LineItemsController#create as HTML Parameters: {"product_id"=>"3", "authenticity_token"=>"Dsv044fqfo7H46jLYx3e6qnbCgqk3Tcoij6pqbOQZx4="}

So I checked the browser errors. Firefox showed

Error: document.on is not a function Source File: http://localhost:3000/javascripts/rails.js?1277734011 Line: 136

Inspecting the element in Chrome I saw

Uncaught TypeError: Object #<an HTMLDocument> has no method 'on'

Looking at the rails.js file, line 136, we see

  document.on("click", "*[data-confirm]", function(event, element) {
    var message = element.readAttribute('data-confirm');
    if (!confirm(message)) event.stop();
  });

Between the errors and the rails.js file, we see that none of the included JavaScript files nor the browser defined the method. A new Rails 3 patch will upgrade prototype from 1.6.1 to 1.7rc2, so future generations will not experience this fun.