简体   繁体   中英

Rails 4: NoMethodError

I am creating a simple ecommerce application with a shopping cart. However when I try to add a product to the cart I get an error

NoMethodError at /carts/1/add/1
undefined method `add_item' for []:Array

Here are my controllers

  • application_controller.rb

     class ApplicationController < ActionController::Base protect_from_forgery with: :exception def initialize_cart @cart = Cart.build_from_hash session end end 
  • carts_controller.rb

     class CartsController < ApplicationController before_filter :initialize_cart def add @cart.add_item params[:id] set_product redirect_to :back, notice: "Added #{product.name} to cart" end private def set_product @product = Product.find params[:id] end end 
  • products_controller.rb

     class ProductsController < ApplicationController before_action :set_product, only: [:show, :edit, :update, :destroy] before_filter :initialize_cart def index @products = Product.all end def show end def new @product = Product.new end def edit end def create @product = Product.new(product_params) respond_to do |format| if @product.save format.html { redirect_to @product, notice: 'Product was successfully created.' } format.json { render :show, status: :created, location: @product } else format.html { render :new } format.json { render json: @product.errors, status: :unprocessable_entity } end end end def update respond_to do |format| if @product.update(product_params) format.html { redirect_to @product, notice: 'Product was successfully updated.' } format.json { render :show, status: :ok, location: @product } else format.html { render :edit } format.json { render json: @product.errors, status: :unprocessable_entity } end end end def destroy @product.destroy respond_to do |format| format.html { redirect_to products_url, notice: 'Product was successfully destroyed.' } format.json { head :no_content } end end private def set_product @product = Product.find(params[:id]) end def product_params params.require(:product).permit(:name, :price, :image) end end 

Here are my models

  • product.rb

     class Product < ActiveRecord::Base mount_uploader :image, ImageUploader validates_presence_of :name, :price validates_numericality_of :price end 

The following are tableless classes in the model directory

  • cart.rb

     class Cart attr_reader :items def self.build_from_hash hash items = if hash["cart"] then hash["cart"]["items"].map do |item_data| CartItem.new item_data["product_id"], item_data["quantity"] end else [] end end def initialize items = [] @items = items end def add_item product_id item = @items.find {|item| item.product_id == product_id} if item item.increment else @items << CartItems.new(product_id) end end def empty? @item.empty? end def serialize items = @items.map do |item| { "product_id" => item.product_id, "quantity" => item.quantity } end { "cart" => { "items" => items } } end end 
  • cart_item.rb

     class CartItem attr_reader :product_id, :quantity def initialize product_id, quantity = 1 @product_id = product_id @quantity = quantity end def increment @quantity += 1 end def product Product.find product_id end end 

Here is a screenshot of my error

error_screenshot

Solved the No Method Error by making initializing @items array in the Cart class at the end of the build_from_hash method

Here is the solution

def self.build_from_hash hash
    items = if hash["cart"] then
      hash["cart"]["items"].map do |item_data|
        CartItem.new item_data["product_id"], item_data["quantity"]
      end
    else
      []
    end

    new items    
  end

Now I am getting a new error

NameError at /carts/1/add/1
uninitialized constant Cart::CartItems

There is no add_item method for arrays which is what your @cart object is when it is returned from Cart.build_from_hash . Well, in this case it looks like it's passing through your "else" statement which is returning an empty array. Is that what you intended to occur?

If so, you append to arrays using something like this:

array << "object"

Edit here because comment editing sucks:

Alright, you're initializing @cart by using:

@cart = Cart.build_from_hash session

Cart.build_from_hash returns an Array object. This is where you need to be returning a Cart object if you want to be able to use Cart.add_item. The easiest way would just add return self to the end of Cart.build_from_hash but I'm fairly certain that will open up other problems if you're using @cart as an actual array at some point.

Of course if you want this Cart object to be saved in your database you'll have to actually create it at some point unless you just wanted to keep all the data in an array until the very end.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM