Skip to main content

Ecommerce multi-step checkout with guest accounts

Rails • Asked by Sean Murphy

Hello, I've been thinking about the best approach for implementing a checkout scenario in a custom ecommerce site I've been developing and wanted to see if anyone here had advice to share.

We're not really doing guest checkout per-say for simplicity sake early on. Customers without an account just give an email up front to get started, and later on at the confirm page we'll ask for a password and make an actual account to associate the order with. This way, I kind of balance having a lower barrier to start checking out and the simplicity of backend work with all orders being associated with actual customer models.

However, what I'm most curious about, is the multi-step approach. All of the various information (shipping, billing, passwords) is being gathered across several pages. When users without an account are preparing an order, where's the best place to hold around this information? Having some sort of "Guest" Customer model might make sense, but I wasn't totally confident about this (I'm using Devise for customers). The other idea is using the session, but I wasn't sure if that's really appropriate either.

If anyone has some thoughts, that'd be great!


So one thing to be aware of is that the session can't store too much information. You're limited in cookie size so it's usually not a great place to store much information. That said, it is perfect for storing an ID of a database record that might represent the Order.

You will probably want to create an Order object and then save the ID to it in the session to track it as the user progresses. You can use it to store the email and other information temporarily while they are checking out. Then, when they finally get to the final stage of checkout, you can use this Order ID from the session to create the actual Devise User and other records.

This would make the user account optional, but potentially leaves some data lying around. If the user decides to not purchase halfway through the order, you will have a leftover Order lying around that's unfinished. You can either keep it around (can't hurt to analyze later) or if you really need to remove it, you can have it expire after a couple days if it isn't marked as "complete". It also doesn't require you to capture an email or anything if you don't want.

There are lots of other ways to handle this and this is just one approach. I'm curious what suggestions other people might have.


Thanks Chris!

That does sound like a great approach; I'll give it a try. I was indeed aware of the session limits, and actually I'm doing the same thing for the shopping cart right now – storing just a Cart ID (with the same consequences of abandoned records, etc).

I saw one of the UserVoice votes for upcoming videos was about wizard forms. I suppose this is kind of a similar goal in some ways.

There are lots of other ways to handle this and this is just one approach. I'm curious what suggestions other people might have.

That's why I wanted to ask. These types of problems, where there's no single right answer, I love seeing the various ways people might tackle it. This was my first post here, thanks for taking time to respond and for the great videos!


Wizards are definitely a good topic to cover. I've used Wicked for wizards a few times and it seems pretty good if you follow the way it wants you to set up the pages. It does want a persisted record in the database to store the state of the wizard, so this approach would work well with it.

As for abandoned records, they might seem scary, but it's kind of interesting to keep around so you can analyze them later. You might notice that certain products are harder for customers to convince themselves to buy. And if you save their email you could email them 5 days later reminding them to check out (if that fits your business). Could be a lot of good uses for things like that.


I'm with Chris on this one. You're going to want to either create a wizard controller that deals with the different stages of the order and checkout process. Due to session/cookie length there's only so much data that you can cram into it and for this type of application you really want to be keeping track of state via a persisted database object.

If you want to look at Wicked and need some help, let me know. Chris schooled me on Wicked a couple of years ago and I've since gone on to do some really complex things with it.

As for abandoned records with a persisted database object, you could always have a rake task that runs every 24 hours and looks for incomplete orders (objects) and delete them or better yet keep them attached to the user in a "order history" and allow him/her to delete the order (simple destroy controller action).

My advice on persisted database objects with Wicked is keep a good eye on your model validations. Things can get screwy really quick when tracking state via a persisted object when you're mixing in a lot of model validations. This is just my experience, so there may be a clean way to handle this that I'm not aware of but it was a pain in the ass for me in the past.


If you ever decided to make a series on an ecommerce solution, that would be awesome.


@poidog22 I definitely should! I've got a separate Stripe course (outside of GoRails) that I've been putting together over the last couple of months and one of the bonus sections towards the end is building a full shopping cart and checkout flow. It's not multi-step right now but that should be a reasonable addition to include in the course.

I'll be announcing that course in the next couple of weeks if all goes well as I finish up these videos.


I'm interested in some ecommerce action as well. It's weird- I haven't seen a single site/video/tutorial that tackles the concepts of variants during a shopping cart/checkout experience. And yet, here in the real world, I keep building websites for people selling clothing (1 style of shirt with 7 colors and 4 different sizes), fine art prints (4 different sizes, no frame or frames in one of 3 different colors), or pizzas (what do you want on your pizza? Do you want that on the whole pizza, or just half? Which half?). And now (lucky me), I just picked up a client that is a clothing manufacturer. Do you want that shirt in one of these 5 standard colors? Or a more expensive "custom color"? Also, if you buy 1 of these shirts, it's $20. If you buy 34 of them, they're $18 each. If you buy 100, they're $16/each. XXL is $2 extra for each item.

The spot that I bang my head on my desk is wearing through. I'm about to just give up and find a less frustrating life as a park ranger or maybe a long haul trucker...


Hahah! Yeah it's a real pain in the butt. This is probably why people use Spree/Solidus for most complex ecommerce projects because it's already solved those problems for you. Doing this from scratch can end up with a whole lot of little gotchas which are almost certain to be addressed already by Spree/Solidus which is nice. Just looking at the sheer list of extensions they have gives you an idea of the complexity: http://extensions.solidus.io/

This is why Shopify is such a giant Rails app. I actually found reading their API docs thought provoking to see how they handle the various pricing options for variants and things. I don't think they even handle things like bulk discounts out of the box and you have to install it to your store: https://apps.shopify.com/bulk-discounts

Variants themselves are relatively straightforward in the sense that users will always see Products and always interact with variants aside from visiting the product pages.

As you might imagine, we could probably talk about the complexities of this for months given how big of projects/businesses ecommerce is these days. :)


Agreed. Even a series about setting up a site with solidus/spree would be cool. I'm a big fan of practical tutorials that you can extend into real world production.


Oh believe me, I've looked into the 3 S's for almost every e-commerce project I've tackled! It seems like I always come to the same outcome though- they provide 50 features when all I need is 6. That's why I'm such a big fan of gems like Piggybak, although even with Piggybak I had to severely prune code so that it wasn't dependent on RailsAdmin cruft. Someday maybe I'll roll my own, and it'll be in the sweet spot between Piggybak and Ror-e. As small as I can get it, except with flexible variant support!

I'm gonna get right on that if the Park Ranger thing doesn't work out...


Login or Create An Account to join the conversation.

Subscribe to the newsletter

Join 24,647+ developers who get early access to new screencasts, articles, guides, updates, and more.

    By clicking this button, you agree to the GoRails Terms of Service and Privacy Policy.

    More of a social being? We're also on Twitter and YouTube.