将产品从Cart,Ruby on rails中删除后,无法将产品添加回产品型号

时间:2016-10-02 17:14:38

标签: ruby-on-rails ruby postgresql cart

在电子商务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

3 个答案:

答案 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 的情况下在单行中编写控制器的描述。

除此之外,您还需要andProductsControllerCartControllerOrderController等等,每个人都应该做一份工作 - 并且做得好。< / 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,说明如何正确完成这项工作。如果你有时间坚持他的答案,并尝试根据他的建议重新设计你的应用程序。