In my rails app I have this code in my _navbar.html.erb
<% if @cart.total_price > 0 %>
<%= link_to @cart do %>
<i class="fa fa-shopping-cart"> € </i>
<%= @cart.total_price %>
<% end %>
<% else %>
<a href="#" class="menu-cart"><i class="fa fa-shopping-cart"></i> € 0.00</a>
<% end %>
It displays the @cart.total_price
but I want it to display the total items in the Cart instead.
I'm not sure how to do that
Most of this code is from a Udemy tutorial, but it's getting little bit to much for my experience so I feel kind a lost trying to modify this to my needs.
I've been trying to add the @product_item
to the above code but with out a luck, can anyone take a look at this and guide me through this.
I have this code in the application_controller.rb
before_action :set_cart
def set_cart
@cart = Cart.find(session[:cart_id])
rescue ActiveRecord::RecordNotFound
@cart = Cart.create
session[:cart_id] = @cart.id
end
In the carts_controller.rb
I have this:
class CartsController < ApplicationController
before_action :set_cart, only: [:show, :destroy]
rescue_from ActiveRecord::RecordNotFound, with: :invalid_cart
def new
@cart = Cart.new
end
def show
@images = ["1.jpg", "2.jpg", "3.jpg", "4.jpg", "5.jpg"]
@random_no = rand(5)
@random_image = @images[@random_no]
end
def destroy
@cart.destroy if @cart.id == session[:cart_id]
session[:cart_id] = nil
redirect_to root_url, notice: 'Your Cart is Empty'
end
private
def set_cart
@cart = Cart.find(params[:id])
end
def cart_params
params[:cart]
end
def invalid_cart
logger_error = 'You are trying to access invalid cart'
redirect_to root_url, notice: 'Invalid Cart'
end
end
In the controllers/concerns
I've this file current_cart.rb
module CurrentCart
private
def set_cart
@cart = Cart.find(session[:cart_id])
rescue ActiveRecord::RecordNotFound
@cart = Cart.create
session[:cart_id] = @cart.id
end
end
Then I have the product_items_controller.rb
and there is this code:
class ProductItemsController < ApplicationController
include CurrentCart
before_action :set_cart, only: [:create]
before_action :set_product_item, only: [:show, :destroy]
def create
@product = Product.find(params[:product_id])
@product_item = @cart.add_product(@product.id)
if @product_item.save
redirect_to root_url, notice:'Product added to Cart'
else
render :new
end
end
private
def set_product_items
@product_item = ProductItem.find(params[:id])
end
def product_item_params
params.require(:product_item).permit(:product_id)
end
end
And the relevant models are cart.rb
and product_item.rb
in the cart.rb
I have this code:
class Cart < ActiveRecord::Base
has_many :product_items, dependent: :destroy
def add_product(product_id)
current_item = product_items.find_by(product_id: product_id)
if current_item
current_item.quantity += 1
else
current_item = product_items.build(product_id: product_id)
end
current_item
end
def total_price
product_items.to_a.sum{|item| item.total_price}
end
end
And in the product_item.rb
there is this code:
class ProductItem < ActiveRecord::Base
belongs_to :product
belongs_to :cart
belongs_to :order
def total_price
product.price * quantity
end
end
You can rewrite the @cart
code in the _navbar.html.erb
to look like this, it should work just like the previous chunk but shows the product_items.count
instead of the total_price
<% if @cart.product_items.count > 0 %>
<%= link_to @cart do %>
<i class="fa fa-shopping-cart"></i>
<%= @cart.product_items.count %>
<% end %>
<% else %>
<a href="#" class="menu-cart"><i class="fa fa-shopping-cart"></i> 0 </a>
<% end %>
If you want total items in the cart, just take the sum of the quantity
column over product_items
in your Cart
model, like this:
def total_quantity
product_items.sum(:quantity)
end
Then you can just call @cart.total_quantity
from the view (or anywhere else).
Note that by calling sum
on product_items
, which is a relation (and not an array), this directly calculates the sum using SQL:
SELECT SUM(`product_items`.`quantity`) FROM product_items
WHERE `product_items`.`cart_id` = 123
where 123
is the id of the cart.
This is more efficient than calling sum
on an array of product items (ie product_items.to_a.sum(&:quantity)
), which would load each product item, then sum the quantities. But either should work, and depending on what you're doing the latter sum
may suit your needs better.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.