TL;DR: controller instance variables are not shared across different HTTP requests as each request create a new instance of the controller.
Conceptually what you are expecting should have been correct! You are defining an instance variable and you should have access to it everywhere across the class.
The problem is that on every HTTP request, a new instance of the class is being created.
So when you hit the new action an instance of the controller will be initiated, new method will be called and @cart will be created and assigned. Something like:
# HTTP request /new
controller = MyController.new # an object of your controller is created
controller.new # the requested action is called and @cart is assigned
But when you make a new HTTP request to update a new instance of the controller will be initiated, update method will be called and it has no @cart!
# HTTP request /update
controller1 = MyController.new # an object of your controller is created
controller1.new # the requested action is called and @cart is not assigned 😱
As you can see controller and controller1 are two different objects initiated from MyController as this took place in two different HTTP requests (different contexts).
To fix your issue you need to create @cart for each action when it's needed something like:
def new
cart
end
def update
logger.debug cart.present?
end
private
def cart
@cart ||= Cart.new(session[:cart])
end