Cart configuration and sessions

Hi,

I guess as many people, I am very new to Rails. I used a book to
create a shopping cart and then modified the code to try and fit it to
my project’s requirements. I have been trying figure this out for the
last week and starting to get really discouraged about the prospects
of solving this. I know what needs to be done but I’m at a loss for
how to achieve it. So, I wanted to ask, for help. Please please
please.

Background:
I have the following classes: customer, product, cart, cart_items,
order, order_items
A customer needs to login to even see the “Add to cart” links – so
the same goes for viewing cart and checkout. (which is achieved).
Things I have trouble with:

  1. The sessions are stored in the db. Right now, customer session and
    cart session are separate. I need to assoociate them together. So,
    when a customer loggs out and a new customer logs in, they have
    different carts. If the session can remember the cart items, if the
    same customer logs in again, that would be great. The customer id will
    also need to be stored in the orders tables as well.
  2. I suddently have trouble even trying to add an item to the cart.
  3. I need to figure out a way to update the quantity of items
    (products) in the cart.
  4. And lastly, my checkout page doesn’t come up suddenly as well

Please can anyone have a look and help me solve this?
Any help will be so much appreciated,
Thanks,
Elle


MODELS
customer.rb:

class Customer < ActiveRecord::Base
has_many :orders,
:dependent => true,
:order => “created_at ASC”
has_many :carts

validates_length_of :name, :within => 3…40
validates_uniqueness_of :name
validates_length_of :password, :within => 4…40, :if
=> :password_required?

def open_orders
orders.find(:all, :conditions => “status = ‘open’”)
end

def orders_history
orders.find(:all, :conditions => “status = ‘closed’”)
end

def password=(value)
write_attribute(“password”, Digest::SHA1.hexdigest(value))
end

def self.authenticate(name,password)
find(:first, :conditions => [“name = ? and password = ?”,name,
Digest::SHA1.hexdigest(password)])
end

def self.orders
current_customer = Customer.find(param[:id])
orders = current_customer.orders
end

def self.carts
current_customer = Customer.find(param[:id])
orders = current_customer.carts
end

end


cart.rb:

class Cart < ActiveRecord::Base
has_many :cart_items
has_many :products, :through => :cart_items
belongs_to :customer

def total
cart_items.inject(0) {|sum, n| n.price * n.amount + sum}
end

def add(product_id)
items = cart_items.find_all_by_product_id(product_id)
product = Product.find(product_id)
if items.size < 1
ci = cart_items.create(:product_id => product_id,
:amount => 1,
:price => product.price)
else
ci = items.first
ci.update_attribute(:amount, ci.amount + 1)
end
ci
end

def remove(product_id)
ci = cart_items.find_by_product_id(product_id)

if ci.amount > 1
  ci.update_attribute(:amount, ci.amount - 1)
else
  CartItem.destroy(ci.id)
end
return ci

end

def update(product_id)
items = cart_items.find_all_by_product_id(product_id)
product = Product.find(product_id)
ci = cart_items
ci.update_attribute(:amount, ci.amount + 1)

end

end


CONTROLLER
cart_controller.rb:

class CartController < ApplicationController
before_filter :initialize_cart
before_filter :authorize, :except => [“login”]

def authorize
return true if @c
flash[:notice] = “To place your order please login”
redirect_to :controller => “catalog”
end

def login
# examine the form data for “name” and “password”
pw,name = params[:customer].values_at(*%w{password name})
# Retrieve the customer record for the name and store it in a
variable ‘c’
c = Customer.find_by_name(name)
# if such record exists, and it’s password matches the password
from the form
if c && Digest::SHA1.hexdigest(pw) == c.password
# start a session with the customer id
session[:customer] = c.id
@cart = Cart.create
session[:customer]

    if @cart.products.empty?
       redirect_to :controller => "catalog"
    else

    redirect_to :action => "view_cart"
    end
else
  # otherwise report an error
  flash[:notice] = "Invalid Login"
  redirect_to :controller => "catalog"
end

end

def logout
session[:customer] = nil
redirect_to :controller => “catalog”
end

def index
end

