# See ActionController::RequestForgeryProtection for details
# Uncomment the :secret if you're not using the cookie session store
- protect_from_forgery # :secret => 'd7e9713fb540572dab37a045152d442a'
+ protect_from_forgery :secret => 'd7e9713fb540572dab37a045152d442a'
# See ActionController::Base for details
# Uncomment this to filter the contents of submitted sensitive data parameters
@products = Product.find_products_for_sale
end
+ def add_to_cart
+ product = Product.find(params[:id])
+ @cart = find_cart
+ @cart.add_product(product)
+ rescue ActiveRecord::RecordNotFound
+ logger.error("Attempt to access invalid product #{params[:id]}" )
+ redirect_to_index('Invalid product')
+ end
+
+ def empty_cart
+ session[:cart] = nil
+ redirect_to_index('Your cart has been emptied')
+ end
+
+ private
+
+ def find_cart
+ session[:cart] ||= Cart.new
+ end
+
+ def redirect_to_index(msg)
+ flash[:notice] = msg
+ redirect_to :action => 'index'
+ end
+
end
--- /dev/null
+class Cart
+ attr_reader :items
+
+ def initialize
+ @items = []
+ end
+
+ def add_product(product)
+ current_item = @items.find {|item| item.product == product}
+ if current_item
+ current_item.increment_quantity
+ else
+ @items << CartItem.new(product)
+ end
+ end
+
+ def total_price
+ @items.sum {|item| item.price}
+ end
+
+end
--- /dev/null
+class CartItem
+ attr_reader :product, :quantity
+
+ def initialize(product)
+ @product = product
+ @quantity = 1
+ end
+
+ def increment_quantity
+ @quantity += 1
+ end
+
+ def title
+ @product.title
+ end
+
+ def price
+ @product.price * @quantity
+ end
+
+end
<a href="http://www..../contact">Contact</a><br />
</div>
<div id="main">
+ <% if flash[:notice] -%>
+ <div id="notice"><%= flash[:notice] %></div>
+ <% end -%>
+
<%= yield :layout %>
</div>
</div>
--- /dev/null
+<h2>Your Whimsical Cart</h2>
+
+<div class="cart-title">Your Cart</div>
+ <table>
+ <% for item in @cart.items %>
+ <tr>
+ <td><%= item.quantity %>×</td>
+ <td><%=h item.title %></td>
+ <td class="item-price"><%= number_to_currency(item.price, :unit => "£") %></td>
+ </tr>
+ <% end %>
+ <tr class="total-line">
+ <td colspan="2">Total</td>
+ <td class="total-cell"><%= number_to_currency(@cart.total_price, :unit => "£") %></td>
+ </tr>
+ </table>
+
+<%= button_to 'Empty cart', :action => :empty_cart %>
# Use the database for sessions instead of the cookie-based default,
# which shouldn't be used to store highly confidential information
# (create the session table with "rake db:sessions:create")
- # config.action_controller.session_store = :active_record_store
+ config.action_controller.session_store = :active_record_store
# Use SQL instead of Active Record's schema dumper when creating the test database.
# This is necessary if your schema can't be completely dumped by the schema dumper,
--- /dev/null
+class CreateSessions < ActiveRecord::Migration
+ def self.up
+ create_table :sessions do |t|
+ t.string :session_id, :null => false
+ t.text :data
+ t.timestamps
+ end
+
+ add_index :sessions, :session_id
+ add_index :sessions, :updated_at
+ end
+
+ def self.down
+ drop_table :sessions
+ end
+end
/* Global styles */
+/* Global styles */
+
+/* START:notice */
+#notice {
+ border: 2px solid red;
+ padding: 1em;
+ margin-bottom: 2em;
+ background-color: #f0f0f0;
+ font: bold smaller sans-serif;
+}
+/* END:notice */
+
h1 {
font: 150% sans-serif;
color: #226;
}
+/* START:cartmain */
+/* Styles for the cart in the main page */
+
+.cart-title {
+ font: 120% bold;
+}
+
+.item-price, .total-line {
+ text-align: right;
+}
+
+.total-line .total-cell {
+ font-weight: bold;
+ border-top: 1px solid #595;
+}
+/* END:cartmain */
+
+
/* The error box */
.fieldWithErrors {