MarkD
MarkD

Reputation: 75

undefined method 'name' for nil:NilClass, but I know the record exists

I am trying to build a simple cart based on sessions. I am using this youtube tutorial as an template: vid#4 here https://www.youtube.com/watch?v=WRVwfVUaj_Y and vid#5 here https://www.youtube.com/watch?v=HSMqi913SL4.

I am getting the same error that he gets in vid#5 at , but he doesn't show how he fixed it.

Here are my routes:

get '/cart' => 'cart#index'
get '/cart/clear' => 'cart#clearCart'
get '/cart/:id' => 'cart#add'

And here is my cart_controller.rb:

class CartController < ApplicationController

  def add
    id = params[:id]

    if session[:cart] then
      cart = session[:cart]
    else
      session[:cart] = {}
      cart = session[:cart]
    end

    if cart[id] then
      cart[id] = cart[id] + 1
    else
      cart[id] = 1
    end

    redirect_to :action => :index
  end

  def clearCart
    session[:cart] = nil
    redirect_to :action => :index
  end

  def index


    if session[:cart] then
      @cart = session[:cart]
    else
      @cart = {}
    end
  end
end

Here is my cart/index.html.erb page:

<h3>Your Shopping Cart</h3>

<%= link_to "Empty Your Cart", cart_clear_path %>

<% total = 0 %>

<% @cart.each do | id, quantity | %>
    <% product = Product.find_by_id(id)%>

<div class="row">
    <div class="col-lg-3 col-md-3 col-sm-6 col-xs-12" >

        <div class="product_text">
            <h3><%= product.name %></h3>
            <h3><%= product.description %></h3>
            <h3>$<%= product.price %></h3>


        </div>  
    </div>
</div>

<%end%>

I am very confused because I know the Product object exists, but I am still getting the error in title.

Upvotes: 0

Views: 107

Answers (2)

MarkD
MarkD

Reputation: 75

Thanks to everyone for the help, but I found the solution. I needed to sanitize the id with .gsub('"', '') before I could pass it through to find_by_id.

This worked:

<% @cart.each do | id , qty | %>
<% p = Product.find_by_id(id.gsub('"', '')) %>
<%= p.name %> <%= qty %>
<%end%>

Upvotes: 0

Andy Gauge
Andy Gauge

Reputation: 1428

You could try assigning the cart variable back to the session after you do the addition

def add
  id = params[:id]
  cart = session[:cart] || {}
  cart[id] = 0 unless cart[id]
  cart[id] = cart[id] + 1
  session[:cart] = cart
  redirect_to :action => :index
end

BTW I don't think if should be included in the language

def index
  @cart = session[:cart] || {}
end

edit

The way I would have processed the Product is in the controller. I have reservations about ever seeing the Model inside the view. I'm not sure if this is a design pattern or not, but I would pass an array of products to the view rather than a collection of Arrays to look up. I know for a fact this helps the test-ability of the code.

# app/controllers/cart_controller.rb  #should be carts_controller for RAILS convention
def index
  @cart = []
  session[:cart].each do |product_id, qty|
    @cart << {product: Product.find(product_id) , qty: qty}
  end
end    

To use this in the view just @cart.each do |c| <%=c.product.name %> <%=c.qty %>

Upvotes: 1

Related Questions