Topics Covered in This Ruby on Rails Tutorial:
Adding an AJAX Request
Exercise Overview
In this comprehensive section, we'll explore a powerful combination of Rails features including AJAX, web services, and email functionality. AJAX (Asynchronous JavaScript and XML) remains a cornerstone of modern web development, enabling seamless user experiences by updating page content without full page reloads. Rails makes AJAX implementation remarkably straightforward through its built-in helpers and conventions, allowing developers to create dynamic, responsive applications with minimal JavaScript code.
This exercise demonstrates practical AJAX implementation in a real-world e-commerce context, where users expect instant feedback when updating cart quantities. We'll transform a traditional form submission into a smooth, asynchronous operation that updates only the necessary page elements.
If you completed the previous exercises, you can skip the following sidebar. We strongly recommend completing the previous exercises (8A-10B) before starting this one, as they establish the foundational cart functionality we'll be enhancing. If you haven't finished them, follow the setup instructions below.
Prerequisites RequiredThis exercise builds on previous work from exercises 8A-10B. If you haven't completed those, follow the Git checkout instructions to catch up to the required starting point.
If You Did Not Do the Previous Exercises (8A-10B)
- Close any files you may have open.
- Open the Finder and navigate to Class Files > yourname-Rails Class
- Open Terminal.
- Type
cdand a single space (do NOT press Return yet). - Drag the yourname-Rails Class folder from the Finder to the Terminal window and press ENTER.
- Run
rm -rf nuttyto delete your copy of the nutty site. - Run
git clone https://bitbucket.org/Noble Desktop/nutty.gitto copy the That Nutty Guy Git repository. - Type
cd nuttyto enter the new directory. - Type
git checkout 10Bto bring the site up to the end of the previous exercise. - Run
bundleto install any necessary gems. - Run
yarn install --check-filesto install JavaScript dependencies.
Quick Setup Process
Clean Previous Work
Remove existing nutty directory and clone fresh repository from Git
Checkout Correct Branch
Use Git checkout 10B to get the codebase at the right starting point
Install Dependencies
Run bundle and yarn install to ensure all gems and JavaScript packages are ready
Getting Started
Now we'll set up our development environment and prepare the necessary dependencies for AJAX functionality. Modern Rails applications rely on JavaScript package managers like Yarn to handle front-end dependencies efficiently.
For this exercise, we'll continue working with the nutty folder located in Desktop > Class Files > yourname-Rails Class > nutty.
If you haven't already done so, we strongly recommend opening the nutty folder in your code editor if it supports project-based editing (like Sublime Text, VS Code, or RubyMine). This provides better navigation and context switching between related files.
Run
yarn add jqueryjQuery remains a practical choice for DOM manipulation in Rails applications, providing cross-browser compatibility and a familiar API for developers transitioning from traditional web development.
You should still have a window with two tabs open in Terminal from the last exercise, with the first tab running the Rails server. The Rails development server needs to remain active to serve our AJAX requests. If you don't have the server running, complete the following sidebar.
Environment Setup
0/3Add jQuery dependency with yarnRequired for JavaScript DOM manipulation in the AJAX responses
Open nutty folder in code editorAllows easy navigation between multiple files during development
Verify Terminal tabs are configuredOne tab for running Rails server, another for executing commands
Restarting the Rails Server
- In Terminal,
cdinto the nutty folder:
- Type
cdand a space. - Drag the nutty folder from Desktop > Class Files > yourname-Rails Class onto the Terminal window (so it will type out the path for you).
- In Terminal, hit Return to change directory.
In Terminal, type the following:
rails s- Open a new tab (Cmd–T) leaving our server running in the old tab.
- In the new tab,
cdinto the nutty folder:
- Type
cdand a space. - Drag the nutty folder from Desktop > Class Files > yourname-Rails Class onto the Terminal window (so it will type out the path for you).
- In Terminal, hit Return to change directory.
In the browser navigate to: localhost:3000
If you see a Sign Out link at the top right, you are already signed in and you can skip the next step. The sign in instructions differ based on whether you already have login credentials.
If you already have a username and password: At the top right, click Sign In and sign in with the email and password you've been using.
If you started from a prepared folder and don't have an account: Click the Sign up link, enter an email and password, then click Sign Up.
Click on a product to view its details.
Click Add To Cart to add the item to your shopping cart.
Notice there is an update button below the product quantity in your cart.
We're going to transform this button into a seamless AJAX-powered feature. Rather than reloading the entire page when the update button is clicked—a jarring experience that disrupts the user's flow—we'll update only the specific elements that change: the individual item's Total Price, the cart's Subtotal, and the overall Total. This approach exemplifies modern web application design, where users expect immediate, contextual feedback without losing their place on the page.
Keep the Rails server running in a dedicated Terminal tab while using a second tab for other commands. This workflow prevents interruptions during development.
Making the Update Link Functional
Let's begin by implementing the core AJAX functionality in our cart view. We'll start by converting the static update link into a functional form that can submit data asynchronously.
In your code editor, open nutty > app > views > cart > index.html.erb
Around line 35, locate the
updatelink wrapped in an<a>tag. We need to convert this into a proper form tag so we can submit the quantity field along with the form submission.Wrap it in a form tag by adding the following bold code starting around line 34:
<td> <%= form_with model: line_item, method: :patch, local: false do |f| %> <%= f.number_field :quantity, min: 1, max: 100 %> <a href="#">update</a> <% end %> <%= link_to 'remove', line_item_path(line_item), method: :delete %>Let's examine this code in detail:
line_itemrefers to the specific line item in question—each row in the shopping cart.method: :patchcalls theupdatemethod by default—exactly what we want because we're modifying an existing line item rather than creating or deleting one.local: falseis the critical parameter that transforms this into an AJAX request. This single option triggers Rails' built-in AJAX handling, which manages the asynchronous submission and response processing behind the scenes.
We need to replace the
updatelink with a proper submit button. Starting around line 36, delete the<a>tags and replace them with the following bold code:<%= f.number_field :quantity, min: 1, max: 100 %> <%= f.submit %> <% end %>NOTE: While this creates a button element, we'll style it to appear as a link to maintain consistency with the page's existing design language.
Save the file and leave it open.
In your code editor, open nutty > app > controllers > line_items_controller.rb
Add the
updatemethod before thedestroymethod around line 15:end def update @line_item = LineItem.find(params[:id]) @line_item.update(params.require(:line_item).permit(:quantity)) @line_item.save end def destroyThis method handles the PATCH request, finds the specific line item, updates its quantity with the submitted value, and saves the changes to the database.
Save the file and close it.
Test the functionality by adding an item to your cart and adjusting its quantity. You'll notice that nothing appears to change immediately, but if you manually reload the cart page, you'll see the adjusted quantity has been saved. This confirms our backend logic is working—now we need to implement the frontend response using Rails' AJAX capabilities.
Key Implementation Components
Form Integration
Wrap update functionality in form_with helper to properly submit quantity data along with the AJAX request.
AJAX Configuration
Set local: false parameter to enable AJAX behavior instead of standard form submission with page reload.
The update method handles finding the line item, updating the quantity parameter, and saving changes. Rails automatically looks for a corresponding JavaScript view file.
Fixing the Total Price
Now we'll create the JavaScript response that updates the page dynamically. Instead of rendering traditional HTML, we'll use Rails' JavaScript template system to execute client-side updates after our AJAX request completes.
Switch back to your code editor.
Create a new file.
Save it as update.js.erb into the nutty > app > views > line_items folder.
This file extension is significant: the
.js.erbformat allows us to embed Ruby code within JavaScript, creating dynamic responses that can access our Rails instance variables and helper methods. Rails automatically renders this template when an AJAX request is made to the update action.Let's verify our JavaScript pipeline is working correctly before proceeding. Type:
alert('<%= @line_item.title %>');Save the file and leave it open.
Go to the browser and reload the cart: localhost:3000/cart
Change the quantity of a product, then click update.
An alert should pop up displaying the title of the item you updated. This demonstrates that our Ruby-to-JavaScript pipeline is functioning correctly, and we can seamlessly pass server-side data to client-side code.
Click OK to dismiss the alert. Excellent—our foundation is solid!
Go back to update.js.erb and delete the alert code.
Now let's implement the actual functionality to update the Total Price field. Type:
$('td.total-price').html('<%= number_to_currency @line_item.subtotal %>');Save the file.
Go to the browser and navigate to: localhost:3000
Add another product to your cart to create multiple line items.
Change the quantity of a product, then click update.
You'll notice that the Total Price changed for all items instead of just the one you updated. This occurs because our CSS selector
td.total-priceis too broad—it targets every element with that class. We need to make our targeting more specific using unobtrusive JavaScript techniques.Unobtrusive JavaScript is a modern best practice that separates behavior from presentation by using data attributes as hooks instead of inline event handlers or overly specific CSS selectors. This approach maintains cleaner separation of concerns and makes code more maintainable.
In your code editor, open nutty > app > views > cart > index.html.erb
Around line 45, add the following bold code to create a unique identifier for each line item:
<td class="total-price" data-line-item-id="<%= line_item.id %>"><%= number_to_currency line_item.subtotal %></td>Save the file.
In your code editor, open nutty > app > views > line_items > update.js.erb
Replace the generic
.total-priceselector with the more specific code shown in bold:$('td[data-line-item-id=<%= @line_item.id %>].total-price').html('<%= number_to_currency @line_item.subtotal %>');Save the file.
Go to the browser and reload the cart: localhost:3000/cart
Change the quantity of a product, then click update.
Perfect! Now only the specific product's price updates, demonstrating precise DOM targeting. Let's extend this functionality to update the cart's Subtotal and Total fields as well.
JavaScript Response Implementation
Create JavaScript View
Build update.js.erb file in line_items views folder to handle AJAX responses
Test Basic Functionality
Use alert to verify JavaScript execution and Ruby variable access
Implement Targeted Updates
Use data attributes and specific selectors to update only the relevant line item
Using generic class selectors like 'td.total-price' will update all matching elements. Use unique data attributes to target specific line items accurately.
Fixing the Subtotal & Total
With individual line items updating correctly, we'll now implement updates for the order summary section. This requires updating the cart's overall calculations, which affects multiple users' perception of the transaction total.
In your code editor, open nutty > app > views > cart > index.html.erb
Around line 59, add a unique identifier to the subtotal field:
<td>Subtotal</td> <td id="subtotal"><%= number_to_currency @cart.subtotal %></td> </tr>Around line 71, add a unique identifier to the total field:
<td>Total</td> <td id="total"><%= number_to_currency @cart.total %></td> </tr>Save the file.
In your code editor, open nutty > app > views > line_items > update.js.erb
On the second line, add the following bold code to update all relevant totals:
$('td[data-line-item-id=<%= @line_item.id %>]').html('<%= number_to_currency @line_item.subtotal %>'); $('td#subtotal').html('<%= number_to_currency @cart.subtotal %>'); $('td#total').html('<%= number_to_currency @cart.total %>');NOTE: The
@cartinstance variable is available here because it's created by ourbefore_actioncallbackload_cart_or_redirect_customer, which runs before every action in our controller.Save the file.
Go to the browser and reload the cart: localhost:3000/cart
Change the quantity of a product, then click update.
Excellent! Now all totals update seamlessly and instantly. You've successfully implemented a professional-grade AJAX feature that provides immediate user feedback while maintaining data integrity. This pattern—updating specific page elements without full page reloads—is fundamental to modern web application development.
Leave Terminal, your code editor, and browser open as we will continue building upon this foundation in the following exercise.
Update Strategy Comparison
| Feature | Individual Items | Cart Totals |
|---|---|---|
| Selector Method | data-line-item-id attribute | unique ID attributes |
| Update Scope | Single line item only | Entire cart summary |
| Data Source | @line_item.subtotal | @cart.subtotal & @cart.total |
With all three update targets implemented, users can modify quantities and see immediate price recalculations without any page reloads, creating a smooth shopping experience.