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