The cart is simply a bucket of stuff.
The first thing that comes to mind of a great cart is that it is "stupid". Sure that might sound crazy but it is very true. A shopping cart should not know much about your "order" or your "products". Your cart should simply be a bucket to keep a bunch of products for a specific user. It doesn't know the price of the products or anything about the checkout process.
The second thing about a great cart is that it ironically it is "smart" about itself. Your cart should NOT know about the order or products but it should know about itself. Note your cart is the combination of a "cart model" and "cart_items model". This cart_items model has the following fields:
cart_id product_id item_type_id quantity Additionally the cart should only have the following field: user_id (this is the stylist user_id in the admin area) customer_id (for the customer facing site this == user_id)
Also note ror_ecommerce adds user_id to the cart_items table to keep queries more simple.
One feature I added to the minimum model is the field item_type_id. item_type_id refers to a model that just has a name field. The ItemTypes are as follows:
What this simple field in the DB does is allows you to have a wish list and save for later functionality out of the box. Additionally you can WOW your marketing team by telling them all the items a user has ever deleted out of their cart or purchased. If you ever need to create a recommendation engine your cart will give you all the data you need.
Now with this model, purchasing an item is simply taking the items that are in the cart and have an item_type of shopping_cart and moving them to an order / order_items object. Once you purchase an order_item you change the cart_item.item_type to "purchased" with cart.mark_items_purchased(order)
I've heard the argument that using an order object for the cart "make things easier". Not only do I disagree but sorry, "You would be wrong". By mixing the cart and the order you have not separated concerns. This can make validations very conditional. It also mixes cart logic with order logic.
I view your cart as something that can be removed off the face of the planet and not effect much. Sure people would be upset to add things back to their cart but at the end of the day it would not effect anything financially. The order however is sacred. If an order was deleted you could lose financial data and even fulfillment information. Hence you don't want to be messing around with the order because you could be shooting yourself in the foot.
By nature your cart has a lot of abandoned records. If the order and cart are separated you could very easily archive the carts without much worry. If your order is your cart the risk to do this would be too great. One small bug could cost you way too much.
Now you have an extremely slim cart with a tremendous amount of functionality.
The when the item is removed from the cart instead of deleting the cart_item the item is changed to active = false. This allows you to see the state of the item when it was removed from the cart.
The when the item is marked for "save_for_later" in the cart now the state of the item is just changed to "save_for_later". So adding it back to the cart is as easy as changing the state to "shopping_cart".
Take a look at This Blog Post for more details.