Reputation: 132
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
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
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