Question

I am trying to add User Session ID into Line_Items table. I have researched everywhere and couldn't find the answer and that is why had to post it here. This application successfully adds the Phone ID and the Cart ID into the Line_Items table but doesn't let me add user session ID when I try the similar method of Phone and Cart ID. See below for my current implementation:

Line_Items Controller:

def create
  # current_cart method in application_controller.rb
  @cart = current_cart
  phone = Phone.find(params[:phone_id])
  if phone.stock > 0
    @line_item = @cart.add_phone(phone.id )
    if @line_item.save
      redirect_to  :back, notice: " '#{phone.model}'  has been added to your cart."
    else
      render action: "new" 
    end
  else
    redirect_to  :back, notice: " Cannot add: '#{phone.model}' - stock level is too low."
  end
end

Cart.rb Model:

def add_phone(phone_id)
  current_item = line_items.find_by_phone_id(phone_id)
  if current_item
    current_item.quantity += 1
  else
    current_item = line_items.build(phone_id: phone_id)
    current_item.quantity = 1
  end
  current_item.phone.stock -= 1
  current_item.phone.save
  current_item
end

# returns true if stock level is greater than zero
def can_add(phone)
  phone.stock > 0
end

Please let me know if any further code needed.

Was it helpful?

Solution

The issue is that the model classes in Rails don't know anything about the controller nor the session. I'm presuming you are using some authentication mechanism that gives you a current_user in your session... so we have to get that into your add_phone method.

In the controller, I'd change this line:

@line_item = @cart.add_phone(phone.id)

to this:

@line_item = @cart.add_phone(phone, current_user)

(notice there are two changes there - one to pass the phone rather than its id, since you already found it, and one to pass the current user.

Then we want to change your add_phone method to look like this:

def add_phone(phone, current_user = nil)
  # make sure your Item class initializes quantity to o, not nil.
  current_item = line_items.find_or_initialize_by_phone_id(phone.id)

  current_item.increment!(:quantity)
  current_item.phone.decrement!(:stock)
  current_item.user = current_user
  current_item.phone.save
  current_item
end

notice I'm setting the user to nil by default... that way, code you already have that doesn't provide that field will continue to work. I'm also simplifying your method a little bit with the find_or_initialize_by helper... avoids an 'if' test. Also, the increment and decrement helpers clean up the intent of the code a little.

You should make sure your line item class includes

belongs_to :user

If you find yourself in a situation where you need to know current_user for a lot of domain logic, you might want to check out the sentient_user gem.

OTHER TIPS

Save

There could be a number of reasons why your user ID is not being inserted:

 - Is `user_id` variable accessible from your model?
 - How are you saving `user_id`?
 - Where are you defining the `user_id` variable?

If you're using an instance method (like in Cart.rb) and something like Devise, you likely won't be able to access the current_user helper directly; you'll have to pass it through the method:

def add_user(user_id)
    @user = User.find(user_id)
    #etc
end

If you post errors or other code pertaining to the user object directly, we'll be in a much better position to help!


Refactoring

I think you'll benefit from the increment! & decrement! methods:

def add_phone(phone_id)
  current_item = line_items.find_by_phone_id(phone_id)
  if current_item
    current_item.incremenet!(:quality)
  else
    current_item = line_items.build(phone_id: phone_id)
    current_item.quantity = 1
  end
  current_item.phone.decrement!(:stock)
  current_item.phone.save
  current_item
end
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top