简体   繁体   中英

Showing Number of Cart Items instead of Cart total price in navbar Rails app

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"> &euro; </i>
                <%=  @cart.total_price %>
                <% end %>

                <% else %>
                    <a href="#" class="menu-cart"><i class="fa fa-shopping-cart"></i> &euro; 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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM