Search code examples
ruby-on-railssessioncart

How to make session[:cart_size] persist after relogging?


I'm trying to show how many items are in the cart. When the user is in the session it works fine, I can browse through different pages inside the app and the cart_size persists. The problems is when the user logs out having some items in their cart and logs back in again, where the cart shows as empty but the items are still in the Order's view.

I'm trying to make the cart_size persist when the user logs out and logs in again.

OrderItemsController

class OrderItemsController < ApplicationController
  before_action :authenticate_user!

  def create
    order_item = current_order.order_items.new(article_id: params[:article_id])
    if order_item.save
      session[:cart_size] = current_order.order_items.size
      redirect_to root_path, notice: 'Successfully added to cart.'
    else
      redirect_to root_path, alert: 'Error adding to cart.'
    end
  end

  def destroy
    order_item = OrderItem.find(params[:id])
    order_item.destroy
    session[:cart_size] = current_order.order_items.size
    redirect_to order_item_path, notice: 'Successfully removed from cart.'
  end

  def current_order
    order = Order.where(user_id: current_user.id, status: 'created').order(updated_at: :desc).last
    order || Order.create(user_id: current_user.id)
  end
end

Cart Icon

I'm calling the cart_size to show in the cart icon as following. The car shows as empty after relogging:

<%= session[:cart_size] || 0 %>

views/orders/show.html.erb

The orders are still in the view after relogging:

<% if @order&.order_items.present? %>
  <% @order.order_items.each do |order_item| %>
    <div><%=order_item.article.title%></div>
<% else %>
  <span>You have no items in your cart</span>
<% end %>

Solution

  • There are a bunch of ways of solving this. One approach is to move current_order into the model layer and not depend on session at all

    Model

    class User < ApplicationRecord
      def current_order
        @current_order ||= Order.order(updated_at: :desc).find_or_create_by(user_id: id, status: 'created')
      end
    end
    

    View

    <%= current_user ? current_user.current_order.order_items.size : 0 %>
    

    Controller

    class OrderItemsController < ApplicationController
      before_action :authenticate_user!
    
      def create
        order_item = current_user.current_order.order_items.new(article_id: params[:article_id])
        if order_item.save
          redirect_to root_path, notice: 'Successfully added to cart.'
        else
          redirect_to root_path, alert: 'Error adding to cart.'
        end
      end
    
      def destroy
        order_item = current_order.current_order.order_items.find(params[:id])
        order_item.destroy
        redirect_to order_item_path, notice: 'Successfully removed from cart.'
      end
    end