5.3. A Real-World ExampleLet's look at an example to see how RJS can be used. The online store IconBuffet.com uses Rails for its shopping cart. When a product is added to the cart, three separate page elements need to be updated to reflect the change, as illustrated by the before and after halves of Figure 5-1. Figure 5-1. Several page elements change when an item is added to the cart5.3.1. The Old WayBefore RJS, the code to handle adding and removing items from the cart entailed over a dozen lines of JavaScript, and multiple round-trips to the server. Here's what the JavaScript looked like: var Cart = { add: function(product_id) { $('product_' + product_id). addClassName('incart'); new Ajax.Request('/cart_items/', { parameters:'id='+product_id, onComplete: Cart.refresh }); }, remove: function(product_id) { $('product_' + product_id). removeClassName('incart'); new Ajax.Request('/cart_items/' + product_id, { method:'delete', onComplete: Cart.refresh }); }, refresh: function( ) { new Ajax.Updater('cartbox', '/cartbox'); new Ajax.Updater('num_items', '/num_items'); } } That approach works but has some serious problems: it's a fair amount of code, making it relatively hard to understand and maintain; it entails multiple round-trips to the server, making it slow, error-prone, and inefficient; and the page elements aren't all updated at the same time, introducing the possibility that an error halfway through the process would leave the page in an inconsistent state. 5.3.2. The RJS WayThe RJS solution, on the other hand, is remarkably simpler and more effective. It can be accomplished in one pass, with no custom JavaScript. Let's take a look at how it's implemented. The "Add to Cart" links use the standard Ajax link helper: <%= link_to_remote "Add to Cart", :url => cart_items_url, :with => "'id=#{product.id}'", :method => :post %> Clicking the link triggers the add_to_cart action, which updates the session and renders its file, add_to_cart.rjs: page[:cart].reload # renders the 'cart' partial page[:num_items].reload # renders the 'num_items' partial page["product_#{params[:id]}"].add_class_name 'incart' The RJS is rendered into JavaScript that is sent back to the browser and evaluated, which updates the three page elements simultaneously. These three lines do everything that the original version did, only faster and less error-prone. |