def add
product = Product.find(params[:id])
if request.post?
@item = @cart.add(params[:id])
flash[:notice] = “Added #{@item.product.title} to
cart.”
redirect_to :controller => “catalog”
else
render
end
end

def update
@product = Product.find(params[:id])
if request.post?
@item = @cart.update_attributes(params[:cart])
flash[:notice] = “Updated #{@item.product.title}'s
quantity.”
redirect_to :action => “view_cart” and return if @cart.save
else
render
end
end

def remove
@product = Product.find(params[:id])
if request.post?
@item = @cart.remove(params[:id])
flash[:notice] = “Removed #{@item.product.title}
redirect_to :action => “view_cart”
else
render
end
end

def clear
if request.post?
@cart.cart_items.destroy_all
flash[:notice] = “Cleared the cart”
redirect_to :controller => “catalog”
else
render
end
end

def view_cart
@page_title = “Shopping Cart for #{@c.name}”
@order = Order.new
if @cart.empty?
flash[:notice] = “Your shopping cart is empty! Please add
something to it before proceeding to checkout.”
redirect_to :controller => ‘catalog’
end
end

def checkout
@page_title = “Checkout”
@order = Order.new(params[:order])
@order.customer_ip = request.remote_ip
@order.customer_id = @session[‘customer’]
populate_order

if @order.save
  if @order.process
    flash[:notice] = 'Your order has been submitted, and will be

processed immediately.’
session[:order_id] = @order.id
# Empty the cart
@cart.cart_items.destroy_all
redirect_to :action => ‘thank_you’
else
flash[:notice] = “Error while placing order.
‘#{@order.error_message}’”
render :action => ‘view_cart’
end
else
render :action => ‘view_cart’
end
end

def thank_you
@page_title = ‘Thank You!’
end

def populate_order
for cart_item in @cart.cart_items
order_item = OrderItem.new(
:product_id => cart_item.product_id,
:price => cart_item.price,
:amount => cart_item.amount
)
@order.order_items << order_item
end
end

end


VIEWS
partial for cart item: _item.rhtml:

<%=h item.product.sku %> <%= link_to item.product.title, :action => "show", :controller => "catalog", :id => item.product.id %> <%= pluralize(item.amount, "pc", "pcs") %> $<%= two_dec(item.price * item.amount) %> <%= form_tag :controller => "cart", :action => "update", :id => item.product, :with => "new_qty" %> <%= text_field_tag "new_qty", "", "size" => 4 %> <%= end_form_tag %> <%= button_to "x", :controller => "cart", :action => "remove", :id => item.product %>

checkout.rhtml:

<%= error_messages_for ‘order’ %>

Your order’s total is: <%=h @cart.total %>

Contact Information

Email

<%= text_field :order, :email %>

<p><label for="order_phone_number">Phone number</label></p>
<p><%= text_field :order, :phone_number %></p>
Shipping Address

First name

<%= text_field :order, :ship_to_first_name %>

<p><label for="order_ship_to_last_name">Last name</label></p>
<p><%= text_field :order, :ship_to_last_name %></p>

<p><label for="order_ship_to_address">Address</label></p>
<p><%= text_field :order, :ship_to_address %></p>

<p><label for="order_ship_to_city">City</label></p>
<p><%= text_field :order, :ship_to_city %></p>

<p><label for="order_ship_to_postal_code">Postal/Zip code</label></

p>

<%= text_field :order, :ship_to_postal_code %>

<p><label for="order_ship_to_country">Country</label></p>
<p>
<select name="order[ship_to_country]" id="order_ship_to_country">
  <option value="US">United States</option>
  <option value="CA">Canada</option>
</select>
</p>

<%= submit_tag "Place Order" %>

While what you are asking is about 20 questions, I will answer this.
The
functionality you are looking for with your shopping cart would really
require you to persist the card and items as a database table. Then
write
logic to save it when things are added/removed and to recall it from the
DB
when a use logs in. A session is not the right place for this type of
functionality. The problem with long running carts, is that if you
change
the price on something you may have a persisted cart item that has a
differnet price, so you need to decide if you persist the price when the
user adds items to the cart, or you keep it linked to the product that
may
change over time.

-Jake