ruby
37 lines · 7 steps
Merging a guest cart into a user cart in Rails
A service object that folds an anonymous cart's items into a logged-in user's cart atomically, respecting stock limits.
Explained by
highlit
1class CartMergeService
2 def initialize(guest_cart:, user_cart:)
3 @guest_cart = guest_cart
4 @user_cart = user_cart
5 end
6
7 def call
8 return @user_cart if @guest_cart.nil? || @guest_cart == @user_cart
9
10 ActiveRecord::Base.transaction do
11 @guest_cart.line_items.includes(:variant).find_each do |guest_item|
12 merge_line_item(guest_item)
13 end
14
15 @guest_cart.destroy!
16 end
17
18 @user_cart.reload
19 end
20
21 private
22
23 def merge_line_item(guest_item)
24 existing = @user_cart.line_items.find_by(variant_id: guest_item.variant_id)
25
26 if existing
27 new_quantity = [existing.quantity + guest_item.quantity, guest_item.variant.stock].min
28 existing.update!(quantity: new_quantity)
29 else
30 @user_cart.line_items.create!(
31 variant: guest_item.variant,
32 quantity: [guest_item.quantity, guest_item.variant.stock].min,
33 price: guest_item.variant.current_price
34 )
35 end
36 end
37end
01 / 01
STEP 01
‹ swipe to step through ›
Walkthrough
Space play
←→ step
click any line
Three takeaways
- 1Wrapping multi-step writes in a transaction keeps the merge all-or-nothing, so a failure never leaves both carts half-updated.
- 2Guarding against nil and identical inputs up front makes the operation safe to call repeatedly without side effects.
- 3Clamping quantities to available stock at merge time prevents the combined cart from exceeding what can actually ship.
Related explainers
php
<?php namespace App\Listeners;
Generating responsive images in a Laravel listener
queued jobs
event listeners
image processing
Intermediate
7 steps
ruby
class Admin::AccountsController < Admin::BaseController before_action :set_account, only: :destroy def destroy
A guarded destroy action in Rails
controllers
callbacks
transactions
Intermediate
8 steps
ruby
class MailingListDeduplicator GMAIL_DOMAINS = %w[gmail.com googlemail.com].freeze def initialize(subscribers)
Deduplicating a mailing list by canonical email
deduplication
normalization
service object
Intermediate
8 steps
php
<?php namespace App\Jobs;
Debouncing a Laravel shipping-rate job
queues
debouncing
atomic-locks
Advanced
9 steps
ruby
class ProgressBar BAR_WIDTH = 40 def initialize(total, io: $stdout)
Building a terminal progress bar in Ruby
state tracking
terminal output
time estimation
Intermediate
8 steps
go
package handlers type WebhookEvent struct { ID string `json:"id"`
Verifying and processing webhooks in Gin
webhooks
hmac
idempotency
Intermediate
9 steps
Share this explainer
Here's the card — post it anywhere.
Made with highlit — turn any snippet into a walkthrough like this in about a minute.
Explain your code
Embed this explainer
Drop the interactive walkthrough into a blog or docs. Views never cost a credit.
<iframe src="https://highlit.co/explainers/merging-a-guest-cart-into-a-user-cart-in-rails-explained-ruby-1213/embed?autoplay=1" width="100%" height="520" loading="lazy" style="border:0"></iframe>
Autoplay is on by default — add ?autoplay=0 to start paused.