Search code examples
ruby-on-railsrubyactiverecordhas-many-through

Has_Many_Through Failing To Push a Many to a Through


I'm trying to set up a has_many_through relationship where a User can have a cart with an item. I can add carts to the user (chip.carts << chips_cart) but I can't push items into my carts (chips_cart << coffee).

I get NoMethodError: undefined method <<' for #<Cart id: 5, user_id: nil>`

class User < ActiveRecord::Base
    has_many :carts
    has_many :items, through: :carts
end
class Cart < ActiveRecord::Base
    belongs_to :user
    has_many :items
end
class Item < ActiveRecord::Base
    belongs_to :carts
    has_many :users, through: :carts
end

chip = User.create(username: "Chip")
chips_cart = Cart.create
socks = Item.create(item: "socks", price: 5.00)

Solution

  • As pointed out by Hubert you have a pluralization error:

    belongs_to :cart # not :carts
    

    The name of belongs_to/has_one assocations should always be singular.

    And you don't need to use the shovel operator << in the first place:

    chip = User.create(username: "Chip")
    chips_cart = chip.carts.create
    socks = chips_cart.items.create(item: "socks", price: 5.00)
    

    Individual records don't respond to <<. Which is why you are getting NoMethodError: undefined method <<' for #<Cart id: 5, user_id: nil>. If you want to use the shovel operator you need to do chips_cart.items << socks instead of chips_cart << socks.

    Oh sweet syntactic sugar

    If you really wanted to be able to do chips_cart << socks you could implement the << method:

    class Cart < ApplicationRecord
      # ...
      def <<(item)
         items << item
      end
    end
    

    Thats because the shovel operator like many operators in Ruby is really just syntactic sugar for a method call.