Hey guys, how about a cart for the marketplace?

I started with the marketplace course today, but...There is no shopping cart! How about the checkout? I thought there would be... :(

Posted about 5 years ago by kikeisasi
Posted about 5 years ago by Alex Yang

Sorry to disappoint, but the reason we didn't include a cart feature in our marketplace course is because it's somewhat advanced for students who are just starting out. Although it's outside the scope of our existing course, if you want to give it a shot, I'd be happy to give you some pointers along the way. Let me know!

Posted about 5 years ago by Razvan Balosin

Hey Alex, I'd also like to try and build the cart feature into the EtsyDemo project. It will be great if you could provide us with an overview about what needs to be done and where.

Posted about 5 years ago by Alex Yang

Alright, here's a high-level guide. It's long and complicated, so you'll need to make sure to follow the same approaches we used in Etsydemo to do things like creating migrations, setting up database associations, etc.

1) Let's start with setting up your databases and associations. You'll need to create 2 new databases: ShoppingCart and Items. A ShoppingCart has many Items. You'll also need to link Items with Listings (Items belong to Listings) and with Orders (Items belong to Orders).

2) Next, you'll need to make sure that a new ShoppingCart is created with each new user session. Sessions weren't covered in Etsydemo, but they basically allow you to store variables that will persist for the duration of the session. We'll store a 'cart_id' variable to remember the user's ShoppingCart ID. Whenever we need to do anything cart-related, we'll retrieve that 'cart_id' - if it doesn't exist (that just means that the user hasn't done anything yet), we'll just create one.

We'll write some code to do this and put it in a new file, app/controllers/concerns/current_cart.rb (see below). Concerns are a way to share common code across controllers.

module CurrentCart
extend ActiveSupport::Concern
def set_cart
@cart = ShoppingCart.find(session[:cart_id])
rescue ActiveRecord::RecordNotFound
@cart = ShoppingCart.create
session[:cart_id] = @cart.id

We'll need to call this code before we run any cart-related code. So for any controller-action where that applies, we only need to put two lines of code at the top of the controller file. For example, we'll need to add this for the 'create' action in our ShoppingCart controller, so we would write:

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

3) Now with our databases set up and a shopping cart tied to a user session, we need to be able to add items to our shopping cart. We'll start by creating a button on our view page, but instead of using 'link_to' as we usually do, we'll use 'button_to'. The reason for this is because we aren't looking to visit a page (GET request), we need to submit info (PUT request). We have to submit the Listing info for our app to know which Listing to add to the shopping cart. It should look something like this:

<%= button_to "Add to Cart", items_path(listing_id: @listing) %>

We'll also need to write the code to add the item in our 'create' action in our Items controller. Here are the key lines:

@listing = Listing.find(params[:listing_id])
@item = @cart.items.build(listing: @listing)

Note that we're using @cart here, which is only possible because of the cart code we wrote in Step 2.

4) Finally, we need to be able to checkout. You'll need to add a 'Checkout' button on your view page. This button should link to the 'new' action of your Orders controller, which is the address/payment form we set up in Etsydemo. When the form is submitted, all the Items will need to be added to the Order and saved. We'll do this through the 'create' action. Here are the relevant lines you need to add:

@cart.items.each do |item|
item.shopping_cart_id = nil
items << item

This code loops through each of the Items, removes them from the current ShoppingCart (that way the ShoppingCart can be deleted without the Items inside being deleted as well), and then adds them to the Order so it can be saved.

That's the essence of it. There's a lot more you can (and probably should) do with this, from displaying the cart contents on the screen after items have been added, to features such as removing items from the cart, consolidating repeats of the same item, incorporating AJAX so the page doesn't need to be refreshed, etc. But build it incrementally - get the simplest version of the shopping cart working before you try to tackle any extensions.

It's definitely possible I missed some details (it's tough to write this all from memory!), so try it out and follow up with me if you're having trouble.