Home>

I am creating an EC site with Ruby_on_rails.

I want to implement the following when I press the "Add to cart" button on the product details screen (items # show).
(1) Generate a cart linked to the user id. The cart is managed by session.
(2) Make it possible to store the quantity, cart_id, and item_id of products in the cart_item table, which plays the role of an intermediate table between the cart table and the item table.

Currently, the following error is displayed.

NoMethodError in CartsController # add_item
undefined method `cart_items' for nil: NilClass
  def setup_cart_item!
    @cart_item = current_cart.cart_items.find_by (item_id: params [: item_id])
  end
end


https://gyazo.com/eed9afc25c8418b49721673f46d6b53b

It is an ER diagram of the entire application
https://gyazo.com/5350d2e6cdfe3d19a3e8037890ce5354

Below is the code for the relevant part

routing
# config/routes.rb
Rails.application.routes.draw do
  devise_for: users
  root to:'items # index'
  resources: items
  resources: carts, only: [: show] do
    member do
      post'/ add_item'=>' carts # add_item'
      post'/ update_item'=>' carts # update_item'
      delete'/ delete_item'=>' carts # delete_item'
    end
  end
end
#rails routes
add_item_cart POST/carts /: id/add_item (.: format) carts # add_item
update_item_cart POST/carts /: id/update_item (.: format) carts # update_item
delete_item_cart DELETE/carts /: id/delete_item (.: format) carts # delete_item
cart GET/carts /: id (.: format) carts # show
association
# app/models/user.rb
class User</pre>
<pre><code># app/models/cart.rb
class Cart</pre>
<pre><code># app/models/item.rb
class Item</pre>
<pre><code># app/models/cart_item.rb
class CartItem</pre>
<strong>View</strong>
<pre><code># app/views/items/show.html.erb (Product details screen)
~ Abbreviation ~<% = link_to add_item_cart_path, method:: post do%><button>Add to cart</button><% end%>
controller Definition of #current_cart method (hold cart information in session)
# app/controllers/application_controller.rb
class ApplicationController</pre>
<strong>carts controller</strong>
<pre><code># app/controllers/carts_controller.rb
class CartsController</pre>
<strong>There is a time when id is entered in both cart_items table once.</strong>
<p>It is when the routing is done as follows.</p>
<pre><code>resources: items do
  resources: carts
    post'/ add_item'=>' carts # add_item'
    post'/ update_item'=>' carts # update_item'
    delete'/ delete_item'=>' carts # delete_item'
end
#rails routes
item_add_item POST/items /: item_id/add_item (.: Format) carts # add_item
~ Omitted ~new_item_cart GET/items /: item_id/carts/new (.: format) carts # new


In this case, you will get the following error

NoMethodError in CartsController # add_item
undefined method `cart_url'for #<CartsController: 0x00007fa1e4688ed0>  @ cart_item.save
    redirect_to current_cart
  end

https://gyazo.com/14affbd26e5ed72bfc393da1a015ce96

Opinion

It's good that cart_items has a value, but I thought it would be strange to nest cart in item by routing, so I decided to remove the nesting, but then cart_items will not have a value.
I changed the routing and checked the params using binding.pry, but it doesn't work.
I'm really in trouble because I can't solve it easily.
I am sorry that it is long and difficult to read, but I would appreciate your help.
Thanks for your advice.

10/4 11:00 Addendum

I received comments from hatsu and tried to execute binding.pry in various places. It was hard to see in the comment section, so I added it to the text.
First, I checked session [: cart_id] of current_cart and whether Cart existed.

8: def current_cart
=>9: binding.pry
10: if session [: cart_id]
11: @cart = Cart.find_by (id: session [: cart_id])
12: else
13: @cart = Cart.create (user_id: current_user.id)
14: session [: cart_id] = @ cart.id
15: @cart = Cart.find_by (id: session [: cart_id])
16: @cart
17: end
18: end
[2] pry (#<CartsController>)>session [: cart_id]
=>13
[4] pry (#<CartsController>)>Cart.find_by (id: session [: cart_id])
Cart Load (0.5ms) SELECT `carts`. * FROM` carts` WHERE `carts`.ʻid` = 13 LIMIT 1
↳ (pry): 43: in `current_cart'
=>#<Cart: 0x00007fa1d1e9e1f0
id: 13,
user_id: 4,


And session [: cart_id] and its Cart seems to exist.

I also put binding.pry right after set_up_item!

34: def setup_cart_item!
=>35: binding.pry
36: @cart_item = current_cart.cart_items.find_by (item_id: params [: item_id])
37: end
[1] pry (#<CartsController>)>current_cart
Cart Load (0.5ms) SELECT `carts`. * FROM` carts` WHERE `carts`.ʻid` = 13 LIMIT 1
↳ app/controllers/application_controller.rb: 10: in `current_cart'
=>#<Cart: 0x00007fa1d1a4db50
id: 13,
user_id: 4,
created_at: Sun, 04 Oct 2020 00:26:44 JST +09: 00,
updated_at: Sun, 04 Oct 2020 00:26:44 JST +09: 00>[3] pry (#<CartsController>)>cart_items
NameError: undefined local variable or method `cart_items' for #<CartsController: 0x00007fa1d1886858>Did you mean? Cart_path


Here, I found that current_cart can be obtained.
However, [3] pry (#)>cart_items
Then again, it becomes undefined local variable or method `cart_items', and it comes out if cart_items is not defined. I applied binding.pry to the same place and changed the question

34: def setup_cart_item!=>35: binding.pry
36: @cart_item = current_cart.cart_items.find_by (item_id: params [: item_id])
37: end
[1] pry (#<CartsController>)>current_cart.cart_items
Cart Load (0.6ms) SELECT `carts`. * FROM` carts` WHERE `carts`.ʻid` = 13 LIMIT 1
↳ app/controllers/application_controller.rb: 10: in `current_cart'
CartItem Load (0.4ms) SELECT `cart_items`. * FROM` cart_items` WHERE `cart_items`.` cart_id` = 13
↳ app/controllers/carts_controller.rb: 35: in `setup_cart_item!'
=>[#<CartItem: 0x00007fa1d1eccde8
id: 15,
quantity: 0,
item_id: 29,
cart_id: 13,
created_at: Sun, 04 Oct 2020 02:25:43 JST +09: 00,
updated_at: Sun, 04 Oct 2020 02:25:43 JST +09: 00>]
[2] pry (#<CartsController>)>current_cart.cart_items.find_by (item_id: params [: item_id])
CACHE Cart Load (0.0ms) SELECT `carts`. * FROM` carts` WHERE `carts`.ʻid` = 13 LIMIT 1 [["id ", 13],

 ["LIMIT", 1]]
↳ app/controllers/application_controller.rb: 10: in `current_cart'
CartItem Load (0.5ms) SELECT `cart_items`. * FROM` cart_items` WHERE `cart_items`.` cart_id` = 13 AND `cart_items` .ʻitem_id` IS NULL LIMIT 1
↳ (pry): 55: in `setup_cart_item!'
=>nil

[1] pry (#)>current_cart.cart_items Then it seems that the contents of cart_items can also be obtained, [2] pry (#)>current_cart.cart_items.find_by (item_id: params [: item_id]) Then, it becomes nil.

def setup_cart_item!
@cart_item = current_cart.cart_items
end

And .find_by (item_id: params [: item_id] should be omitted?

If i try to pull it out and set binding.pry directly under the add_item method,

10: def add_item
=>11: binding.pry
12: if @ cart_item.blank?
13: @cart_item = current_cart.cart_items.build (item_id: params [: item_id])
14: end
15: @ cart_item.save
16: redirect_to current_cart
17: end
[1] pry (#<CartsController>)>@cart_item
CartItem Load (0.5ms) SELECT `cart_items`. * FROM` cart_items` WHERE `cart_items`.` cart_id` = 13
↳ app/controllers/carts_controller.rb: 11: in ʻadd_item'
=>[#<CartItem: 0x00007fa1d00d4548
id: 15,
quantity: 0,
item_id: 29,
cart_id: 13,
created_at: Sun, 04 Oct 2020 02:25:43 JST +09: 00,
updated_at: Sun, 04 Oct 2020 02:25:43 JST +09: 00>]

And we think that the set_up_item! Method can be executed. However, at this time,

NoMethodError in CartsController # add_item
undefined method `save'for #<CartItem :: ActiveRecord_Associations_CollectionProxy: 0x00007fa1eebacee8>Extracted source (around line # 16):
end
@ cart_item.save
redirect_to current_cart
end


You will not be able to save. What does it mean that the save method cannot be used? I would appreciate it if you could answer.
We apologize for the inconvenience, but thanks for your cooperation.

  • Answer # 1

    Nesting routing

    resources: carts, only: [: show]
    resources: items do
    Post'/ add_item'=>' carts # add_item'
    Post'/ update_item'=>' carts # update_item'
    Delete'/ delete_item'=>' carts # delete_item'
    end


    And I was able to save the value in the cart_items table by nesting add_item and others in item.

Related articles