T
We're Happier Together! NYC Devshop has joined the HappyFunCorp family! Learn more!

Devshop

A Shopping Cart For Your Web App

A Shopping Cart For Your Web App

Development

A Shopping Cart For Your Web App

Posted by: Jared Rader

Friday, Jul 25th, 2014

If you're looking to build an e-commerce web application, there is no shortage of tools you can use, from Spree to Shopify. However, it's not too difficult to build your own - which is something we were tasked with over the past week.

In this post, I'll cover creating a shopping cart that will keep track of products and their quantity and allow users to remove items.

Having read Agile Web Development with Rails 4, I decided to use that book's shopping cart implementation. I'd encourage you to go through the book, especially if you're new to Ruby on Rails, but I'll give you an outline of everything required to make a robust shopping cart for your web application.

At least four models are necessary for an e-commerce site: Products, Carts, Orders and Ordered Items (which is a join table between products and orders and products and carts).

Creating and retrieving our cart

Because setting a cart is functionality we'll need to access among different controllers, a great place to put it is inside the concerns folder provided by default in Rails 4. In here, you can create a module where you retrieve the right cart object based on the cart ID stored in the session, or you create the cart if it doesn't yet exist.

module CurrentCart

extend ActiveSupport::Concern
private
def set_cart
@cart = Cart.find(session[:cart_id])
rescue ActiveRecord::RecordNotFound
@cart = Cart.create
session[:cart_id] = @cart.id
end
end

The astute reader may look at this and say, wait, what happens when a customer creates a cart but then abandons it? That's a great question, and there are a number of things you could do to handle this scenario. You could create a cron job that checks how old the cart is and determine an expiration date, upon which the job destroys those cart records. On the other hand, you may not want to destroy the carts, especially if you add users later on and associate carts with users. Abandoned carts will help you determine which users aren't checking out, which can be useful information.

Adding products to our cart

A good time to call our `set_cart` method would be at the moment a customer decides to add an item to their cart, or in terms of our web application's functionality, right before creating an Ordered Item record:

class OrderedItemsController < ApplicationController

include CurrentCart
before_action :set_cart, only: [:create, :update, :destroy]

def create
@cart.add_product(params)
if @cart.save
render partial: 'carts/shopping_bag', locals: { order: @cart }
else
flash[:error] = 'There was a problem adding this item to your shopping bag.'
redirect :back
end
end
end

To include the current cart functionality, all you need to do is `include CurrentCart` in the controller. Then you can use a `before_action` filter to specify which actions need to retrieve or create a cart.

You probably also noticed the `add_product` method on cart. This is a special method we create on the cart model that allows us to create initial Ordered Items records, as well as keep track of the quantity of the same product. If we simply used `@cart.ordered_items.build`, we'd be creating individual records of the same product each time.

Let's take a look at the `add_product()` method:

class Cart < ActiveRecord::Base

def add_product(product_args)
current_item = ordered_items.find_by(product_id: product_args[:product_id])
if current_item
current_item.quantity += product_args[:quantity].to_i
current_item.save
else
current_item = ordered_items.build(product_args)
end
current_item
end



This method differed a bit from the one in Agile Web Development. In our application, users could choose the quantity of items they wanted to add, rather than adding them one at a time. So a quantity parameter was always being passed to the controller action inside of `product_args`.

`add_product()` checks for the existence of the Ordered Item record in the cart. If we have the same product in our cart, it simply updates the quantity and saves the record. Otherwise, we build the relationship and return the item.

Adding and removing products

Like most e-commerce sites, we built a page where customers can look at their cart and update the quantity of items or remove them entirely. This calls for two more actions in our Ordered Items controller: update and destroy:

class OrderedItemsController < ApplicationController

include CurrentOrder
before_action :set_cart, only: [:create, :update, :destroy]
before_action :set_ordered_item, only: [:update, :destroy]

# ...

def update
@ordered_item.update(quantity: params[:quantity]) if @ordered_item
if @ordered_item.save
render json: { itemPrice: @ordered_item.quantity * @ordered_item.product.price, subtotal: @cart.total_price }
else
flash.now[:error] = 'There was a problem updating your shopping bag.'
end
end

def destroy
@ordered_item.destroy
render json: { order_total: "$%.2f" % @cart.total_price }
end

private
def set_ordered_item
@ordered_item = @cart.ordered_items.find_by(id: params[:item_id])
end
end

Now we have everything we need to keep track of items in a customer's cart.

In my next post, I'll cover how we handled check out and processing orders with ActiveMerchant and Authorize.net.

Devshop

About Us

Devshop is a highly motivated group of entrepreneurs, developers, and designers that aim to work with companies that are looking for an edge. Each member of our team brings something unique to the table allowing us to cater our services specifically to meet your needs and exceed your expectations.