Search code examples
ruby-on-railsdatabaseherokucookiescart

Rails shopping Cart - how to destroy them in production without User to get a 404?


In a rails 5 e-commerce site, Carts from a classic shopping cart model have not been destroyed because of a badly written code, so now the heroku database has more than 10 000 rows of empty carts. If I destroy them from the heroku console, next time a user who already came to the site but gave up in the middle of the buying process will try to reach the site, he will get a 404 error like this:

ActiveRecord::RecordNotFound (Couldn't find Cart with 'id'=305)

Because of the cookies, obviously. The heroku DB has exceeded its allocated storage capacity, so I need to destroy the empty carts. (And fix the code, but this is not the question here). Is there a way to do this smoothly?

class CartsController < ApplicationController
  def show
    @cart = @current_cart
    total = []
    @cart.order_items.each do |item|

      total << item.product.price_cents * item.quantity.to_i
    end

    @cart.amount_cents_cents = total.sum

  end

  def destroy
    @cart = @current_cart
    @cart.destroy
    session[:cart_id] = nil
    redirect_to root_path
  end
end

class OrdersController < ApplicationController

  before_action :authenticate_user!

  def create
    @order = Order.new

    total = []
    @current_cart.order_items.each do |item|

      total << item.product.price_cents * item.quantity.to_i
    end

    @order.amount_cents_cents = total.sum

    if @order.amount_cents_cents == 0
       redirect_to root_path
    else
      @current_cart.order_items.each do |item|
        @order.order_items << item
        item.cart_id = nil
      end

      @user = current_user
      @order.user_id = @user.id
      @order.save

      Cart.destroy(session[:cart_id])
      session[:cart_id] = nil

      redirect_to order_path(@order)
    end
  end

class ApplicationController < ActionController::Base

  before_action  :current_cart

  def current_cart

        if session[:cart_id]
          cart = Cart.find(session[:cart_id])
          if cart.present?
            @current_cart = cart
          else
            session[:cart_id] = nil
          end
        end


        if session[:cart_id] == nil
          @current_cart = Cart.create
          session[:cart_id] = @current_cart.id
        end
  end

Solution

  • instead of using find which throws an exception if it does not find a record you can use find_by_id which returns nil. And if you get nil you can make the cart empty and display a message to the user that your cart is empty.

    also, you can use rescue block to rescue from the exception thrown by find