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
我有 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