Ruby on Rails 从购物车中移除商品时抛出错误

Ruby on Rails throws error when removing items from a cart

我有 3 个模型:Cart、LineItems 和 Tracks 我通过与 line_items.

的关联将曲目添加到我的购物车

我可以成功地将轨道添加到购物车,但是当我将其删除时出现以下错误:

undefined method 'line_items' for nil:NilClass

考虑到抛出错误的方法在添加项目时不会引发相同的错误,这很奇怪;知道什么给了吗? 该应用程序维护附加到用户会话的购物车,并使用会话 ID 来识别唯一的购物车。

帮手 > application_helper.rb

module ApplicationHelper


  def cart_count_over_one
    if cart_has_items
      return  "<span class='tag is-dark'>#{cart_has_items}</span>".html_safe
    end
  end

  def cart_has_items
    total = @cart.line_items.map{ |item| item.quantity }.sum #error occurs here
    return total if total > 0
  end

end

浏览量 > 布局> application.html.haml

!!!
%html
  %head
    %title Home
    %meta{:content => "width=device-width, initial-scale=1", :name => "viewport"}/
    = stylesheet_link_tag 'https://maxcdn.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css'
    = stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track': 'reload'
    = javascript_include_tag 'modernizr'
    = csrf_meta_tags
  %body{:class => yield(:body_class)}
    - if flash[:notice]
      .notification.is-success.global-notification
        %p.notice= notice
    - if flash[:alert]
      .notification.is-danger.global-notification
        %p.alert= alert
    %nav.navbar.is-warning{"aria-label" => "main navigation", :role => "navigation"}
      .navbar-brand
        = link_to root_path, class:"navbar-item" do
          %h1.title.is-centered Cscades
        .navbar-burger.burger{"data-target" => "navbar"}
          %span
          %span
          %span
      #navbar.navbar-menu
        .navbar-end
          .navbar-item
            .field.is-grouped
              - if cart_has_items #method gets called here
                = link_to cart_path(@cart), class:"navbar-item button is-warning" do
                  %span.icon.is-small
                    %i.fa.fa-shopping-cart
                  %span
                    Cart
                    \#{cart_count_over_one}
              - if user_signed_in?
                = link_to 'Sell', new_track_path, class: "navbar-item button is-dark"
                .navbar-item.has-dropdown.is-hoverable
                  = link_to 'Account', edit_user_registration_path, class: "navbar-link"
                  .navbar-dropdown.is-right
                    = link_to current_user.name, edit_user_registration_path, class:"navbar-item"
                    = link_to "Log Out", destroy_user_session_path, method: :delete, class:"navbar-item"
              - else
                = link_to "Sign In", new_user_session_path, class:"navbar-item button is-warning"
                = link_to "Sign up", new_user_registration_path, class:"navbar-item button is-warning"
    = yield(:header)
    .container
      = yield

line_items_controller.rb

class LineItemsController < ApplicationController
  include CurrentCart
  before_action :set_cart, only: [:create]
  before_action :set_line_item, only: [:show, :edit, :update, :destroy]


  # GET /line_items
  # GET /line_items.json
  def index
    @line_items = LineItem.all
  end

  # GET /line_items/1
  # GET /line_items/1.json
  def show
  end

  # GET /line_items/new
  def new
    @line_item = LineItem.new
  end

  # GET /line_items/1/edit
  def edit
  end

  # POST /line_items
  # POST /line_items.json
  def create
    @track  = Track.find(params[:track_id])
    @line_item = @cart.add_track(@track)

    respond_to do |format|
      if @line_item.save
        format.html { redirect_to @line_item, notice: 'Line item was successfully created.' }
        format.json { render :show, status: :created, location: @line_item }
      else
        format.html { render :new }
        format.json { render json: @line_item.errors, status: :unprocessable_entity }
      end
    end
  end

  # PATCH/PUT /line_items/1
  # PATCH/PUT /line_items/1.json
  def update
    respond_to do |format|
      if @line_item.update(line_item_params)
        format.html { redirect_to @line_item, notice: 'Line item was successfully updated.' }
        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

  # DELETE /line_items/1
  # DELETE /line_items/1.json
  def destroy
    @cart = Cart.find(session[:cart_id])
    @line_item.destroy
    respond_to do |format|
      format.html { redirect_to cart_path(@cart), notice: 'Line item was successfully destroyed.' }
      format.json { head :no_content }
    end
  end

  private
    # Use callbacks to share common setup or constraints between actions.
    def set_line_item
      @line_item = LineItem.find(params[:id])
    end

    # Never trust parameters from the scary internet, only allow the white list through.
    def line_item_params
      params.require(:line_item).permit(:track_id)
    end
end

carts_controller.rb

class CartsController < ApplicationController
  rescue_from ActiveRecord::RecordNotFound, with: :invalid_cart
  before_action :set_cart, only: [:show, :edit, :update, :destroy]

  # GET /carts
  # GET /carts.json
  def index
    @carts = Cart.all
  end

  # GET /carts/1
  # GET /carts/1.json
  def show
  end

  # GET /carts/new
  def new
    @cart = Cart.new
  end

  # GET /carts/1/edit
  def edit
  end

  # POST /carts
  # POST /carts.json
  def create
    @cart = Cart.new(cart_params)

    respond_to do |format|
      if @cart.save
        format.html { redirect_to @cart, notice: 'Cart was successfully created.' }
        format.json { render :show, status: :created, location: @cart }
      else
        format.html { render :new }
        format.json { render json: @cart.errors, status: :unprocessable_entity }
      end
    end
  end

  # PATCH/PUT /carts/1
  # PATCH/PUT /carts/1.json
  def update
    respond_to do |format|
      if @cart.update(cart_params)
        format.html { redirect_to @cart, notice: 'Cart was successfully updated.' }
        format.json { render :show, status: :ok, location: @cart }
      else
        format.html { render :edit }
        format.json { render json: @cart.errors, status: :unprocessable_entity }
      end
    end
  end

  # DELETE /carts/1
  # DELETE /carts/1.json
  def destroy
    @cart.destroy if cart.id == session[:cart_id] #hook into current client session instead of user
    session[:cart_id] = nil
    respond_to do |format|
      format.html { redirect_to root-path, notice: 'Cart was successfully destroyed.' }
      format.json { head :no_content }
    end
  end

  private
    # Use callbacks to share common setup or constraints between actions.
    def set_cart
      @cart = Cart.find(params[:id])
    end

    # Never trust parameters from the scary internet, only allow the white list through.
    def cart_params
      params.fetch(:cart, {})
    end

    def invalid_cart
      logger.error "Attempt to access invalid cart #{params[:id]}"
      redirect_to root_path, notice: "That cart doesn't exist"
    end
end

错误消息说:

undefined method 'line_items' for nil:NilClass

你说的指向:

def cart_has_items
  total = @cart.line_items.map{ |item| item.quantity }.sum #error occurs here
  return total if total > 0
end

您正在尝试在@cart 上调用 line_items,在本例中显然为 nil。 尝试在之前进行检查,将其更改为:

def cart_has_items
  return false unless @cart

  total = @cart.line_items.map{ |item| item.quantity }.sum #error occurs here
  return total if total > 0
end