在电子商务Rails应用程序中,构建从ShoppingCart中删除的产品在删除后不会添加回生产模型。
当我将产品添加到购物车时,应用程序正在使用此控制器来减少产品型号中的产品数量(请参阅创建方法)
controllers/product_item_controller.rb
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'
product = Product.find params[:product_id]
product.update_columns(stock_quantity: product.stock_quantity - 1)
else
render :new
end
end
private
def set_product_item
@product_item = ProductItem.find(params[:id])
end
def product_item_params
params.require(:product_item).permit(:product_id)
end
end
这很好。
但是当我删除购物车时,它会被删除,但产品不会添加到产品型号中。我也收到了这样的消息:Invalid Cart
这是carts_controller.rb
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
product = Product.find params[:product_id]
product.update_columns(stock_quantity: product.stock_quantity + 1)
redirect_to root_url, notice: 'Your Cart is Empty'
end
def remove
cart = session['cart']
item = cart['items'].find { |item| item['product_id'] == params[:id] }
product = Product.find(item['product_id'])
product.update_columns(stock_quantity: product.stock_quantity + 1)
if item
cart['items'].delete item
end
redirect_to cart_path
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
我无法看到此代码有什么问题,以及为什么产品在从购物车中删除后未添加到product.rb
。
我在这里遗漏了什么吗?有人可以在这里告诉我吗?
以下是其他相关型号和控制器
products_controller.rb
class ProductsController < ApplicationController
before_action :set_product, only: [:show, :edit, :update, :destroy]
def show
end
def search
@product = Product.search(params[:query]).order("created_at DESC")
@categories = Category.joins(:products).where(:products => {:id => @product.map{|x| x.id }}).distinct
end
private
# Use callbacks to share common setup or constraints between actions.
def set_product
@product = Product.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def product_params
params.require(:product).permit(:title, :description, :price_usd, :price_isl, :image, :category_id, :stock_quantity, :label_id, :query)
end
end
Cart.rb
模型
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_usd
product_items.to_a.sum{|item| item.total_price_usd}
end
def total_price_isl
product_items.to_a.sum{|item| item.total_price_isl}
end
end
product.rb
模型
Class Product < ActiveRecord::Base
belongs_to :category
belongs_to :label
has_many :product_item, :dependent => :destroy
#before_destroy :ensure_not_product_item
validates :title, :description, presence: true
validates :price_usd, :price_isl, numericality: {greater_than_or_equal_to: 0.01}
validates :title, uniqueness: true
has_attached_file :image, styles: { medium: "500x500#", thumb: "100x100#" }
validates_attachment_content_type :image, content_type: /\Aimage\/.*\z/
#def ensure_not_product_item
# if product_item.empty?
# return true
# else
# errors.add(:base, 'You have Product Items')
# return false
# end
#end
def self.search(query)
where("title LIKE ? OR description LIKE ?", "%#{query}%", "%#{query}%")
end
end
答案 0 :(得分:3)
您正在从ActiveRecord::RecordNotFound
rescue_from ActiveRecord::RecordNotFound, with: :invalid_cart
但是你可能不正确地从destroy方法中的Product.find...
救援......我不确定为什么你会期望product_id在params中。
您的代码......
def destroy
@cart.destroy if @cart.id == session[:cart_id]
session[:cart_id] = nil
product = Product.find params[:product_id]
product.update_columns(stock_quantity: product.stock_quantity + 1)
redirect_to root_url, notice: 'Your Cart is Empty'
end
更好的选择可能是......
def destroy
if @card.id == session[:cart_id]
@cart.product_items each do |product_item|
product_item.product.update_columns(stock_quantity: product_item.product.stock_quantity + 1)
end
@cart.destroy
end
end
但是,最好将此作为product_item模型的before_destroy
操作,因此销毁product_item会自动增加库存总数。
答案 1 :(得分:2)
我不会提供逐行解决方案,因为关于这个应用程序有很多要点不太正确,需要重新思考一下。让我们看看购物车是如何完成的。
var projection = d3.geoArmadillo();
var path = d3.geo.path()
.projection(projection);
d3.json("/d/4090846/world-110m.json", function(error, world) {
svg.insert("path", ".graticule")
.datum(topojson.object(world, world.objects.land))
.attr("class", "land")
.attr("d", path);
svg.insert("path", ".graticule")
.datum(topojson.mesh(world, world.objects.countries, function(a, b) { return a.id !== b.id; }))
.attr("class", "boundary")
.attr("d", path);
这里的命名不是错误或草率的复制粘贴。购物车只是网络应用中的一个概念,在创建订单时作为“用户帮助”存在。
订单和产品之间的连接通常称为订单项。请注意,我们使用class User < ApplicationRecord
has_many :orders
has_many :products, through: :orders
def current_order
orders.find_or_create_by(status: :open)
end
end
class Order < ApplicationRecord
enum status: [:in_cart, :processing, :shipped]
belongs_to :user
has_many :line_items
has_many :products, through: :line_items
end
# The join model between a Order and Product
# The name line item comes from the lines on a order form.
class LineItem < ApplicationRecord
belongs_to :order
belongs_to :product
end
class Product < ApplicationRecord
has_many :line_items
has_many :orders, through: :line_items
end
以便我们可以查询:
has_many though:
在构建像结帐一样复杂的东西时,您需要关注单一责任原则和KISS。拥有很多课程并不是件坏事。拥有巨大纠结的控制器太多了。
因此,例如创建一个控制器,它自己负责添加和删除购物车中的商品。
User.find(1).order
Product.find(1).orders
Order.find(1).products
请注意路径的路径清楚地告诉我们它的作用以及如何在不使用单词# routes.rb
resource :cart
resources :line_items,
only: [:create, :destroy, :update] do
collection do
delete :clear
end
end
end
# app/controllers/line_items.rb
class LineItemsController < ApplicationController
before_action :set_cart
before_action :set_item
rescue_from Orders::NotOpenError, -> { redirect_to @order, error: 'Order is locked and cannot be edited' }
# Add an item to cart
# POST /cart/line_items
def create
@cart.product_items.create(create_params)
# ...
end
# Remove an item from cart
# DESTROY /cart/line_items/:id
def destroy
@item.destroy
if @item.destroyed?
redirect_to cart_path, success: 'Item removed.'
else
redirect_to cart_path, alert: 'Could not remove item.'
end
end
# Remove all items from cart
# DESTROY /cart/line_items
def clear
@order.line_items.destroy_all
if @order.items.count.zero?
redirect_to cart_path, success: 'All items destroyed'
else
redirect_to cart_path, alert: 'Could not remove all items.'
end
end
# Update a line in the order
# PATCH /cart/line_items/:id
def update
@line_item.update(update_params)
end
private
def set_order
@order = current_user.current_order
# Ensure that order is not processed in some way
raise Orders::NotOpenError unless @order.open?
end
def set_line_item
@line_item = @order.line_items.find(params[:id])
end
def create_params
params.require(:line_item).permit(:product_id, :quantity)
end
def update_params
params.require(:line_item).permit(:quantity)
end
end
的情况下在单行中编写控制器的描述。
除此之外,您还需要and
,ProductsController
,CartController
,OrderController
等等,每个人都应该做一份工作 - 并且做得好。< / p>
当我们向订单添加订单项时,产品的可用库存当然会减少。这是业务逻辑的明确示例。
在MVC中,业务逻辑属于模型层。
将商品添加到购物车的用户只应创建预订。只有在订单处理或发货时,才能更改产品的实际库存:
PaymentsController
答案 2 :(得分:1)
你有
before_action :set_cart, only: [:show, :destroy]
rescue_from ActiveRecord::RecordNotFound, with: :invalid_cart
调用CartsController#destroy
方法后,将调用私有方法set_cart
。它尝试做的是初始化一个实例变量@cart = Cart.find(params[:id])
。
#destroy
方法的第一行是@cart.destroy if @cart.id == session[:cart_id]
。问题@cart = Cart.find(params[:id])
不是问题吗? params[:id]
的价值是多少?我想它与session[:cart_id]
不一样,可能是nil
或某个Intreger值,DB无法通过该值找到Cart记录,因此出错。
修改1:
同样适用于史蒂夫在answer中提到的product = Product.find params[:product_id]
。
Max发布了一篇非常有用的信息report,说明如何正确完成这项工作。如果你有时间坚持他的答案,并尝试根据他的建议重新设计你的应用程序。