Reputation: 169
I'm learning ruby and rails building a shopping cart and I'm struggling trying to delete only one instance of Product
with id
of 3
from a cart that has a collection.
When i do current.user.cart.products.delete(product)
it removes both instances from the shopping cart whats the magic trick to only remove one, I tried a few things but I think I'm not understanding something, maybe someone can help. Thanks ahead ! Sorry forgot to say hello to you ;)
current_user.cart.products.find_by(params[:id])
CACHE Product Load (0.0ms) SELECT "products".* FROM "products" INNER
JOIN "carts_products" ON "products"."id" =
"carts_products"."product_id" WHERE "carts_products"."cart_id" = ? AND
(3) LIMIT ? [["cart_id", 1], ["LIMIT", 1]]
#<Product id: 3, title: "Coco", description: "Voluptates ut dolor. Voluptas aperiam temporibus d...", price: 0.5278e2, created_at: "2018-03-07 16:59:42", updated_at: "2018-03-07 16:59:42">
current_user.cart.products
Product Load (0.6ms) SELECT "products".* FROM "products" INNER JOIN
"carts_products" ON "products"."id" = "carts_products"."product_id"
WHERE "carts_products"."cart_id" = ? LIMIT ? [["cart_id", 1],
["LIMIT", 11]]
#<ActiveRecord::Associations::CollectionProxy [#<Product id: 3, title:
"Coco", description: "Voluptates ut dolor. Voluptas aperiam temporibus
d...", price: 0.5278e2, created_at: "2018-03-07 16:59:42", updated_at:
"2018-03-07 16:59:42">, #<Product id: 3, title: "Coco",
description:"Voluptates ut dolor. Voluptas aperiam temporibus d...",
price: 0.5278e2, created_at: "2018-03-07 16:59:42", updated_at: "2018-
03-07 16:59:42">, #<Product id: 4, title: "Oliver", description:
"Quisquam corporis voluptatem sint ut atque veniam ...", price:
0.6417e2, created_at: "2018-03-07 16:59:42", updated_at: "2018-03-07
16:59:42">]>
This function deletes all products with the same product_id
from the cart I would like to only destroy one
def remove_from_cart
Product.find(params[:id]).destroy
redirect_back fallback_location: root_path
end
Upvotes: 1
Views: 84
Reputation: 102250
You need to setup an join table and intermediary model between Cart and Product:
class Cart < ApplicationRecord
has_many :line_items
has_many :products, through: :line_items
end
# Think lines on an order form.
# columns:
# - quantity [Integer] default: 1
# - cart_id [Integer] foreign key, NOT NULL
# - product_id [Integer] foreign key, NOT NULL
class LineItem < ApplicationRecord
belongs_to :cart
belongs_to :product
validates_uniqueness_of :product_id, scope: :cart_id.
end
class Product
has_many :line_items
has_many :carts, through: :line_items
end
In your view you would display it like so:
<table>
<thead>
<tr>
<th>Name</th>
<th>Quantity</th>
<th>Destroy</th>
</tr>
</thead>
<tbody>
<% @cart.line_items.each do |line_item| %>
<tr>
<td><%= line_item.product.name %></td>
<td><%= line_item.quantity %></td>
<td><%= link_to line_item, method: :delete %></td>
</tr>
<% end %>
</tbody>
</table>
When adding an item to the cart you´re really just creating a line item. To remove an item you destroy the line item that links them:
class LineItemsController < ApplicationController
before_action :set_cart, only: [:create, :destroy]
# POST /line_items
def create
@product = Product.find(params[:line_item][:product_id])
if @cart.products.include?(@product)
@cart.line_items
.find_by!(product: @product)
.increment!(:quantity)
else
@cart.products << @product
end
redirect_to @cart
end
# DELETE /line_items/:id
def destroy
@line_item = LineItem.find(params[:id])
@line_item.destroy
redirect_to @cart
end
# ...
def set_cart
@cart = current_user.cart
end
end
Upvotes: 1