LemonDev
LemonDev

Reputation: 132

Rails Cart Return Product Quantities on Destroy

I am new to rails and have a simple product store site. When a user adds a product to their cart or updates the line_item quantities in the cart, it will add/remove from the base product quantity as necessary. However, when they empty their cart (delete/destroy cart), it does not restore the base product quantity as if they did not buy anything. How do I update the destroy method to return the line_items listed back to the original product quantity?

line_items_controller.rb - Sample method to completely empty one product line_item in cart and increase base product quantity:

def empty
  product = Product.find(params[:product_id])
  @line_item = @cart.empty_product(product)
  @total = @line_item.quantity
  product.increment!(:quantity, @total)

  respond_to do |format|
    if @line_item.save
      format.html { redirect_to :back, notice: 'Product removed.' }
      format.js
      format.json { render :show, status: :ok, location: @line_item }
    else
      format.html { render :edit }
      format.json { render json: @line_item.errors, status: :unprocessable_entity }
    end
  end
end

carts/show.html.erb - Call to destroy/empty cart:

<%= link_to 'Empty Cart', @cart, method: :delete, data: {confirm: 'Are you sure you want to empty your cart?'}, :class => 'btn btn-danger whiteText' %>

carts_controller.rb - Current method to destroy cart:

def destroy
  @cart.destroy if @cart.id == session[:cart_id]
  session[:cart_id] = nil
  respond_to do |format|
    format.html { redirect_to root_path, notice: 'Cart was emptied.' }
    format.json { head :no_content }
  end
end

carts_controller.rb - What I'm trying to do (I think there may be an issue with this as it does not know how to resolve product = Product.find(params[:product_id])):

def destroy
  @cart.destroy if @cart.id == session[:cart_id]
    @cart.line_items.each do
      product = Product.find(params[:product_id])
      @total = @line_item.quantity
      product.increment!(:quantity, @total)
    end
  session[:cart_id] = nil
  respond_to do |format|
    format.html { redirect_to root_path, notice: 'Cart was emptied.' }
    format.json { head :no_content }
  end
end

EDIT

Tried to change the destroy method:

def destroy
  if @cart.id == session[:cart_id]
    @cart.line_items.each do |l|
      product = Product.where(:id => l.product_id)
      @total = @l.quantity
      product.increment!(:quantity, @total)
    end
    @cart.destroy
  end
  session[:cart_id] = nil
  respond_to do |format|
    format.html { redirect_to root_path, notice: 'Cart was emptied.' }
    format.json { head :no_content }
  end
end

It gives me the following error, even though I was able to use increment! on product quantity in the line_items_controller:

undefined method `increment!' for #<Product::ActiveRecord_Relation:0xb5ad1b4>

Also tried calling the path straight into the carts controller method. It shows cart successfully emptied, but does not return the product quantity to what it should be like when I call this same method in the html:

if @cart.id == session[:cart_id]
  @cart.line_items.each do |l|
    empty_line_item_path(product_id: l.product)
  end
  @cart.destroy
end

Upvotes: 3

Views: 247

Answers (2)

SteveTurczyn
SteveTurczyn

Reputation: 36860

For the question about destroy, you can actually do this at the model level.

On your LineItem model you can do...

before_destroy { |record| record.product.increment!(:quantity, record.quantity }

This assumes the LineItem has...

belongs_to :product

And will ensure the product quantity is updated regardless of where the line_item record is destroyed.

Upvotes: 3

SteveTurczyn
SteveTurczyn

Reputation: 36860

For your error after your EDIT part, you have...

  product = Product.where(:id => l.product_id)
  @total = @l.quantity
  product.increment!(:quantity, @total)

The where method doesn't return a single product, it returns a relation of productions (which likely only contain one product anyway).

Better would be...

  product = Product.find_by(:id => l.product_id)
  @total = @l.quantity
  product.increment!(:quantity, @total)

...which will return a product object.

Upvotes: 2

Related Questions