Ruby on Rails выдает ошибку при удалении товаров из корзины - PullRequest
0 голосов
/ 08 декабря 2018

У меня есть 3 модели: корзина, LineItems и треки. Я добавляю треки в свою корзину с помощью ассоциаций с line_items.

Я могу успешно добавить трек в корзину, но когда я иду удалить ее, появляется следующая ошибкавыброшено:

undefined method 'line_items' for nil:NilClass

Что странно, если учесть, что метод, выдающий ошибку, не вызывает ту же ошибку при добавлении элемента;любая идея, что дает?Приложение поддерживает корзину, прикрепленную к сеансу пользователя, и использует идентификатор сеанса для распознавания уникальной корзины.

helpers> 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

views> layouts> 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

1 Ответ

0 голосов
/ 08 декабря 2018

Сообщение об ошибке гласит:

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

Вы пытаетесь вызвать line_items на @cart, что в данном случае, по-видимому,ноль.Попробуйте поставить чек раньше, изменив его на что-то вроде:

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
...