# Cart configuration and sessions

**URL:** <https://www.ruby-forum.com/t/cart-configuration-and-sessions/229129>\
**Category:** Rails\
**Created:** [October 18, 2007, 9:14am UTC](https://www.ruby-forum.com/t/cart-configuration-and-sessions/229129 "2007-10-18T09:14:38Z")\
**Posts on this page:** 2\
**Page:** 1

<div class="post-metadata">

**Author:** ![elle](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/e/ccd318/32.png) [@elle](https://www.ruby-forum.com/u/elle)\
**Post date:** [October 18, 2007, 9:14am UTC](https://www.ruby-forum.com/t/cart-configuration-and-sessions/229129/1 "2007-10-18T09:14:38Z")

</div>

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" %\>

---

<div class="post-metadata">

**Author:** ![elle](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/e/ccd318/32.png) [@elle](https://www.ruby-forum.com/u/elle)\
**Post date:** [October 18, 2007, 3:36pm UTC](https://www.ruby-forum.com/t/cart-configuration-and-sessions/229129/2 "2007-10-18T15:36:53Z")

</div>

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
