0

This one has me a perplexed. I'm still a newbie with Rails so it may be simple.

The situation:

  1. I can add items to the cart, no problem. Everything works fine the current_cart method resolves to the same cart each request.
  2. But as soon as I remove a line item from the cart, it works, the line item is deleted, but the
    variable "session[:cart_id]" becomes null, and a new cart gets
    created when current_cart is called the next time.

I'm using Devise so I'm not sure if that has something to do with it, or maybe the line item delete method is cascade deleting the session or something like that.

The question is, can anyone help me understand why the session variable is becoming null after calling line_item delete?

I've created a cart application, following along with Agile web development with rails. Firstly, here's the code for application controller to retrieve the current cart:

  private
  def current_cart 
    Checkout::Cart.find(session[:cart_id])
  rescue ActiveRecord::RecordNotFound 
    cart = Checkout::Cart.create 
    session[:cart_id] = cart.id
    cart
  end

Now the code for my line item controller

class Checkout::LineItemsController < ApplicationController

# POST /checkout/line_items # POST /checkout/line_items.json def create

@cart = current_cart
product = Catalog::Product.find(params[:product_id])
apparel_event_log.info (product.to_json)


@checkout_line_item = @cart.line_items.find_or_initialize_by_sku_id(product.part_number)
new_quantity = @checkout_line_item.quantity || 0
@checkout_line_item.quantity = new_quantity+1
@checkout_line_item.line_item_description = product.name
@checkout_line_item.image = product.primary_image

respond_to do |format|
  if @checkout_line_item.save
    format.html { redirect_to @checkout_line_item.cart, notice: 'Line item was successfully created.' }
    format.json { render json: @checkout_line_item, status: :created, location: @checkout_line_item }
  else
    format.html { render action: "new" }
    format.json { render json: @checkout_line_item.errors, status: :unprocessable_entity }
  end
end   end

# DELETE /checkout/line_items/1 # DELETE /checkout/line_items/1.json def destroy Checkout::LineItem.delete(params[:id])

respond_to do |format|
  format.html { redirect_to current_cart, notice: 'Line item removed.' }
  format.json { head :no_content }
end   end end

and also the code for the line items model

class Checkout::LineItem < ActiveRecord::Base
  before_save :default_values

  attr_accessible :customer_update_date, :inventory_status, :line_item_color, :line_item_description, :line_item_size, :line_item_tagline, :line_item_total, :image, :quantity, :sku_id, :style_id, :tax, :tax_code, :timestamps, :unit_price, :cart, :product
  belongs_to :cart
  belongs_to :product, :class_name => 'Catalog::Product'
  has_one :image, :class_name => 'Assets::Medium'

  def default_values
     Rails.logger.debug { "Entering default values" }
     self.quantity ||= 0
   end

end
Richard G
  • 5,243
  • 11
  • 53
  • 95
  • did you check that the book example was working before you started making changes to it? check that all the tests are still passing at the end of Task D – prusswan Nov 01 '12 at 20:19
  • The book is okay, I'm kind of past the learning stage from the book and trying to implement the rest of the cart. The book didn't cover the delete line item really that I could see. – Richard G Nov 01 '12 at 21:12

2 Answers2

1

Ok I actually managed to solve this now. That was tough!

It appears to be some sort of problem using link_to ... :destroy or delete, where I think default rails code wasn't producing the CSRF protection and so was invalidating the session.

I've solved the main part by replacing the link_to with button_to to delete the line item and that seems to be working, at least functionally.

I really would prefer to use a link rather than a button. This seems to be a more common issue, so I'll hunt the forums for an answer, but if you know an answer, appreciate if you could please post a link or the answer directly on this thread.

Richard G
  • 5,243
  • 11
  • 53
  • 95
0

First you should move the logic into the model:

class Cart << AR
  def add(product_id)
    product = Catalog::Product.find(product_id)

    if item = self.line_items.find_or_initialize_by_sku_id(product.part_number)
      item.quantity = (item.quantity || 0) + 1
      item.line_item_description = product.name
      item.image = product.primary_image
      return item.save
    end
  end
end


class Checkout::LineItemsController < ApplicationController
    # POST /checkout/line_items # POST /checkout/line_items.json def create

    @cart = current_cart
    apparel_event_log.info (product.to_json)

    respond_to do |format|
      if @checkout_line_item = @cart.add(params[:product_id])
        format.html { redirect_to @checkout_line_item.cart, notice: 'Line item was successfully created.' }
        format.json { render json: @checkout_line_item, status: :created, location: @checkout_line_item }
      else
        format.html { render action: "new" }
        format.json { render json: @checkout_line_item.errors, status: :unprocessable_entity }
      end
    end   
end

Second you should add beginning:

  private
  def current_cart 
    begin
      Checkout::Cart.find(session[:cart_id])
    rescue ActiveRecord::RecordNotFound 
      cart = Checkout::Cart.create 
      session[:cart_id] = cart.id
      cart
    end
  end
BvuRVKyUVlViVIc7
  • 11,641
  • 9
  • 59
  • 111
  • thanks I tried to add the begin but it didn't work. A slight update, but it turns out that the line item delete method is actually deleting the entire session, not just the object from the session. I checked with session.inspect, and it changes the session id. – Richard G Nov 02 '12 at 08:38