【转】学习ruby on rails 笔记(第一版)depot源代码
关键字: 学习笔记 ruby on rails depot
完整的Depot应用源代码 Source Code
参考 《应用 Rails 进行敏捷 Web 开发》第一版
林芷薰 翻译
透明 审校
Database Files
数据库文件
D:\work\depot\config\database.yml
1.development:
2. adapter: mysql
3. database: depot_development
4. username: root
5. password:
6. host: localhost
7.
8.# Warning: The database defined as 'test' will be erased and
9.# re-generated from your development database when you run 'rake'.
10.# Do not set this db to the same as development or production.
11.test:
12. adapter: mysql
13. database: depot_test
14. username: root
15. password:
16. host: localhost
17.
18.production:
19. adapter: mysql
20. database: depot_production
21. username: root
22. password:
23. host: localhost
D:\work\depot\db\create.sql
1.drop table if exists users;
2.drop table if exists line_items;
3.drop table if exists orders;
4.drop table if exists products;
5.
6.create table products (
7. id int not null auto_increment,
8. title varchar(100) not null,
9. description text not null,
10. image_url varchar(200) not null,
11. price decimal(10,2) not null,
12. date_available datetime not null,
13. primary key(id)
14.);
15.
16.create table orders (
17. id int not null auto_increment,
18. name varchar(100) not null,
19. email varchar(255) not null,
20. address text not null,
21. pay_type char(10) not null,
22. shipped_at datetime null,
23. primary key (id)
24.);
25.
26.create table line_items (
27. id int not null auto_increment,
28. product_id int not null,
29. order_id int not null,
30. quantity int not null default 0,
31. unit_price decimal(10,2) not null,
32. constraint fk_items_product foreign key (product_id) references products(id),
33. constraint fk_items_order foreign key (order_id) references orders(id),
34. primary key (id)
35.);
36.
37.create table users (
38. id int not null auto_increment,
39. name varchar(100) not null,
40. hashed_password char(40) null,
41. primary key (id)
42.);
43.
44./* password = 'admin' */
45.insert into users values(null, 'admin','d033e22ae348aeb5660fc2140aec35850c4da997');
D:\work\depot\db\product_data.sql
1.lock tables products write;
2.insert into products( title, description, image_url, price, date_available ) values(
3. 'Pragmatic Project Automation',
4. 'A really great read!',
5. 'http://localhost:3000/images/svn.JPG',
6. '29.95',
7. '2007-12-25 05:00:00' );
8.insert into products( title, description, image_url, price, date_available ) values(
9. 'Pragmatic Version Control',
10. 'A really contrlooed read!',
11. 'http://localhost:3000/images/utc.jpg',
12. '29.95',
13. '2007-12-01 05:00:00');
14.insert into products( title, description, image_url, price, date_available ) values(
15. 'Pragmatic Version Control2',
16. 'A really contrlooed read!',
17. 'http://localhost:3000/images/auto.jpg',
18. '29.95',
19. '2007-12-01 05:00:00');
20.unlock tables;
D:\work\depot\db\product_data2.sql
1.lock tables products write;
2.insert into products( title, description, image_url, price, date_available ) values(
3. 'Pragmatic Project Automation',
4. 'A really great read!',
5. '/images/svn.JPG',
6. '29.95',
7. '2007-12-25 05:00:00' );
8.insert into products( title, description, image_url, price, date_available ) values(
9. 'Pragmatic Version Control',
10. 'A really contrlooed read!',
11. '/images/utc.jpg',
12. '29.95',
13. '2007-12-01 05:00:00');
14.insert into products( title, description, image_url, price, date_available ) values(
15. 'Pragmatic Version Control2',
16. 'A really contrlooed read!',
17. '/images/auto.jpg',
18. '29.95',
19. '2007-12-01 05:00:00');
20.unlock tables;
控制器
D:\work\depot\app\controllers\application.rb
1.class ApplicationController < ActionController::Base
2. model :cart
3. model :line_item
4.
5. # Pick a unique cookie name to distinguish our session data from others'
6. session :session_key => '_depot_session_id'
7.
8. private
9. def redirect_to_index(msg = nil)
10. flash[:notice] = msg if msg
11. redirect_to(:action => 'index')
12. end
13.
14. def authorize
15. unless session[:user_id]
16. flash[:notice] = "Please log in"
17. redirect_to(:controller => "login", :action => "login")
18. end
19. end
20.
21.end
D:\work\depot\app\controllers\admin_controller.rb
1.class AdminController < ApplicationController
2. before_filter :authorize
3.
4. # GETs should be safe (see http://www.w3.org/2001/tag/doc/whenToUseGet.html)
5. verify :method => :post, :only => [ :destroy, :create, :update ],
6. :redirect_to => { :action => :list }
7.
8. def index
9. list
10. render :action => 'list'
11. end
12.
13. def list
14. @product_pages, @products = paginate :products, :per_page => 10
15. end
16.
17. def show
18. @product = Product.find(params[:id])
19. end
20.
21. def new
22. @product = Product.new
23. end
24.
25. def create
26. @product = Product.new(params[:product])
27. if @product.save
28. flash[:notice] = 'Product was successfully created.'
29. redirect_to :action => 'list'
30. else
31. render :action => 'new'
32. end
33. end
34.
35. def edit
36. @product = Product.find(params[:id])
37. end
38.
39. def update
40. @product = Product.find(params[:id])
41. if @product.update_attributes(params[:product])
42. flash[:notice] = 'Product was successfully updated.'
43. redirect_to :action => 'show', :id => @product
44. else
45. render :action => 'edit'
46. end
47. end
48.
49. def destroy
50. Product.find(params[:id]).destroy
51. redirect_to :action => 'list'
52. end
53.
54. def ship
55. count = 0
56. if things_to_ship = params[:to_be_shipped]
57. count = do_shipping(things_to_ship)
58. if count > 0
59. count_text = pluralize(count, "order")
60. flash.now[:notice] = "#{count_text} marked as shipped"
61. end
62. end
63. @penging_orders = Order.pending_shipping
64. end
65.
66. private
67. def do_shipping(things_to_ship)
68. count = 0
69. things_to_ship.each do |order_id, do_it|
70. if do_it == "yes"
71. order = Order.find(order_id)
72. order.mark_as_shipped
73. order.save
74. count += 1
75. end
76. end
77. count
78. end
79.
80. def pluralize(count, noun)
81. case count
82. when 0: "No #{noun.pluralize}"
83. when 1: "One #{noun}"
84. else "#{count} #{noun.pluralize}"
85. end
86. end
87.
88.end
D:\work\depot\app\controllers\login_controller.rb
1.class LoginController < ApplicationController
2. layout "admin"
3. before_filter :authorize, :except => :login
4.
5. def index
6. @total_orders = Order.count
7. @pending_orders = Order.count_pending
8. end
9.
10. def login
11. if request.get?
12. session[:user_id] = nil
13. @user = User.new
14. else
15. @user = User.new(params[:user])
16. logged_in_user = @user.try_to_login
17. if logged_in_user
18. session[:user_id] = logged_in_user.id
19. redirect_to(:action => "index")
20. else
21. flash[:notice] = "Invalid user/password conbination"
22. end
23. end
24. end
25.
26. def add_user
27. if request.get?
28. @user = User.new
29. else
30. @user = User.new(params[:user])
31. if @user.save
32. redirect_to_index("User #{@user.name} created")
33. end
34. end
35. end
36.
37. def delete_user
38. id = params[:id]
39. if id && user = User.find(id)
40. begin
41. user.destroy
42. flash[:notice] = "User #{user.name} deleted"
43. rescue
44. flash[:notice] = "Can't delete that user"
45. end
46. end
47. redirect_to(:action => :list_users)
48. end
49.
50. def list_users
51. @all_users = User.find(:all)
52. end
53.
54. def logout
55. session[:user_id] = nil
56. flash[:notice] = "Logged out"
57. redirect_to(:action => "login")
58. end
59.
60.end
D:\work\depot\app\controllers\store_controller.rb
1.class StoreController < ApplicationController
2.
3. before_filter :find_cart, :except => :index
4.
5. def index
6. @products = Product.salable_items
7. end
8.
9. def add_to_cart
10. product = Product.find(params[:id])
11. @cart.add_product(product)
12. redirect_to(:action => 'display_cart')
13. rescue
14. logger.error("Attempt to access invalid product #{params[:id]}")
15. redirect_to_index('Invalid product')
16. end
17.
18. def display_cart
19. @items = @cart.items
20. if @items.empty?
21. redirect_to_index('Your cart is currently empty')
22. end
23. if params[:context] == :checkout
24. render(:layout => false)
25. end
26. end
27.
28. def empty_cart
29. @cart.empty!
30. redirect_to_index('Your cart is now empty')
31. end
32.
33. def checkout
34. @items = @cart.items
35. if @items.empty?
36. redirect_to_index("There's nothing in your cart!")
37. else
38. @order = Order.new
39. end
40. end
41.
42. def save_order
43. @order = Order.new(params[:order])
44. @order.line_items << @cart.items
45. if @order.save
46. @cart.empty!
47. redirect_to_index('Thank you for your order.')
48. else
49. render(:action => 'checkout')
50. end
51. end
52.
53. private
54. def find_cart
55. @cart = (session[:cart] ||= Cart.new)
56. end
57.
58.end
模型
D:\work\depot\app\models\cart.rb
1.class Cart
2. attr_reader :items
3. attr_reader :total_price
4. def initialize
5. empty!
6. end
7.
8. def empty!
9. @items = []
10. @total_price = 0.0
11. end
12.
13. def add_product(product)
14. item = @items.find {|i| i.product_id == product.id}
15. if item
16. item.quantity += 1
17. else
18. item = LineItem.for_product(product)
19. @items << item
20. end
21. @total_price += product.price
22. end
23.end
D:\work\depot\app\models\line_item.rb
1.class LineItem < ActiveRecord::Base
2. belongs_to :product
3. belongs_to :order
4. def self.for_product(product)
5. item = self.new
6. item.quantity = 1
7. item.product = product
8. item.unit_price = product.price
9. item
10. end
11.end
D:\work\depot\app\models\order.rb
1.class Order < ActiveRecord::Base
2. has_many :line_items
3.
4. PAYMENT_TYPES = [
5. [ "Check", "check"],
6. [ "Credit Card", "cc"],
7. [ "Purchas Order", "po"]
8. ].freeze # freeze to make this array constant
9.
10. validates_presence_of :name, :email, :address, :pay_type
11.
12. def self.pending_shipping
13. find(:all, :conditions => "shipped_at is null")
14. end
15.
16. def self.count_pending
17. count("shipped_at is null")
18. end
19.
20. def mark_as_shipped
21. self.shipped_at = Time.now
22. end
23.
24.end
D:\work\depot\app\models\product.rb
1.class Product < ActiveRecord::Base
2. validates_presence_of :title, :description, :image_url
3. validates_numericality_of :price
4. validates_uniqueness_of :title
5. validates_format_of :image_url,
6. :with => %r{^http:.+\.(gif|jpg|png)$}i,
7. :message => "must be a URL for a GIF, JPG, or PNG image"
8.
9. def self.salable_items
10. find(:all,
11. :conditions => "date_available <= now()",
12. :order => "date_available desc")
13. end
14.
15. protected
16. def validate
17. errors.add(:price, "should be positive") unless price.nil? || price >= 0.01
18. end
19.
20.end
D:\work\depot\app\models\user.rb
1.require "digest/sha1"
2.class User < ActiveRecord::Base
3. attr_accessor :password
4. attr_accessible :name, :password
5. validates_uniqueness_of :name
6. validates_presence_of :name, :password
7.
8. def self.login(name, password)
9. hashed_password = hash_password(password || "")
10. find(:first,
11. :conditions => ["name = ? and hashed_password = ?",
12. name, hashed_password])
13. end
14.
15. def try_to_login
16. User.login(self.name, self.password)
17. User.find_by_name_and_hashed_password(name, "")
18. end
19.
20. def before_create
21. self.hashed_password = User.hash_password(self.password)
22. end
23.
24.
25. before_destroy :dont_destroy_admin
26. def dont_destroy_admin
27. raise "Can't destroy admin" if self.name == 'admin'
28. end
29.
30. def after_create
31. @password = nil
32. end
33.
34. private
35. def self.hash_password(password)
36. Digest::SHA1.hexdigest(password)
37. end
38.
39.end
视图
D:\work\depot\app\views\layouts\admin.rhtml
1.<html>
2.<head>
3. <title>ADMINISTER Pragprog Books Online Store</title>
4. <%= stylesheet_link_tag 'scaffold', 'depot', 'admin', :media => "all" %>
5.</head>
6.<body>
7. <div id="banner">
8. <%= @page_title || "Adminster Bookshelf" %>
9. </div>
10. <div id="columns">
11. <div id="side">
12. <% if session[:user_id] -%>
13. <%= link_to("Products", :controller => "admin", :action => "list") %><br />
14. <%= link_to("Shipping", :controller => "admin", :action => "ship") %><br />
15. <hr />
16. <%= link_to("Add user", :controller => "login", :action => "add_user") %><br />
17. <%= link_to("List users", :controller => "login", :action => "list_users") %><br />
18. <hr />
19. <%= link_to("Log out", :controller => "login", :action => "logout") %>
20. <% end -%>
21. </div>
22. <div id="main">
23. <% if flash[:notice] -%>
24. <div id="notice"><%= flash[:notice] %></div>
25. <% end -%>
26. <%= @content_for_layout %>
27. </div>
28. </div>
29.</body>
30.</html>
D:\work\depot\app\views\layouts\store.rhtml
1.<html>
2. <head>
3. <title>Pragprog Books Online Store</title>
4. <%= stylesheet_link_tag "scaffold", "depot", :media => "all" %>
5. </head>
6. <body>
7. <div id="banner">
8. <img src="http://images.cnblogs.com/logo.png" />
9. <%= @page_title || "Pragmatic Bookshelf" %>
10. </div>
11. <div id="columns">
12. <div id="side">
13. <a href="http://www....">Home</a><br />
14. <a href="http://www..../faq">Questions</a><br />
15. <a href="http://www..../news">News</a><br />
16. <a href="http://www..../contact">Contact</a><br />
17. </div>
18. <div id="main">
19. <% if @flash[:notice] -%>
20. <div id="notice"><%= @flash[:notice] %></div>
21. <% end -%>
22. <%= @content_for_layout %>
23. </div>
24. </div>
25. </body>
26.</html>
D:\work\depot\app\views\admin\_order_line.rhtml
1.<tr valign="top">
2. <td class="olnamebox">
3. <div class="olnamebox"><%= h(order_line.name) %></div>
4. <div class="oladdress"><%= h(order_line.address) %></div>
5. </td>
6. <td class="olitembox">
7. <% order_line.line_items.each do |li| %>
8. <div class="olitem">
9. <span class="olitemqty"><%= li.quantity %></span>
10. <span class="olitemtitle"><%= li.product.title %></span>
11. </div>
12. <% end %>
13. </td>
14. <td>
15. <%= check_box("to_be_shipped", order_line.id, {}, "yes", "no") %>
16. </td>
17.</tr>
D:\work\depot\app\views\admin\list.rhtml
1.<h1>Products Listing </h1>
2.<table cellpadding="5" cellspacing="0">
3.<%
4.odd_or_even = 0
5.for product in @products
6. odd_or_even = 1 - odd_or_even
7.%>
8. <tr valign="top" class="ListLine<%= odd_or_even %>">
9. <td>
10. <img width="60" height="70" src="<%= product.image_url %>"/>
11. </td>
12. <td width="60%">
13. <span class="ListTitle"><%= h(product.title) %></span><br />
14. <%= h(truncate(product.description, 80)) %>
15. </td>
16. <td allign="right">
17. <%= product.date_available.strftime("%y-%m-%d") %><br />
18. <strong>$<%= sprintf("%0.2f", product.price) %></strong>
19. </td>
20. <td class="ListActions">
21. <%= link_to 'Show', :action => 'show', :id => product %><br />
22. <%= link_to 'Edit', :action => 'edit', :id => product %><br />
23. <%= link_to 'Destroy', { :action => 'destroy', :id => product }, :confirm => 'Are you sure?', :method => :post %>
24. </td>
25. <tr>
26. <% end %>
27.</table>
28. <%= if @product_pages.current.previous
29. link_to ('Previous page', { :page => @product_pages.current.previous })
30. end
31. %>
32. <%= if @product_pages.current.next
33. link_to ('Next page', { :page => @product_pages.current.next })
34. end
35. %>
36.<br />
37.<%= link_to 'New product', :action => 'new' %>
D:\work\depot\app\views\admin\ship.rhtml
1.<div class="olheader">Orders To Be Shipped</div>
2.<%= form_tag(:action => "ship") %>
3.<table cellpadding="5" cellspacing="0">
4.<%= render(:partial => "order_line", :collection => @pending_orders) %>
5.</table>
6.<br />
7.<input type="submit" value=" SHIP CHECKED ITEMS " />
8.<%= end_form_tag %>
9.<br />
D:\work\depot\app\views\login\add_user.rhtml
1.<% @page_title = "Add a User" -%>
2.<%= error_messages_for 'user' %>
3.<%= form_tag %>
4.<table>
5. <tr>
6. <td>User name:</td>
7. <td><%= text_field("user", "name") %></td>
8. </tr>
9. <tr>
10. <td>Password:</td>
11. <td><%= password_field("user", "password") %></td>
12. </tr>
13. <tr>
14. <td></td>
15. <td><input type="submit" value=" ADD USER " /></td>
16. </tr>
17.</table>
18.<%= end_form_tag %>
D:\work\depot\app\views\login\index.rhtml
1.<% @page_title = "Administer your Store" -%>
2.<h1>Depot Store Status</h1>
3.<p>
4. Total orders in system: <%= @total_orders %>
5.</p>
6.<p>
7. Orders pending shipping: <%= @pending_orders %>
8.</p>
D:\work\depot\app\views\login\list_users.rhtml
1.<% @page_title = "User List" -%>
2.<table>
3.<% for user in @all_users -%>
4.<tr>
5. <td><%= user.name %></td>
6. <td><%= link_to("(delete)", :action => :delete_user, :id => user.id) %></td>
7.</tr>
8.<% end %>
9.</table>
D:\work\depot\app\views\login\login.rhtml
1.<%= form_tag %>
2.<table>
3. <tr>
4.
5. <td>User name:</td>
6. <td><%= text_field("user", "name") %></td>
7. </tr>
8. <tr>
9. <td>Password</td>
10. <td><%= password_field("user", "password") %></td>
11. </tr>
12. <tr>
13. <td></td>
14. <td><input type="submit" value=" LOGIN " /></td>
15. </tr>
16.</table>
17.<%= end_form_tag %>
D:\work\depot\app\views\store\checkout.rhtml
1.<% @page_title = "Checkout" -%>
2.<%= error_messages_for("order") %>
3.<%= render_component(:acton => "display_cart",
4. :params => { :context => :checkout }) %>
5.<h3>Please enter your details below</h3>
6.<%= start_form_tag(:action => "save_order") %>
7.<table>
8. <tr>
9. <td>Name:</td>
10. <td><%= text_field("order", "name", "size" => 40) %></td>
11. </tr>
12. <tr>
13. <td>EMail:</td>
14. <td><%= text_field("order", "email", "size" => 40) %></td>
15. </tr>
16. <tr valign="top">
17. <td>Address:</td>
18. <td><%= text_area("order", "address", "cols" => 40, "rows" => 5) %></td>
19. </tr>
20. <tr>
21. <td>Pay using:</td>
22. <td><%=
23. options = [["Select a payment option", ""]] + Order::PAYMENT_TYPES
24. select("order", "pay_type", options) %></td>
25. </tr>
26. <tr>
27. <td></td>
28. <td><%= submit_tag(" CHECKOUT ") %></td>
29. </tr>
30.</table>
31.<%= end_form_tag %>
D:\work\depot\app\views\store\display_cart.rhtml
1.<% @page_title = "Your Pragmatic Cart" -%>
2.<div id="cartmenu">
3. <u1>
4. <li><%= link_to 'Continue shopping', :action => "index" %></li>
5. <% unless params[:context] == :checkout -%>
6. <li><%= link_to 'Empty car', :action => "empty_cart" %></li>
7. <li><%= link_to 'Checkout', :action => "checkout" %></li>
8. <% end -%>
9. </u1>
10.</div>
11.<table cellpadding="10" cellspacing="0">
12. <tr class="carttitle">
13. <td rowspan="2">Qty</td>
14. <td rowspan="2">Description</td>
15. <td colspan="2">Price</td>
16. </tr>
17. <tr class="carttitle">
18. <td>Each</td>
19. <td>Total</td>
20. </tr>
21.<%
22.for item in @items
23. product = item.product
24.-%>
25. <tr>
26. <td><%= item.quantity %></td>
27. <td><%= h(product.title) %></td>
28. <td align="right"><%= fmt_dollars(item.unit_price) %></td>
29. <td align="right"><%= fmt_dollars(item.unit_price * item.quantity) %></td>
30. </tr>
31.<% end %>
32. <tr>
33. <td colspan="3" align="right"><strong>Total:</strong></td>
34. <td id="totalcell"><%= fmt_dollars(@cart.total_price) %></td>
35. </tr>
36.</table>
D:\work\depot\app\views\store\index.rhtml
1.<% for product in @products %>
2. <div class="catalogentry">
3. <img src="<%= product.image_url %>"/>
4. <h3><%= h(product.title) %></h3>
5. <%= product.description %>
6. <span class="catalogprice"><%= fmt_dollars(product.price) %></span>
7. <%= link_to 'Add to Cart',
8. {:action => 'add_to_cart', :id => product },
9. :class => 'addtocart' %><br />
10. <div class="separator"> </div>
11.<% end %>
12.<%= link_to "Show my cart", :action => "display_cart" %>
辅助模块
D:\work\depot\app\helpers\application_helper.rb
1.# Methods added to this helper will be available to all templates in the application.
2.module ApplicationHelper
3. def fmt_dollars(amt)
4. sprintf("$%0.2f", amt)
5. end
6.end
CSS 文件
D:\work\depot\public\stylesheets\depot.css
1./* Global styles */
2.
3./* START:notice */
4.#notice {
5. border: 2px solid red;
6. padding: 1em;
7. margin-bottom: 2em;
8. background-color: #f0f0f0;
9. font: bold smaller sans-serif;
10.}
11./* END:notice */
12.
13./* Styles for admin/list */
14.
15.#product-list .list-title {
16. color: #244;
17. font-weight: bold;
18. font-size: larger;
19.}
20.
21.#product-list .list-image {
22. width: 60px;
23. height: 70px;
24.}
25.
26.
27.#product-list .list-actions {
28. font-size: x-small;
29. text-align: right;
30. padding-left: 1em;
31.}
32.
33.#product-list .list-line-even {
34. background: #e0f8f8;
35.}
36.
37.#product-list .list-line-odd {
38. background: #f8b0f8;
39.}
40.
41.
42./* Styles for main page */
43.
44.#banner {
45. background: #9c9;
46. padding-top: 10px;
47. padding-bottom: 10px;
48. border-bottom: 2px solid;
49. font: small-caps 40px/40px "Times New Roman", serif;
50. color: #282;
51. text-align: center;
52.}
53.
54.#banner img {
55. float: left;
56.}
57.
58.#columns {
59. background: #141;
60.}
61.
62.#main {
63. margin-left: 15em;
64. padding-top: 4ex;
65. padding-left: 2em;
66. background: white;
67.}
68.
69.#side {
70. float: left;
71. padding-top: 1em;
72. padding-left: 1em;
73. padding-bottom: 1em;
74. width: 14em;
75. background: #141;
76.}
77.
78.#side a {
79. color: #bfb;
80. font-size: small;
81.}
82.
83.h1 {
84. font: 150% sans-serif;
85. color: #226;
86. border-bottom: 3px dotted #77d;
87.}
88.
89./* And entry in the store catalog */
90.
91.#store .entry {
92. border-bottom: 1px dotted #77d;
93.}
94.
95.#store .title {
96. font-size: 120%;
97. font-family: sans-serif;
98.}
99.
100.#store .entry img {
101. width: 75px;
102. float: left;
103.}
104.
105.
106.#store .entry h3 {
107. margin-bottom: 2px;
108. color: #227;
109.}
110.
111.#store .entry p {
112. margin-top: 0px;
113. margin-bottom: 0.8em;
114.}
115.
116.#store .entry .price-line {
117.}
118.
119.#store .entry .add-to-cart {
120. position: relative;
121.}
122.
123.#store .entry .price {
124. color: #44a;
125. font-weight: bold;
126. margin-right: 2em;
127.}
128.
129./* START:inline */
130.#store .entry form, #store .entry form div {
131. display: inline;
132.}
133./* END:inline */
134.
135./* START:cart */
136./* Styles for the cart in the main page and the sidebar */
137.
138..cart-title {
139. font: 120% bold;
140.}
141.
142..item-price, .total-line {
143. text-align: right;
144.}
145.
146..total-line .total-cell {
147. font-weight: bold;
148. border-top: 1px solid #595;
149.}
150.
151.
152./* Styles for the cart in the sidebar */
153.
154.#cart, #cart table {
155. font-size: smaller;
156. color: white;
157.
158.}
159.
160.#cart table {
161. border-top: 1px dotted #595;
162. border-bottom: 1px dotted #595;
163. margin-bottom: 10px;
164.}
165./* END:cart */
166.
167./* Styles for order form */
168.
169..depot-form fieldset {
170. background: #efe;
171.}
172.
173..depot-form legend {
174. color: #dfd;
175. background: #141;
176. font-family: sans-serif;
177. padding: 0.2em 1em;
178.}
179.
180..depot-form label {
181. width: 5em;
182. float: left;
183. text-align: right;
184. margin-right: 0.5em;
185. display: block;
186.}
187.
188..depot-form .submit {
189. margin-left: 5.5em;
190.}
191.
192./* The error box */
193.
194..fieldWithErrors {
195. padding: 2px;
196. background-color: red;
197. display: table;
198.}
199.
200.#errorExplanation {
201. width: 400px;
202. border: 2px solid red;
203. padding: 7px;
204. padding-bottom: 12px;
205. margin-bottom: 20px;
206. background-color: #f0f0f0;
207.}
208.
209.#errorExplanation h2 {
210. text-align: left;
211. font-weight: bold;
212. padding: 5px 5px 5px 15px;
213. font-size: 12px;
214. margin: -7px;
215. background-color: #c00;
216. color: #fff;
217.}
218.
219.#errorExplanation p {
220. color: #333;
221. margin-bottom: 0;
222. padding: 5px;
223.}
224.
225.#errorExplanation ul li {
226. font-size: 12px;
227. list-style: square;
228.}
D:\work\depot\public\stylesheets\admin.css
1.#banner {
2. background: #ecc;
3. color: #822;
4.}
5.#columns {
6. background: #411;
7.}
8.#side {
9. background: #411;
10.}
11.#side a {
12. color: #fdd;
13.}
14.@side a:hover {
15. background: #411;
16.}
17./* order shipping screen */
18..olheader {
19. font: bold large sans-serif;
20. color: #411;
21. margin-bottom: 2ex;
22.}
23..olnamebox, .olitembox {
24. padding-bottom: 3ex;
25. padding-right: 3em;
26. border-top: 1px dotted #411;
27.}
28..olname {
29. font-weight: bold;
30.}
31..oladdress {
32. font-size: smaller;
33. white-space: pre;
34.}
35..olitemqty {
36. font-size: smaller;
37. font-weight: bold;
38.}
39..olitemqty:after {
40. content: " x ";
41.}
42..olitemtitle {
43. font-weight: bold;
44.}
45..ListTitle {
46. color: #244;
47. font-weight: bold;
48. font-size: larger;
49.}
50..ListActions {
51. font-size: x-small;
52. text-align: right;
53. padding-left: lem;
54.}
55..ListLine0 {
56. background: #e0f8f8;
57.}
58..ListLine1 {
59. background: #f8e0f8;
60.}
D:\work\depot\public\stylesheets\scaffold.css
1.body { background-color: #fff; color: #333; }
2.
3.body, p, ol, ul, td {
4. font-family: verdana, arial, helvetica, sans-serif;
5. font-size: 13px;
6. line-height: 18px;
7.}
8.
9.pre {
10. background-color: #eee;
11. padding: 10px;
12. font-size: 11px;
13.}
14.
15.a { color: #000; }
16.a:visited { color: #666; }
17.a:hover { color: #fff; background-color:#000; }
18.
19..fieldWithErrors {
20. padding: 2px;
21. background-color: red;
22. display: table;
23.}
24.
25.#errorExplanation {
26. width: 400px;
27. border: 2px solid red;
28. padding: 7px;
29. padding-bottom: 12px;
30. margin-bottom: 20px;
31. background-color: #f0f0f0;
32.}
33.
34.#errorExplanation h2 {
35. text-align: left;
36. font-weight: bold;
37. padding: 5px 5px 5px 15px;
38. font-size: 12px;
39. margin: -7px;
40. background-color: #c00;
41. color: #fff;
42.}
43.
44.#errorExplanation p {
45. color: #333;
46. margin-bottom: 0;
47. padding: 5px;
48.}
49.
50.#errorExplanation ul li {
51. font-size: 12px;
52. list-style: square;
53.}
54.
55.div.uploadStatus {
56. margin: 5px;
57.}
58.
59.div.progressBar {
60. margin: 5px;
61.}
62.
63.div.progressBar div.border {
64. background-color: #fff;
65. border: 1px solid grey;
66. width: 100%;
67.}
68.
69.div.progressBar div.background {
70. background-color: #333;
71. height: 18px;
72. width: 0%;
73.}
74.
75..ListTitle {
76. color: #244;
77. font-weight: bold;
78. font-size: larger;
79.}
80.
81..ListActions {
82. font-size: x-small;
83. text-align: right;
84. padding-left: lem;
85.}
86.
87..ListLine0 {
88. background: #e0f8f8;
89.}
90.
91..ListLine1 {
92. background: #f8b0f8;
93.}
以上代码 完全参考书本 考虑到 第一版的 代码下载官方网站已经没有提供了,所以特意贴出来,为今后无论是自己还是别人如果看的书是第一版的,免得输入累。
完整的Depot应用源代码 Source Code
参考 《应用 Rails 进行敏捷 Web 开发》第一版
林芷薰 翻译
透明 审校
Database Files
数据库文件
D:\work\depot\config\database.yml
1.development:
2. adapter: mysql
3. database: depot_development
4. username: root
5. password:
6. host: localhost
7.
8.# Warning: The database defined as 'test' will be erased and
9.# re-generated from your development database when you run 'rake'.
10.# Do not set this db to the same as development or production.
11.test:
12. adapter: mysql
13. database: depot_test
14. username: root
15. password:
16. host: localhost
17.
18.production:
19. adapter: mysql
20. database: depot_production
21. username: root
22. password:
23. host: localhost
D:\work\depot\db\create.sql
1.drop table if exists users;
2.drop table if exists line_items;
3.drop table if exists orders;
4.drop table if exists products;
5.
6.create table products (
7. id int not null auto_increment,
8. title varchar(100) not null,
9. description text not null,
10. image_url varchar(200) not null,
11. price decimal(10,2) not null,
12. date_available datetime not null,
13. primary key(id)
14.);
15.
16.create table orders (
17. id int not null auto_increment,
18. name varchar(100) not null,
19. email varchar(255) not null,
20. address text not null,
21. pay_type char(10) not null,
22. shipped_at datetime null,
23. primary key (id)
24.);
25.
26.create table line_items (
27. id int not null auto_increment,
28. product_id int not null,
29. order_id int not null,
30. quantity int not null default 0,
31. unit_price decimal(10,2) not null,
32. constraint fk_items_product foreign key (product_id) references products(id),
33. constraint fk_items_order foreign key (order_id) references orders(id),
34. primary key (id)
35.);
36.
37.create table users (
38. id int not null auto_increment,
39. name varchar(100) not null,
40. hashed_password char(40) null,
41. primary key (id)
42.);
43.
44./* password = 'admin' */
45.insert into users values(null, 'admin','d033e22ae348aeb5660fc2140aec35850c4da997');
D:\work\depot\db\product_data.sql
1.lock tables products write;
2.insert into products( title, description, image_url, price, date_available ) values(
3. 'Pragmatic Project Automation',
4. 'A really great read!',
5. 'http://localhost:3000/images/svn.JPG',
6. '29.95',
7. '2007-12-25 05:00:00' );
8.insert into products( title, description, image_url, price, date_available ) values(
9. 'Pragmatic Version Control',
10. 'A really contrlooed read!',
11. 'http://localhost:3000/images/utc.jpg',
12. '29.95',
13. '2007-12-01 05:00:00');
14.insert into products( title, description, image_url, price, date_available ) values(
15. 'Pragmatic Version Control2',
16. 'A really contrlooed read!',
17. 'http://localhost:3000/images/auto.jpg',
18. '29.95',
19. '2007-12-01 05:00:00');
20.unlock tables;
D:\work\depot\db\product_data2.sql
1.lock tables products write;
2.insert into products( title, description, image_url, price, date_available ) values(
3. 'Pragmatic Project Automation',
4. 'A really great read!',
5. '/images/svn.JPG',
6. '29.95',
7. '2007-12-25 05:00:00' );
8.insert into products( title, description, image_url, price, date_available ) values(
9. 'Pragmatic Version Control',
10. 'A really contrlooed read!',
11. '/images/utc.jpg',
12. '29.95',
13. '2007-12-01 05:00:00');
14.insert into products( title, description, image_url, price, date_available ) values(
15. 'Pragmatic Version Control2',
16. 'A really contrlooed read!',
17. '/images/auto.jpg',
18. '29.95',
19. '2007-12-01 05:00:00');
20.unlock tables;
控制器
D:\work\depot\app\controllers\application.rb
1.class ApplicationController < ActionController::Base
2. model :cart
3. model :line_item
4.
5. # Pick a unique cookie name to distinguish our session data from others'
6. session :session_key => '_depot_session_id'
7.
8. private
9. def redirect_to_index(msg = nil)
10. flash[:notice] = msg if msg
11. redirect_to(:action => 'index')
12. end
13.
14. def authorize
15. unless session[:user_id]
16. flash[:notice] = "Please log in"
17. redirect_to(:controller => "login", :action => "login")
18. end
19. end
20.
21.end
D:\work\depot\app\controllers\admin_controller.rb
1.class AdminController < ApplicationController
2. before_filter :authorize
3.
4. # GETs should be safe (see http://www.w3.org/2001/tag/doc/whenToUseGet.html)
5. verify :method => :post, :only => [ :destroy, :create, :update ],
6. :redirect_to => { :action => :list }
7.
8. def index
9. list
10. render :action => 'list'
11. end
12.
13. def list
14. @product_pages, @products = paginate :products, :per_page => 10
15. end
16.
17. def show
18. @product = Product.find(params[:id])
19. end
20.
21. def new
22. @product = Product.new
23. end
24.
25. def create
26. @product = Product.new(params[:product])
27. if @product.save
28. flash[:notice] = 'Product was successfully created.'
29. redirect_to :action => 'list'
30. else
31. render :action => 'new'
32. end
33. end
34.
35. def edit
36. @product = Product.find(params[:id])
37. end
38.
39. def update
40. @product = Product.find(params[:id])
41. if @product.update_attributes(params[:product])
42. flash[:notice] = 'Product was successfully updated.'
43. redirect_to :action => 'show', :id => @product
44. else
45. render :action => 'edit'
46. end
47. end
48.
49. def destroy
50. Product.find(params[:id]).destroy
51. redirect_to :action => 'list'
52. end
53.
54. def ship
55. count = 0
56. if things_to_ship = params[:to_be_shipped]
57. count = do_shipping(things_to_ship)
58. if count > 0
59. count_text = pluralize(count, "order")
60. flash.now[:notice] = "#{count_text} marked as shipped"
61. end
62. end
63. @penging_orders = Order.pending_shipping
64. end
65.
66. private
67. def do_shipping(things_to_ship)
68. count = 0
69. things_to_ship.each do |order_id, do_it|
70. if do_it == "yes"
71. order = Order.find(order_id)
72. order.mark_as_shipped
73. order.save
74. count += 1
75. end
76. end
77. count
78. end
79.
80. def pluralize(count, noun)
81. case count
82. when 0: "No #{noun.pluralize}"
83. when 1: "One #{noun}"
84. else "#{count} #{noun.pluralize}"
85. end
86. end
87.
88.end
D:\work\depot\app\controllers\login_controller.rb
1.class LoginController < ApplicationController
2. layout "admin"
3. before_filter :authorize, :except => :login
4.
5. def index
6. @total_orders = Order.count
7. @pending_orders = Order.count_pending
8. end
9.
10. def login
11. if request.get?
12. session[:user_id] = nil
13. @user = User.new
14. else
15. @user = User.new(params[:user])
16. logged_in_user = @user.try_to_login
17. if logged_in_user
18. session[:user_id] = logged_in_user.id
19. redirect_to(:action => "index")
20. else
21. flash[:notice] = "Invalid user/password conbination"
22. end
23. end
24. end
25.
26. def add_user
27. if request.get?
28. @user = User.new
29. else
30. @user = User.new(params[:user])
31. if @user.save
32. redirect_to_index("User #{@user.name} created")
33. end
34. end
35. end
36.
37. def delete_user
38. id = params[:id]
39. if id && user = User.find(id)
40. begin
41. user.destroy
42. flash[:notice] = "User #{user.name} deleted"
43. rescue
44. flash[:notice] = "Can't delete that user"
45. end
46. end
47. redirect_to(:action => :list_users)
48. end
49.
50. def list_users
51. @all_users = User.find(:all)
52. end
53.
54. def logout
55. session[:user_id] = nil
56. flash[:notice] = "Logged out"
57. redirect_to(:action => "login")
58. end
59.
60.end
D:\work\depot\app\controllers\store_controller.rb
1.class StoreController < ApplicationController
2.
3. before_filter :find_cart, :except => :index
4.
5. def index
6. @products = Product.salable_items
7. end
8.
9. def add_to_cart
10. product = Product.find(params[:id])
11. @cart.add_product(product)
12. redirect_to(:action => 'display_cart')
13. rescue
14. logger.error("Attempt to access invalid product #{params[:id]}")
15. redirect_to_index('Invalid product')
16. end
17.
18. def display_cart
19. @items = @cart.items
20. if @items.empty?
21. redirect_to_index('Your cart is currently empty')
22. end
23. if params[:context] == :checkout
24. render(:layout => false)
25. end
26. end
27.
28. def empty_cart
29. @cart.empty!
30. redirect_to_index('Your cart is now empty')
31. end
32.
33. def checkout
34. @items = @cart.items
35. if @items.empty?
36. redirect_to_index("There's nothing in your cart!")
37. else
38. @order = Order.new
39. end
40. end
41.
42. def save_order
43. @order = Order.new(params[:order])
44. @order.line_items << @cart.items
45. if @order.save
46. @cart.empty!
47. redirect_to_index('Thank you for your order.')
48. else
49. render(:action => 'checkout')
50. end
51. end
52.
53. private
54. def find_cart
55. @cart = (session[:cart] ||= Cart.new)
56. end
57.
58.end
模型
D:\work\depot\app\models\cart.rb
1.class Cart
2. attr_reader :items
3. attr_reader :total_price
4. def initialize
5. empty!
6. end
7.
8. def empty!
9. @items = []
10. @total_price = 0.0
11. end
12.
13. def add_product(product)
14. item = @items.find {|i| i.product_id == product.id}
15. if item
16. item.quantity += 1
17. else
18. item = LineItem.for_product(product)
19. @items << item
20. end
21. @total_price += product.price
22. end
23.end
D:\work\depot\app\models\line_item.rb
1.class LineItem < ActiveRecord::Base
2. belongs_to :product
3. belongs_to :order
4. def self.for_product(product)
5. item = self.new
6. item.quantity = 1
7. item.product = product
8. item.unit_price = product.price
9. item
10. end
11.end
D:\work\depot\app\models\order.rb
1.class Order < ActiveRecord::Base
2. has_many :line_items
3.
4. PAYMENT_TYPES = [
5. [ "Check", "check"],
6. [ "Credit Card", "cc"],
7. [ "Purchas Order", "po"]
8. ].freeze # freeze to make this array constant
9.
10. validates_presence_of :name, :email, :address, :pay_type
11.
12. def self.pending_shipping
13. find(:all, :conditions => "shipped_at is null")
14. end
15.
16. def self.count_pending
17. count("shipped_at is null")
18. end
19.
20. def mark_as_shipped
21. self.shipped_at = Time.now
22. end
23.
24.end
D:\work\depot\app\models\product.rb
1.class Product < ActiveRecord::Base
2. validates_presence_of :title, :description, :image_url
3. validates_numericality_of :price
4. validates_uniqueness_of :title
5. validates_format_of :image_url,
6. :with => %r{^http:.+\.(gif|jpg|png)$}i,
7. :message => "must be a URL for a GIF, JPG, or PNG image"
8.
9. def self.salable_items
10. find(:all,
11. :conditions => "date_available <= now()",
12. :order => "date_available desc")
13. end
14.
15. protected
16. def validate
17. errors.add(:price, "should be positive") unless price.nil? || price >= 0.01
18. end
19.
20.end
D:\work\depot\app\models\user.rb
1.require "digest/sha1"
2.class User < ActiveRecord::Base
3. attr_accessor :password
4. attr_accessible :name, :password
5. validates_uniqueness_of :name
6. validates_presence_of :name, :password
7.
8. def self.login(name, password)
9. hashed_password = hash_password(password || "")
10. find(:first,
11. :conditions => ["name = ? and hashed_password = ?",
12. name, hashed_password])
13. end
14.
15. def try_to_login
16. User.login(self.name, self.password)
17. User.find_by_name_and_hashed_password(name, "")
18. end
19.
20. def before_create
21. self.hashed_password = User.hash_password(self.password)
22. end
23.
24.
25. before_destroy :dont_destroy_admin
26. def dont_destroy_admin
27. raise "Can't destroy admin" if self.name == 'admin'
28. end
29.
30. def after_create
31. @password = nil
32. end
33.
34. private
35. def self.hash_password(password)
36. Digest::SHA1.hexdigest(password)
37. end
38.
39.end
视图
D:\work\depot\app\views\layouts\admin.rhtml
1.<html>
2.<head>
3. <title>ADMINISTER Pragprog Books Online Store</title>
4. <%= stylesheet_link_tag 'scaffold', 'depot', 'admin', :media => "all" %>
5.</head>
6.<body>
7. <div id="banner">
8. <%= @page_title || "Adminster Bookshelf" %>
9. </div>
10. <div id="columns">
11. <div id="side">
12. <% if session[:user_id] -%>
13. <%= link_to("Products", :controller => "admin", :action => "list") %><br />
14. <%= link_to("Shipping", :controller => "admin", :action => "ship") %><br />
15. <hr />
16. <%= link_to("Add user", :controller => "login", :action => "add_user") %><br />
17. <%= link_to("List users", :controller => "login", :action => "list_users") %><br />
18. <hr />
19. <%= link_to("Log out", :controller => "login", :action => "logout") %>
20. <% end -%>
21. </div>
22. <div id="main">
23. <% if flash[:notice] -%>
24. <div id="notice"><%= flash[:notice] %></div>
25. <% end -%>
26. <%= @content_for_layout %>
27. </div>
28. </div>
29.</body>
30.</html>
D:\work\depot\app\views\layouts\store.rhtml
1.<html>
2. <head>
3. <title>Pragprog Books Online Store</title>
4. <%= stylesheet_link_tag "scaffold", "depot", :media => "all" %>
5. </head>
6. <body>
7. <div id="banner">
8. <img src="http://images.cnblogs.com/logo.png" />
9. <%= @page_title || "Pragmatic Bookshelf" %>
10. </div>
11. <div id="columns">
12. <div id="side">
13. <a href="http://www....">Home</a><br />
14. <a href="http://www..../faq">Questions</a><br />
15. <a href="http://www..../news">News</a><br />
16. <a href="http://www..../contact">Contact</a><br />
17. </div>
18. <div id="main">
19. <% if @flash[:notice] -%>
20. <div id="notice"><%= @flash[:notice] %></div>
21. <% end -%>
22. <%= @content_for_layout %>
23. </div>
24. </div>
25. </body>
26.</html>
D:\work\depot\app\views\admin\_order_line.rhtml
1.<tr valign="top">
2. <td class="olnamebox">
3. <div class="olnamebox"><%= h(order_line.name) %></div>
4. <div class="oladdress"><%= h(order_line.address) %></div>
5. </td>
6. <td class="olitembox">
7. <% order_line.line_items.each do |li| %>
8. <div class="olitem">
9. <span class="olitemqty"><%= li.quantity %></span>
10. <span class="olitemtitle"><%= li.product.title %></span>
11. </div>
12. <% end %>
13. </td>
14. <td>
15. <%= check_box("to_be_shipped", order_line.id, {}, "yes", "no") %>
16. </td>
17.</tr>
D:\work\depot\app\views\admin\list.rhtml
1.<h1>Products Listing </h1>
2.<table cellpadding="5" cellspacing="0">
3.<%
4.odd_or_even = 0
5.for product in @products
6. odd_or_even = 1 - odd_or_even
7.%>
8. <tr valign="top" class="ListLine<%= odd_or_even %>">
9. <td>
10. <img width="60" height="70" src="<%= product.image_url %>"/>
11. </td>
12. <td width="60%">
13. <span class="ListTitle"><%= h(product.title) %></span><br />
14. <%= h(truncate(product.description, 80)) %>
15. </td>
16. <td allign="right">
17. <%= product.date_available.strftime("%y-%m-%d") %><br />
18. <strong>$<%= sprintf("%0.2f", product.price) %></strong>
19. </td>
20. <td class="ListActions">
21. <%= link_to 'Show', :action => 'show', :id => product %><br />
22. <%= link_to 'Edit', :action => 'edit', :id => product %><br />
23. <%= link_to 'Destroy', { :action => 'destroy', :id => product }, :confirm => 'Are you sure?', :method => :post %>
24. </td>
25. <tr>
26. <% end %>
27.</table>
28. <%= if @product_pages.current.previous
29. link_to ('Previous page', { :page => @product_pages.current.previous })
30. end
31. %>
32. <%= if @product_pages.current.next
33. link_to ('Next page', { :page => @product_pages.current.next })
34. end
35. %>
36.<br />
37.<%= link_to 'New product', :action => 'new' %>
D:\work\depot\app\views\admin\ship.rhtml
1.<div class="olheader">Orders To Be Shipped</div>
2.<%= form_tag(:action => "ship") %>
3.<table cellpadding="5" cellspacing="0">
4.<%= render(:partial => "order_line", :collection => @pending_orders) %>
5.</table>
6.<br />
7.<input type="submit" value=" SHIP CHECKED ITEMS " />
8.<%= end_form_tag %>
9.<br />
D:\work\depot\app\views\login\add_user.rhtml
1.<% @page_title = "Add a User" -%>
2.<%= error_messages_for 'user' %>
3.<%= form_tag %>
4.<table>
5. <tr>
6. <td>User name:</td>
7. <td><%= text_field("user", "name") %></td>
8. </tr>
9. <tr>
10. <td>Password:</td>
11. <td><%= password_field("user", "password") %></td>
12. </tr>
13. <tr>
14. <td></td>
15. <td><input type="submit" value=" ADD USER " /></td>
16. </tr>
17.</table>
18.<%= end_form_tag %>
D:\work\depot\app\views\login\index.rhtml
1.<% @page_title = "Administer your Store" -%>
2.<h1>Depot Store Status</h1>
3.<p>
4. Total orders in system: <%= @total_orders %>
5.</p>
6.<p>
7. Orders pending shipping: <%= @pending_orders %>
8.</p>
D:\work\depot\app\views\login\list_users.rhtml
1.<% @page_title = "User List" -%>
2.<table>
3.<% for user in @all_users -%>
4.<tr>
5. <td><%= user.name %></td>
6. <td><%= link_to("(delete)", :action => :delete_user, :id => user.id) %></td>
7.</tr>
8.<% end %>
9.</table>
D:\work\depot\app\views\login\login.rhtml
1.<%= form_tag %>
2.<table>
3. <tr>
4.
5. <td>User name:</td>
6. <td><%= text_field("user", "name") %></td>
7. </tr>
8. <tr>
9. <td>Password</td>
10. <td><%= password_field("user", "password") %></td>
11. </tr>
12. <tr>
13. <td></td>
14. <td><input type="submit" value=" LOGIN " /></td>
15. </tr>
16.</table>
17.<%= end_form_tag %>
D:\work\depot\app\views\store\checkout.rhtml
1.<% @page_title = "Checkout" -%>
2.<%= error_messages_for("order") %>
3.<%= render_component(:acton => "display_cart",
4. :params => { :context => :checkout }) %>
5.<h3>Please enter your details below</h3>
6.<%= start_form_tag(:action => "save_order") %>
7.<table>
8. <tr>
9. <td>Name:</td>
10. <td><%= text_field("order", "name", "size" => 40) %></td>
11. </tr>
12. <tr>
13. <td>EMail:</td>
14. <td><%= text_field("order", "email", "size" => 40) %></td>
15. </tr>
16. <tr valign="top">
17. <td>Address:</td>
18. <td><%= text_area("order", "address", "cols" => 40, "rows" => 5) %></td>
19. </tr>
20. <tr>
21. <td>Pay using:</td>
22. <td><%=
23. options = [["Select a payment option", ""]] + Order::PAYMENT_TYPES
24. select("order", "pay_type", options) %></td>
25. </tr>
26. <tr>
27. <td></td>
28. <td><%= submit_tag(" CHECKOUT ") %></td>
29. </tr>
30.</table>
31.<%= end_form_tag %>
D:\work\depot\app\views\store\display_cart.rhtml
1.<% @page_title = "Your Pragmatic Cart" -%>
2.<div id="cartmenu">
3. <u1>
4. <li><%= link_to 'Continue shopping', :action => "index" %></li>
5. <% unless params[:context] == :checkout -%>
6. <li><%= link_to 'Empty car', :action => "empty_cart" %></li>
7. <li><%= link_to 'Checkout', :action => "checkout" %></li>
8. <% end -%>
9. </u1>
10.</div>
11.<table cellpadding="10" cellspacing="0">
12. <tr class="carttitle">
13. <td rowspan="2">Qty</td>
14. <td rowspan="2">Description</td>
15. <td colspan="2">Price</td>
16. </tr>
17. <tr class="carttitle">
18. <td>Each</td>
19. <td>Total</td>
20. </tr>
21.<%
22.for item in @items
23. product = item.product
24.-%>
25. <tr>
26. <td><%= item.quantity %></td>
27. <td><%= h(product.title) %></td>
28. <td align="right"><%= fmt_dollars(item.unit_price) %></td>
29. <td align="right"><%= fmt_dollars(item.unit_price * item.quantity) %></td>
30. </tr>
31.<% end %>
32. <tr>
33. <td colspan="3" align="right"><strong>Total:</strong></td>
34. <td id="totalcell"><%= fmt_dollars(@cart.total_price) %></td>
35. </tr>
36.</table>
D:\work\depot\app\views\store\index.rhtml
1.<% for product in @products %>
2. <div class="catalogentry">
3. <img src="<%= product.image_url %>"/>
4. <h3><%= h(product.title) %></h3>
5. <%= product.description %>
6. <span class="catalogprice"><%= fmt_dollars(product.price) %></span>
7. <%= link_to 'Add to Cart',
8. {:action => 'add_to_cart', :id => product },
9. :class => 'addtocart' %><br />
10. <div class="separator"> </div>
11.<% end %>
12.<%= link_to "Show my cart", :action => "display_cart" %>
辅助模块
D:\work\depot\app\helpers\application_helper.rb
1.# Methods added to this helper will be available to all templates in the application.
2.module ApplicationHelper
3. def fmt_dollars(amt)
4. sprintf("$%0.2f", amt)
5. end
6.end
CSS 文件
D:\work\depot\public\stylesheets\depot.css
1./* Global styles */
2.
3./* START:notice */
4.#notice {
5. border: 2px solid red;
6. padding: 1em;
7. margin-bottom: 2em;
8. background-color: #f0f0f0;
9. font: bold smaller sans-serif;
10.}
11./* END:notice */
12.
13./* Styles for admin/list */
14.
15.#product-list .list-title {
16. color: #244;
17. font-weight: bold;
18. font-size: larger;
19.}
20.
21.#product-list .list-image {
22. width: 60px;
23. height: 70px;
24.}
25.
26.
27.#product-list .list-actions {
28. font-size: x-small;
29. text-align: right;
30. padding-left: 1em;
31.}
32.
33.#product-list .list-line-even {
34. background: #e0f8f8;
35.}
36.
37.#product-list .list-line-odd {
38. background: #f8b0f8;
39.}
40.
41.
42./* Styles for main page */
43.
44.#banner {
45. background: #9c9;
46. padding-top: 10px;
47. padding-bottom: 10px;
48. border-bottom: 2px solid;
49. font: small-caps 40px/40px "Times New Roman", serif;
50. color: #282;
51. text-align: center;
52.}
53.
54.#banner img {
55. float: left;
56.}
57.
58.#columns {
59. background: #141;
60.}
61.
62.#main {
63. margin-left: 15em;
64. padding-top: 4ex;
65. padding-left: 2em;
66. background: white;
67.}
68.
69.#side {
70. float: left;
71. padding-top: 1em;
72. padding-left: 1em;
73. padding-bottom: 1em;
74. width: 14em;
75. background: #141;
76.}
77.
78.#side a {
79. color: #bfb;
80. font-size: small;
81.}
82.
83.h1 {
84. font: 150% sans-serif;
85. color: #226;
86. border-bottom: 3px dotted #77d;
87.}
88.
89./* And entry in the store catalog */
90.
91.#store .entry {
92. border-bottom: 1px dotted #77d;
93.}
94.
95.#store .title {
96. font-size: 120%;
97. font-family: sans-serif;
98.}
99.
100.#store .entry img {
101. width: 75px;
102. float: left;
103.}
104.
105.
106.#store .entry h3 {
107. margin-bottom: 2px;
108. color: #227;
109.}
110.
111.#store .entry p {
112. margin-top: 0px;
113. margin-bottom: 0.8em;
114.}
115.
116.#store .entry .price-line {
117.}
118.
119.#store .entry .add-to-cart {
120. position: relative;
121.}
122.
123.#store .entry .price {
124. color: #44a;
125. font-weight: bold;
126. margin-right: 2em;
127.}
128.
129./* START:inline */
130.#store .entry form, #store .entry form div {
131. display: inline;
132.}
133./* END:inline */
134.
135./* START:cart */
136./* Styles for the cart in the main page and the sidebar */
137.
138..cart-title {
139. font: 120% bold;
140.}
141.
142..item-price, .total-line {
143. text-align: right;
144.}
145.
146..total-line .total-cell {
147. font-weight: bold;
148. border-top: 1px solid #595;
149.}
150.
151.
152./* Styles for the cart in the sidebar */
153.
154.#cart, #cart table {
155. font-size: smaller;
156. color: white;
157.
158.}
159.
160.#cart table {
161. border-top: 1px dotted #595;
162. border-bottom: 1px dotted #595;
163. margin-bottom: 10px;
164.}
165./* END:cart */
166.
167./* Styles for order form */
168.
169..depot-form fieldset {
170. background: #efe;
171.}
172.
173..depot-form legend {
174. color: #dfd;
175. background: #141;
176. font-family: sans-serif;
177. padding: 0.2em 1em;
178.}
179.
180..depot-form label {
181. width: 5em;
182. float: left;
183. text-align: right;
184. margin-right: 0.5em;
185. display: block;
186.}
187.
188..depot-form .submit {
189. margin-left: 5.5em;
190.}
191.
192./* The error box */
193.
194..fieldWithErrors {
195. padding: 2px;
196. background-color: red;
197. display: table;
198.}
199.
200.#errorExplanation {
201. width: 400px;
202. border: 2px solid red;
203. padding: 7px;
204. padding-bottom: 12px;
205. margin-bottom: 20px;
206. background-color: #f0f0f0;
207.}
208.
209.#errorExplanation h2 {
210. text-align: left;
211. font-weight: bold;
212. padding: 5px 5px 5px 15px;
213. font-size: 12px;
214. margin: -7px;
215. background-color: #c00;
216. color: #fff;
217.}
218.
219.#errorExplanation p {
220. color: #333;
221. margin-bottom: 0;
222. padding: 5px;
223.}
224.
225.#errorExplanation ul li {
226. font-size: 12px;
227. list-style: square;
228.}
D:\work\depot\public\stylesheets\admin.css
1.#banner {
2. background: #ecc;
3. color: #822;
4.}
5.#columns {
6. background: #411;
7.}
8.#side {
9. background: #411;
10.}
11.#side a {
12. color: #fdd;
13.}
14.@side a:hover {
15. background: #411;
16.}
17./* order shipping screen */
18..olheader {
19. font: bold large sans-serif;
20. color: #411;
21. margin-bottom: 2ex;
22.}
23..olnamebox, .olitembox {
24. padding-bottom: 3ex;
25. padding-right: 3em;
26. border-top: 1px dotted #411;
27.}
28..olname {
29. font-weight: bold;
30.}
31..oladdress {
32. font-size: smaller;
33. white-space: pre;
34.}
35..olitemqty {
36. font-size: smaller;
37. font-weight: bold;
38.}
39..olitemqty:after {
40. content: " x ";
41.}
42..olitemtitle {
43. font-weight: bold;
44.}
45..ListTitle {
46. color: #244;
47. font-weight: bold;
48. font-size: larger;
49.}
50..ListActions {
51. font-size: x-small;
52. text-align: right;
53. padding-left: lem;
54.}
55..ListLine0 {
56. background: #e0f8f8;
57.}
58..ListLine1 {
59. background: #f8e0f8;
60.}
D:\work\depot\public\stylesheets\scaffold.css
1.body { background-color: #fff; color: #333; }
2.
3.body, p, ol, ul, td {
4. font-family: verdana, arial, helvetica, sans-serif;
5. font-size: 13px;
6. line-height: 18px;
7.}
8.
9.pre {
10. background-color: #eee;
11. padding: 10px;
12. font-size: 11px;
13.}
14.
15.a { color: #000; }
16.a:visited { color: #666; }
17.a:hover { color: #fff; background-color:#000; }
18.
19..fieldWithErrors {
20. padding: 2px;
21. background-color: red;
22. display: table;
23.}
24.
25.#errorExplanation {
26. width: 400px;
27. border: 2px solid red;
28. padding: 7px;
29. padding-bottom: 12px;
30. margin-bottom: 20px;
31. background-color: #f0f0f0;
32.}
33.
34.#errorExplanation h2 {
35. text-align: left;
36. font-weight: bold;
37. padding: 5px 5px 5px 15px;
38. font-size: 12px;
39. margin: -7px;
40. background-color: #c00;
41. color: #fff;
42.}
43.
44.#errorExplanation p {
45. color: #333;
46. margin-bottom: 0;
47. padding: 5px;
48.}
49.
50.#errorExplanation ul li {
51. font-size: 12px;
52. list-style: square;
53.}
54.
55.div.uploadStatus {
56. margin: 5px;
57.}
58.
59.div.progressBar {
60. margin: 5px;
61.}
62.
63.div.progressBar div.border {
64. background-color: #fff;
65. border: 1px solid grey;
66. width: 100%;
67.}
68.
69.div.progressBar div.background {
70. background-color: #333;
71. height: 18px;
72. width: 0%;
73.}
74.
75..ListTitle {
76. color: #244;
77. font-weight: bold;
78. font-size: larger;
79.}
80.
81..ListActions {
82. font-size: x-small;
83. text-align: right;
84. padding-left: lem;
85.}
86.
87..ListLine0 {
88. background: #e0f8f8;
89.}
90.
91..ListLine1 {
92. background: #f8b0f8;
93.}
以上代码 完全参考书本 考虑到 第一版的 代码下载官方网站已经没有提供了,所以特意贴出来,为今后无论是自己还是别人如果看的书是第一版的,免得输入累。