I am working on creating shop cart / order. I created shop cart with association by this guide so I have some problem. After a new sign in session My app can't find my previous cart and create one new
module ApplicationHelper
def current_cart
if !session[:cart_id].nil?
Cart.find(session[:cart_id])
else
Cart.new
end
end
end
Cart_items_controller
class CartItemsController < ApplicationController
def create
@cart = current_cart
@cart_item = @cart.cart_items.new(cart_params)
@cart.save
redirect_back fallback_location: root_path
flash[:success] = "Items added to your cart"
session[:cart_id] = @cart.id
end
def destroy
@cart = current_cart
@cart_item = @cart.cart_items.find(params[:id])
@cart_item.destroy
@cart_items = current_cart.cart_items
redirect_to carts_path
end
private
def cart_params
params.require(:cart_item).permit(:product_id, :user_id)
end
end
Cart Controller
class CartsController < ApplicationController
def index
end
def show
@cart_items = current_cart.cart_items
@order_item = current_order.order_items.new
end
def new
end
end
My module association
class CartItem < ApplicationRecord
belongs_to :cart
belongs_to :product
end
class Cart < ApplicationRecord
has_many :cart_items
end
class User < ApplicationRecord
has_one :cart
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :validatable
end
class Product < ApplicationRecord
has_one_attached :image
has_many :order_items
has_many :cart_items
end
Product controller show
def show
@product = Product.find(params[:id])
@cart_item = current_cart.cart_items.new
end
Product view show
...
<%= form_for @cart_item, remote: true do |f|%>
<%= f.hidden_field :product_id, :value => @product.id %>
<%= f.hidden_field :user_id, :value => current_user.id %>
<%= f.submit "Add to Card ", class: "btn btn-primary"%>
<% end %>
So my Schema
create_table "cart_items", charset: "utf8mb3", force: :cascade do |t|
t.integer "cart_id"
t.integer "product_id"
t.integer "user_id"
end
create_table "carts", charset: "utf8mb3", force: :cascade do |t|
t.integer "user_id"
end
create_table "products", charset: "utf8mb3", force: :cascade do |t|
t.string "title"
t.string "description"
t.integer "price"
end
create_table "users", charset: "utf8mb3", force: :cascade do |t|
t.string "email", default: "", null: false
t.string "encrypted_password", default: "", null: false
t.string "name"
end
So what I get after adding to cart. enter image description here
I think problem with finding session[:cart_id] It return nil and after every sign in it create a new cart Can anyone help me?
CodePudding user response:
Your current_cart
helper is creating a new cart any time there isn't one in the session. In a new session, there of course won't be a cart, even if the user has had one previously, so if you want to use their latest cart instead of always creating a new one, you could do something like this:
def current_cart
if session[:cart_id].present?
Cart.find(session[:cart_id])
else
current_user.cart || current_user.build_cart
end
end
You should probably also make sure that a cart can't be created without an associated user, or you might end up with orphaned carts / cart items in your database, like in the screenshot you posted. The cart should have a belongs_to :user
association, and user_id
could be a foreign key with null: false
on the database layer if you wanted to be extra safe. In your User model, the relation to cart could be has_one :cart, dependent: :destroy
to make sure that the user's cart is destroyed when the user gets destroyed.
Also, it seems redundant to have a user_id
in your cart_items
table, since the user will of course be the same as in the associated cart
. A has_one :user, through: :cart
association should take care of that.