`

学习ruby on rails 笔记(第一版)

阅读更多
我用的 Rails 和 Ruby 的版本:
D:\work\depot>rails -v
Rails 1.2.6

D:\work\depot>ruby -v
ruby 1.8.6 (2007-09-24 patchlevel 111) [i386-mswin32]

第六章 任务A 货品维护

rails depot

ruby script/server scaffold Product Admin

ruby script/server

http://localhost:3000/admin


depot 数据库的脚本
D:\work>mysql -u root
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 12 to server version: 5.0.27-community-nt

Type 'help;' or '\h' for help. Type '\c' to clear the buffer.

建立数据库:
create database depot_development;
create database depot_test;
create database depot_production;

D:\work\depot>mysql -u root -p
Enter password:
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 7 to server version: 5.0.27-community-nt

Type 'help;' or '\h' for help. Type '\c' to clear the buffer.

mysql> grant all on depot_development.* to 'root'@'localhost';
Query OK, 0 rows affected (0.00 sec)

mysql> grant all on depot_test.* to 'root'@'localhost';
Query OK, 0 rows affected (0.00 sec)

mysql> grant all on depot_production.* to 'root'@'localhost';
Query OK, 0 rows affected (0.00 sec)

删除数据库:
drop database depot_development;
drop database depot_test;
drop database depot_production;

mysql> use mysql
Database changed
mysql> show databases;
+--------------------+
| Database           |
+--------------------+
| information_schema |
| depot_development  |
| depot_production   |
| depot_test         |
| mysql              |
+--------------------+
5 rows in set (0.00 sec)

mysql> drop database depot_development;
Query OK, 1 row affected (0.06 sec)

mysql> drop database depot_test;
Query OK, 0 rows affected (0.00 sec)

mysql> drop database depot_production;
Query OK, 0 rows affected (0.00 sec)

mysql>

显示所有数据库:
show databases;

选择数据库:
use depot_development

mysql> use depot_development
Database changed
mysql> use mysql
Database changed
mysql> use depot_development; 这个地方可要';' 也可不要';'
Database changed

显示所有表:
show tables;

创建货品表(create_0.sql 的内容):
drop table if exists products;
create table products (
id int not null auto_increment,
title varchar(100) not null,
description text not null,
image_url varchar(200) not null,
price decimal(10,2) not null,
primary key(id)
);

执行 SQL 语句:
建表:
mysql depot_development <db/create.sql
删除表中数据:
mysql> delete from products;
Query OK, 4 rows affected (0.03 sec)

D:\work\depot>mysql depot_development <db/create.sql (没有指定用户出错了)
ERROR 1045 (28000): Access denied for user 'ODBC'@'localhost' (using password: NO)

D:\work\depot>mysql -u root depot_development <db/create.sql

D:\work\depot>mysql -u root depot_development <db/product_data.sql (导入数据)

D:\work\depot>mysql -u root -p
Enter password:
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 10 to server version: 5.0.27-community-nt

Type 'help;' or '\h' for help. Type '\c' to clear the buffer.

mysql> use depot_development
Database changed
mysql> show tables;
+-----------------------------+
| Tables_in_depot_development |
+-----------------------------+
| products                    |
+-----------------------------+
1 row in set (0.00 sec)

mysql> select * from products;
Empty set (0.00 sec)

mysql>


添加缺失的字段 :
alter table products add column date_available datetime; 这个是以前老的方法,不建议采用

创建货品表(create_1.sql 的内容):
drop table if exists products;
create table products (
id int not null auto_increment,
title varchar(100) not null,
description text not null,
image_url varchar(200) not null,
price decimal(10,2) not null,
date_available datetime not null,
primary key(id)
);


product.rb
class Product < ActiveRecord::Base
	validates_presence_of	:title, :description, :image_url
	validates_numericality_of :price
	validates_uniqueness_of :title
	validates_format_of :image_url,
	                    :with    => %r{^http:.+\.(gif|jpg|png)$}i,
	                    :message => "must be a URL for a GIF, JPG, or PNG image"
	protected
	def validate
		errors.add(:price, "should be positive") unless price.nil? || price >= 0.01
	end
end



D:\work\depot\app\views\admin\list.rhtml

<h1>Products Listing </h1>
<table cellpadding="5" cellspacing="0">
<%
odd_or_even = 0
for product in @products
	odd_or_even = 1 - odd_or_even
%>
	<tr valign="top" class="ListLine<%= odd_or_even %>">
		<td>
			<img width="60" height="70" src="<%= product.image_url %>"/>
		</td>
		<td width="60%">
			<span class="ListTitle"><%= h(product.title) %></span><br />
			<%= h(truncate(product.description, 80)) %>
		</td>
		<td allign="right">
			<%= product.date_availbale.strftime("%y-%m-%d") %><br />
			<strong>$<%= sprintf("%0.2f", product.price) %></strong>
		</td>
		<td class="ListActions">
			<%= link_to 'Show', :action => 'show', :id => product %><br />
			<%= link_to 'Edit', :action => 'edit', :id => product %><br />
			<%= link_to 'Destroy', { :action => 'destroy', :id => product }, :confirm => 'Are you sure?', :method => :post %>
		</td>	
  <tr>
  <% end %>
  </table>
  <%= if @product_pages.current.previous
  			link_to ('Previous page', { :page => @product_pages.current.previous })
  		end
  %>
  <%= if @product_pages.current.next
  			link_to ('Next page', { :page => @product_pages.current.next })
  		end 
  %>
<br />
<%= link_to 'New product', :action => 'new' %>


修改样式文件
D:\work\depot\public\stylesheets\scaffold.css

.ListTitle {
	color:				#244;
	font-weight:	bold;
	font-size:		larger;
}

.ListActions {
	font-size:		x-small;
	text-align:		right;
	padding-left:	lem;
}

.ListLine0 {
	background:		#e0f8f8;
}

.ListLine1 {
	background:		#f8b0f8;
}


新增货品的时候输入的图片地址
http://localhost:3000/images/svn.JPG
http://localhost:3000/images/utc.jpg
http://localhost:3000/images/auto.jpg

第七章 任务B 分类显示

ruby script/generate controller Store index

D:\work\depot\app\controllers\store_controller.rb

class StoreController < ApplicationController

  def index
  	@products = Product.salable_items
  end  
end


D:\work\depot\app\models\product.rb
class Product < ActiveRecord::Base
	validates_presence_of	:title, :description, :image_url
	validates_numericality_of :price
	validates_uniqueness_of :title
	validates_format_of :image_url,
	                    :with    => %r{^http:.+\.(gif|jpg|png)$}i,
	                    :message => "must be a URL for a GIF, JPG, or PNG image"
	protected
	def validate
		errors.add(:price, "should be positive") unless price.nil? || price >= 0.01
	end
	
	def self.salable_items
		find(:all,
				 :conditions		=> 	"date_available <= now()",
				 :order					=> "date_available desc")
	end
end


D:\work\depot\app\views\store\index.rhtml
<table cellpadding="5" cellspacing="0">
<% for product in @products %>
	<tr valign="top">
		<td>
			<img src="<%= product.image_url %>"/>
		</td>
		<td width="450">
			<h3><%=h product.title %></h3>
			<small>
				<%= product.description %>
			</small>
			<br />
			<strong>$<%= sprintf("%0.2f", product.price) %></strong>
			<%= link_to 'Add to Cart',
										:action => 'add_to_cart',
										:id => product %>
			<br />
		</td>
	</tr>
	<tr><td colspan="2"><hr/></td></tr>
<% end %>
</table>


D:\work\depot\app\views\layouts\store.rhtml
<html>
	<head>
		<title>Pragprog Books Online Store</title>
		<%= stylesheet_link_tag "depot", :media => "all" %>
	</head>
	<body>
		<div id="banner">
			<img src="/images/logo.png" />
			<%= @page_title || "Pragmatic Bookshelf" %>
		</div>
		<div id="columns">
			<div id="side">
				<a href="http://www....">Home</a><br />
				<a href="http://www..../faq">Questions</a><br />
				<a href="http://www..../news">News</a><br />
				<a href="http://www..../contact">Contact</a><br />
			</div>
			<div id="main">
				<%= @content_for_layout %>
			</div>
		</div>
	</body>
</html>


D:\work\depot\app\views\store\index.rhtml
<% for product in @products %>
	<div class="catalogentry">
		<img src="<%= product.image_url %>"/>
		<h3><%=h product.title %></h3>
		<%= product.description %>
		<span class="catalogprice">$<%= sprintf("%0.2f", product.price) %></span>		
		<%= link_to 'Add to Cart',
										{:action => 'add_to_cart', :id => product },
										:class => 'addtocart' %><br />
	<div class="separator">&nbsp;</div>
<% end %>
<%= link_to "Show my cart", :action => "display_cart" %>


D:\work\depot\public\stylesheets\depot.css
/* Global styles */

/* START:notice */
#notice {
  border: 2px solid red;
  padding: 1em;
  margin-bottom: 2em;
  background-color: #f0f0f0;
  font: bold smaller sans-serif;
}
/* END:notice */

/* Styles for admin/list */

#product-list .list-title {
	color:        #244;
	font-weight:  bold;
	font-size:    larger;
}

#product-list .list-image {
  width:        60px;
  height:       70px;
}


#product-list .list-actions {
  font-size:    x-small;
  text-align:   right;
  padding-left: 1em;
}

#product-list .list-line-even {
  background:   #e0f8f8;
}

#product-list .list-line-odd {
  background:   #f8b0f8;
}


/* Styles for main page */

#banner {
  background: #9c9;
  padding-top: 10px;
  padding-bottom: 10px;
  border-bottom: 2px solid;
  font: small-caps 40px/40px "Times New Roman", serif;
  color: #282;
  text-align: center;
}

#banner img {
  float: left;
}

#columns {
  background: #141;
}

#main {
  margin-left: 15em;
  padding-top: 4ex;
  padding-left: 2em;
  background: white;
}

#side {
  float: left;
  padding-top: 1em;
  padding-left: 1em;
  padding-bottom: 1em;
  width: 14em;
  background: #141;
}

#side a {
  color: #bfb;
  font-size: small;
}

h1 {
  font:  150% sans-serif;
  color: #226;
  border-bottom: 3px dotted #77d;
}

/* And entry in the store catalog */

#store  .entry {
  border-bottom: 1px dotted #77d;
}

#store  .title {
  font-size: 120%;
  font-family: sans-serif;
}

#store .entry img {
  width: 75px;
  float: left;
}


#store .entry h3 {
 margin-bottom: 2px;
 color: #227;
}

#store .entry p {
 margin-top: 0px; 
 margin-bottom: 0.8em; 
}

#store .entry .price-line {
}

#store .entry .add-to-cart {
  position: relative;
}

#store .entry  .price {
  color: #44a;
  font-weight: bold;
  margin-right: 2em;
}

/* START:inline */
#store .entry form, #store .entry form div {
  display: inline;
}
/* END:inline */

/* START:cart */
/* Styles for the cart in the main page and the sidebar */

.cart-title {
  font: 120% bold; 
}

.item-price, .total-line {
  text-align: right;	
}

.total-line .total-cell {
  font-weight: bold;
  border-top: 1px solid #595;
}


/* Styles for the cart in the sidebar */

#cart, #cart table {
  font-size: smaller;	
  color:     white;

}

#cart table {
  border-top:    1px dotted #595;
  border-bottom: 1px dotted #595;
  margin-bottom: 10px;
}
/* END:cart */

/* Styles for order form */

.depot-form fieldset {
  background: #efe;
}

.depot-form legend {
  color: #dfd;
  background: #141;
  font-family: sans-serif;
  padding: 0.2em 1em;
}

.depot-form label {
  width: 5em;
  float: left;
  text-align: right;
  margin-right: 0.5em;
  display: block;
}

.depot-form .submit {
  margin-left: 5.5em;
}

/* The error box */

.fieldWithErrors {
  padding: 2px;
  background-color: red;
  display: table;
}

#errorExplanation {
  width: 400px;
  border: 2px solid red;
  padding: 7px;
  padding-bottom: 12px;
  margin-bottom: 20px;
  background-color: #f0f0f0;
}

#errorExplanation h2 {
  text-align: left;
  font-weight: bold;
  padding: 5px 5px 5px 15px;
  font-size: 12px;
  margin: -7px;
  background-color: #c00;
  color: #fff;
}

#errorExplanation p {
  color: #333;
  margin-bottom: 0;
  padding: 5px;
}

#errorExplanation ul li {
  font-size: 12px;
  list-style: square;
}


第八章 任务C: 创建购物车

D:\work\depot\app\controllers\store_controller.rb
class StoreController < ApplicationController

  def index
  	@products = Product.salable_items
  end
  
  private
  def find_cart
  	session[:cart] ||= Cart.new
  end
end


drop table if exists line_items;
create table line_items (
	id							int							not null auto_increment,
	product_id			int							not null,
	quantity				int							not null default 0,
	unit_price			decimal(10,2)		not null,
	constraint fk_items_product foreign key (product_id) references products(id),
	primary key (id)
);


D:\work\depot\db\product_data.sql

lock tables products write;
insert into products(	title, description, image_url, price, date_available ) values(
											'Pragmatic Project Automation',
											'A really great read!',
                      'http://localhost:3000/images/svn.JPG',
                      '29.95',
                      '2007-12-25 05:00:00'	);
insert into products(	title, description, image_url, price, date_available ) values(
                      'Pragmatic Version Control',
                      'A really contrlooed read!',
                      'http://localhost:3000/images/utc.jpg',
                      '29.95',
                      '2007-12-01 05:00:00');
insert into products(  title, description, image_url, price, date_available ) values(
                     'Pragmatic Version Control2',
                     'A really contrlooed read!',
                     'http://localhost:3000/images/auto.jpg',
                     '29.95',
                     '2007-12-01 05:00:00');
unlock tables;


D:\work\depot>mysql -u root depot_development <db/product_data.sql (导入数据)

下面说明在mysql中 exit 和 quit 命令都可以退出 mysql
D:\work\depot>mysql -u root
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 41 to server version: 5.0.27-community-nt

Type 'help;' or '\h' for help. Type '\c' to clear the buffer.

mysql> use depot_development
Database changed
mysql> delete from products;
Query OK, 3 rows affected (0.05 sec)

mysql> exit
Bye

D:\work\depot>mysql -u root
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 42 to server version: 5.0.27-community-nt

Type 'help;' or '\h' for help. Type '\c' to clear the buffer.

mysql> quit
Bye

D:\work\depot>

D:\work\depot>ruby script/generate model LineItem

D:\work\depot\app\models\line_item.rb
class LineItem < ActiveRecord::Base
	belongs_to :product
end


D:\work\depot\app\controllers\store_controller.rb
  def add_to_cart
  	product = Product.find(params[:id])
  	@cart = find_cart
  	@cart.add_product(product)
  	redirect_to(:action => 'display_cart')
  end


D:\work\depot\app\models\cart.rb
class Cart
	attr_reader :items
	attr_reader :total_price
	def initialize
		@items = []
		@total_price = 0.0
	end
	def add_product(product)
		@items << LineItem.for_product(product)
		@total_price += product.price
	end
end


D:\work\depot\app\models\line_item.rb
class LineItem < ActiveRecord::Base
	belongs_to :product
	def self.for_product(product)
		item = self.new
		item.quantity = 1
		item.product = product
		item.unit_price = product.price
		item
	end
end


D:\work\depot\app\controllers\store_controller.rb
  def display_cart
  	@cart = find_cart
  	@items = @cart.items
  end


D:\work\depot\app\views\store\display_cart.rhtml
<h1>Display Cart</h1>
<p>
	Your cart contains <%= @items.size %> items.
</p>


D:\work\depot\app\controllers\application.rb
# Filters added to this controller apply to all controllers in the application.
# Likewise, all the methods added will be available for all controllers.

class ApplicationController < ActionController::Base
	model :cart
	model :line_item
  # Pick a unique cookie name to distinguish our session data from others'
  session :session_key => '_depot_session_id'
end


D:\work\depot\app\views\store\display_cart.rhtml

<h1>Display Cart</h1>
<table>
<% for item in @items 
		product = item.product
-%>
	<tr>
		<td><%= item.quantity %></td>
		<td><%= h(product.title) %></td>
		<td align="right"><%= item.unit_price %></td>
		<td aling="right"><%= item.unit_price * item.quantity %></td>
	</tr>
<% end -%>
<table>


D:\work\depot\app\models\cart.rb

class Cart
	attr_reader :items
	attr_reader :total_price
	def initialize
		@items = []
		@total_price = 0.0
	end
	def add_product(product)
		item = @items.find {|i| i.product_id == product.id}
		if item
			item.quantity += 1
		else
			item = LineItem.for_product(product)
			@items << item
		end
		@total_price += product.price
	end
end


美化购物车

D:\work\depot\app\views\store\display_cart.rhtml

<div id="cartmenu">
	<u1>
		<li><%= link_to 'Continue shopping', :action => "index" %></li>
		<li><%= link_to 'Empty car', :action => "empty_cart" %></li>
		<li><%= link_to 'Checkout', :action => "checkout" %></li>
	</u1>
</div>
<table cellpadding="10" cellspacing="0">
	<tr class="carttitle">
		<td rowspan="2">Qty</td>
		<td rowspan="2">Description</td>
		<td colspan="2">Price</td>
	</tr>
	<tr class="carttitle">
		<td>Each</td>
		<td>Total</td>
	</tr>
<%
for item in @items
	product = item.product
-%>
	<tr>
		<td><%= item.quantity %></td>
		<td><%= h(product.title) %></td>
		<td align="right"><%= item.unit_price %></td>
		<td align="right"><%=item.unit_price * item.quantity %></td>
	</tr>
<% end %>
	<tr>
		<td colspan="3" align="right"><strong>Total:</strong></td>
		<td id="totalcell"><%= @cart.total_price %></td>
	</tr>
</table>


处理错误

D:\work\depot\app\controllers\store_controller.rb

  def add_to_cart
  	product = Product.find(params[:id])
  	@cart = find_cart
  	@cart.add_product(product)
  	redirect_to(:action => 'display_cart')
  rescue
  	logger.error("Attempt to access invalid product #{params[:id]}")
  	flash[:notice] = 'Invalid product'
  	redirect_to(:action => 'index')
  end


D:\work\depot\log\development.log

D:\work\depot\app\views\layouts\store.rhtml
<html>
	<head>
		<title>Pragprog Books Online Store</title>
		<%= stylesheet_link_tag "depot", :media => "all" %>
	</head>
	<body>
		<div id="banner">
			<img src="/images/logo.png" />
			<%= @page_title || "Pragmatic Bookshelf" %>
		</div>
		<div id="columns">
			<div id="side">
				<a href="http://www....">Home</a><br />
				<a href="http://www..../faq">Questions</a><br />
				<a href="http://www..../news">News</a><br />
				<a href="http://www..../contact">Contact</a><br />
			</div>
			<div id="main">
				<% if @flash[:notice] -%>
					<div id="notice"><%= @flash[:notice] %></div>
				<% end -%>
				<%= @content_for_layout %>
			</div>
		</div>
	</body>
</html>


D:\work\depot\app\controllers\store_controller.rb

class StoreController < ApplicationController

  def index
  	@products = Product.salable_items
  end
  
  def add_to_cart
  	product = Product.find(params[:id])
  	@cart = find_cart
  	@cart.add_product(product)
  	redirect_to(:action => 'display_cart')
  rescue
  	logger.error("Attempt to access invalid product #{params[:id]}")
  	flash[:notice] = 'Invalid product'
  	redirect_to(:action => 'index')
  end
  
  def display_cart
  	@cart = find_cart
  	@items = @cart.items
  	if @items.empty?
  		flash[:notice] = "Your cart is currently empty"
  		redirect_to(:action => 'index')
  	end
  end
  
  private
  def find_cart
  	session[:cart] ||= Cart.new
  end
end


D:\work\depot\app\views\store\display_cart.rhtml

<% @page_title = "Your Pragmatic Cart" -%>
<div id="cartmenu">
	<u1>
		<li><%= link_to 'Continue shopping', :action => "index" %></li>
		<li><%= link_to 'Empty car', :action => "empty_cart" %></li>
		<li><%= link_to 'Checkout', :action => "checkout" %></li>
	</u1>
</div>
<table cellpadding="10" cellspacing="0">
	<tr class="carttitle">
		<td rowspan="2">Qty</td>
		<td rowspan="2">Description</td>
		<td colspan="2">Price</td>
	</tr>
	<tr class="carttitle">
		<td>Each</td>
		<td>Total</td>
	</tr>
<%
for item in @items
	product = item.product
-%>
	<tr>
		<td><%= item.quantity %></td>
		<td><%= h(product.title) %></td>
		<td align="right"><%= item.unit_price %></td>
		<td align="right"><%=item.unit_price * item.quantity %></td>
	</tr>
<% end %>
	<tr>
		<td colspan="3" align="right"><strong>Total:</strong></td>
		<td id="totalcell"><%= @cart.total_price %></td>
	</tr>
</table>


完成购物车

D:\work\depot\app\controllers\store_controller.rb
	def empty_cart
		@cart = find_cart
		@cart.empty!
		flash[:notice] = 'Your cart is now empty'
		redirect_to(:action => 'index')
	end


D:\work\depot\app\models\cart.rb
	def empty!
		@items = []
		@total_price = 0.0
	end


D:\work\depot\app\controllers\store_controller.rb

class StoreController < ApplicationController

  def index
  	@products = Product.salable_items
  end
  
  def add_to_cart
  	product = Product.find(params[:id])
  	@cart = find_cart
  	@cart.add_product(product)
  	redirect_to(:action => 'display_cart')
  rescue
  	logger.error("Attempt to access invalid product #{params[:id]}")
  	redirect_to_index(:action => 'Invalid product')
  end

	def empty_cart
		@cart = find_cart
		@cart.empty!
		redirect_to_index(:action => 'Your cart is now empty')
	end
  
  def display_cart
  	@cart = find_cart
  	@items = @cart.items
  	if @items.empty?
  		redirect_to_index('Your cart is currently empty')
  	end
  end
  
  private  
  def find_cart
  	session[:cart] ||= Cart.new
  end  
  def redirect_to_index(msg = nil)
  	flash[:notice] = msg if msg
  	redirect_to(:action => 'index')
  end
end


D:\work\depot\app\models\cart.rb
class Cart
	attr_reader :items
	attr_reader :total_price
	def initialize
		empty!
	end
	
	def empty!
		@items = []
		@total_price = 0.0
	end
	
	def add_product(product)
		item = @items.find {|i| i.product_id == product.id}
		if item
			item.quantity += 1
		else
			item = LineItem.for_product(product)
			@items << item
		end
		@total_price += product.price
	end
end


辅助方法

D:\work\depot\app\helpers\application_helper.rb
# Methods added to this helper will be available to all templates in the application.
module ApplicationHelper
	def fmt_dollars(amt)
		sprintf("$%0.2f", amt)
	end
end


D:\work\depot\app\views\store\display_cart.rhtml
<% @page_title = "Your Pragmatic Cart" -%>
<div id="cartmenu">
	<u1>
		<li><%= link_to 'Continue shopping', :action => "index" %></li>
		<li><%= link_to 'Empty car', :action => "empty_cart" %></li>
		<li><%= link_to 'Checkout', :action => "checkout" %></li>
	</u1>
</div>
<table cellpadding="10" cellspacing="0">
	<tr class="carttitle">
		<td rowspan="2">Qty</td>
		<td rowspan="2">Description</td>
		<td colspan="2">Price</td>
	</tr>
	<tr class="carttitle">
		<td>Each</td>
		<td>Total</td>
	</tr>
<%
for item in @items
	product = item.product
-%>
	<tr>
		<td><%= item.quantity %></td>
		<td><%= h(product.title) %></td>
		<td align="right"><%= fmt_dollars(item.unit_price) %></td>
		<td align="right"><%= fmt_dollars(item.unit_price * item.quantity) %></td>
	</tr>
<% end %>
	<tr>
		<td colspan="3" align="right"><strong>Total:</strong></td>
		<td id="totalcell"><%= fmt_dollars(@cart.total_price) %></td>
	</tr>
</table>


D:\work\depot\app\views\store\index.rhtml
<% for product in @products %>
	<div class="catalogentry">
		<img src="<%= product.image_url %>"/>
		<h3><%=h product.title %></h3>
		<%= product.description %>
		<span class="catalogprice"><%= fmt_dollars(product.price) %></span>		
		<%= link_to 'Add to Cart',
										{:action => 'add_to_cart', :id => product },
										:class => 'addtocart' %><br />
	<div class="separator">&nbsp;</div>
<% end %>
<%= link_to "Show my cart", :action => "display_cart" %>


第九章 任务D: 结账

D:\work\depot\db\create.sql
drop table if exists line_items;
drop table if exists orders;
drop table if exists products;

create table products (
	id							int						not null auto_increment,
	title						varchar(100)	not null,
	description			text					not null,
	image_url				varchar(200)	not null,
	price						decimal(10,2)	not null,
	date_available	datetime			not null,
	primary key(id)
);

create table orders (
	id          int           not null auto_increment,
	name			  varchar(100)  not null,
	email       varchar(255)  not null,
	address     text          not null,
	pay_type    char(10)      not null,
	primary key (id)
);

create table line_items (
	id							int							not null auto_increment,
	product_id			int							not null,
	order_id			int							not null,
	quantity				int							not null default 0,
	unit_price			decimal(10,2)		not null,
	constraint fk_items_product foreign key (product_id) references products(id),
	constraint fk_items_order foreign key (order_id) references orders(id),
	primary key (id)
);


D:\work\depot\app\models\order.rb
class Order < ActiveRecord::Base
	has_many :line_items
end


D:\work\depot\app\models\line_item.rb
class LineItem < ActiveRecord::Base
	belongs_to :product
	belongs_to :order
	def self.for_product(product)
		item = self.new
		item.quantity = 1
		item.product = product
		item.unit_price = product.price
		item
	end
end


D:\work\depot\app\controllers\store_controller.rb
  def checkout
  	@cart = find_cart
  	@items = @cart.items
  	if @items.empty?
  		redirect_to_index("There's nothing in your cart!")
  	else
  		@order = Order.new
  	end
  end


D:\work\depot\app\views\store\checkout.rhtml
<% @page_title = "Checkout" -%>
<%= start_form_tag(:action => "save_order") %>
<table>
	<tr>
		<td>Name:</td>
		<td><%= text_field("order", "name", "size" => 40) %></td>
	</tr>
	<tr>
		<td>EMail:</td>
		<td><%= text_field("order", "email", "size" => 40) %></td>
	</tr>
	<tr valign="top">
		<td>Address:</td>
		<td><%= text_area("order", "address", "cols" => 40, "rows" => 5) %></td>
	</tr>
	<tr>
		<td>Pay using:</td>
		<td><%=
			options = [["Select a payment option", ""]] + Order::PAYMENT_TYPES
			select("order", "pay_type", options) %></td>
	</tr>
	<tr>
		<td></td>
		<td><%= submit_tag(" CHECKOUT ") %></td>
	</tr>
</table>
<%= end_form_tag %>		


D:\work\depot\app\models\order.rb
class Order < ActiveRecord::Base
	has_many :line_items
	
	PAYMENT_TYPES = [
		[ "Check",					"check"],
		[ "Credit Card",		"cc"],
		[ "Purchas Order",	"po"]
	].freeze  # freeze to make this array constant
end


D:\work\depot\app\controllers\store_controller.rb
class StoreController < ApplicationController

  def index
  	@products = Product.salable_items
  end
  
  def add_to_cart
  	product = Product.find(params[:id])
  	@cart = find_cart
  	@cart.add_product(product)
  	redirect_to(:action => 'display_cart')
  rescue
  	logger.error("Attempt to access invalid product #{params[:id]}")
  	redirect_to_index(:action => 'Invalid product')
  end

	def empty_cart
		@cart = find_cart
		@cart.empty!
		redirect_to_index(:action => 'Your cart is now empty')
	end
  
  def display_cart
  	@cart = find_cart
  	@items = @cart.items
  	if @items.empty?
  		redirect_to_index('Your cart is currently empty')
  	end
  end
  
  def checkout
  	@cart = find_cart
  	@items = @cart.items
  	if @items.empty?
  		redirect_to_index("There's nothing in your cart!")
  	else
  		@order = Order.new
  	end
  end
  
  def save_order
  	@cart = find_cart
  	@order = Order.new(params[:order])
  	@order.line_items << @cart.items
  	if @order.save
  		@cart.empty!
  		redirect_to_index('Thank you for your order.')
  	else
  		render(:action => 'checkout')
  	end
  end
  
  private  
  def find_cart
  	session[:cart] ||= Cart.new
  end  
  def redirect_to_index(msg = nil)
  	flash[:notice] = msg if msg
  	redirect_to(:action => 'index')
  end
end


D:\work\depot\app\models\order.rb
class Order < ActiveRecord::Base
	has_many :line_items
	
	PAYMENT_TYPES = [
		[ "Check",					"check"],
		[ "Credit Card",		"cc"],
		[ "Purchas Order",	"po"]
	].freeze  # freeze to make this array constant
	
	validates_presence_of :name, :email, :address, :pay_type
	
end


D:\work\depot\app\views\layouts\store.rhtml
<html>
	<head>
		<title>Pragprog Books Online Store</title>
		<%= stylesheet_link_tag "scaffold", "depot", :media => "all" %>
	</head>
	<body>
		<div id="banner">
			<img src="/images/logo.png" />
			<%= @page_title || "Pragmatic Bookshelf" %>
		</div>
		<div id="columns">
			<div id="side">
				<a href="http://www....">Home</a><br />
				<a href="http://www..../faq">Questions</a><br />
				<a href="http://www..../news">News</a><br />
				<a href="http://www..../contact">Contact</a><br />
			</div>
			<div id="main">
				<% if @flash[:notice] -%>
					<div id="notice"><%= @flash[:notice] %></div>
				<% end -%>
				<%= @content_for_layout %>
			</div>
		</div>
	</body>
</html>


mysql> select * from orders;
+----+------+---------------+----------------+----------+
| id | name | email         | address        | pay_type |
+----+------+---------------+----------------+----------+
|  3 | aaaa | bbbb@aaaa.com | aaaa bbbb cccc | cc       |
+----+------+---------------+----------------+----------+
1 row in set (0.00 sec)

mysql> select * from line_items;
+----+------------+----------+----------+------------+
| id | product_id | order_id | quantity | unit_price |
+----+------------+----------+----------+------------+
|  1 |          1 |        3 |        1 |      29.95 |
|  2 |          2 |        3 |        1 |      29.95 |
|  3 |          3 |        3 |        1 |      29.95 |
+----+------------+----------+----------+------------+
3 rows in set (0.00 sec)

迭代D2: 在付账页面显示购物车内容

D:\work\depot\app\views\store\checkout.rhtml

<% @page_title = "Checkout" -%>
<%= error_messages_for("order") %>
<%= render_component(:acton => "display_cart") %>
<%= start_form_tag(:action => "save_order") %>
<table>
	<tr>
		<td>Name:</td>
		<td><%= text_field("order", "name", "size" => 40) %></td>
	</tr>
	<tr>
		<td>EMail:</td>
		<td><%= text_field("order", "email", "size" => 40) %></td>
	</tr>
	<tr valign="top">
		<td>Address:</td>
		<td><%= text_area("order", "address", "cols" => 40, "rows" => 5) %></td>
	</tr>
	<tr>
		<td>Pay using:</td>
		<td><%=
			options = [["Select a payment option", ""]] + Order::PAYMENT_TYPES
			select("order", "pay_type", options) %></td>
	</tr>
	<tr>
		<td></td>
		<td><%= submit_tag(" CHECKOUT ") %></td>
	</tr>
</table>
<%= end_form_tag %>	



D:\work\depot\app\views\store\checkout.rhtml
<% @page_title = "Checkout" -%>
<%= error_messages_for("order") %>
<%= render_component(:acton => "display_cart",
                     :params => { :context => :checkout }) %>
<%= start_form_tag(:action => "save_order") %>
<table>
	<tr>
		<td>Name:</td>
		<td><%= text_field("order", "name", "size" => 40) %></td>
	</tr>
	<tr>
		<td>EMail:</td>
		<td><%= text_field("order", "email", "size" => 40) %></td>
	</tr>
	<tr valign="top">
		<td>Address:</td>
		<td><%= text_area("order", "address", "cols" => 40, "rows" => 5) %></td>
	</tr>
	<tr>
		<td>Pay using:</td>
		<td><%=
			options = [["Select a payment option", ""]] + Order::PAYMENT_TYPES
			select("order", "pay_type", options) %></td>
	</tr>
	<tr>
		<td></td>
		<td><%= submit_tag(" CHECKOUT ") %></td>
	</tr>
</table>
<%= end_form_tag %>	


D:\work\depot\app\controllers\store_controller.rb

修改如下方法:
  def display_cart
  	@cart = find_cart
  	@items = @cart.items
  	if @items.empty?
  		redirect_to_index('Your cart is currently empty')
  	end
  	if params[:context] == :checkout
  		render(:layout => false )
  	end
  end


D:\work\depot\app\views\store\display_cart.rhtml
<% @page_title = "Your Pragmatic Cart" -%>
<div id="cartmenu">
	<u1>
		<li><%= link_to 'Continue shopping', :action => "index" %></li>
		<% unless params[:context] == :checkout -%>
		<li><%= link_to 'Empty car', :action => "empty_cart" %></li>
		<li><%= link_to 'Checkout', :action => "checkout" %></li>
		<% end -%>
	</u1>
</div>
<table cellpadding="10" cellspacing="0">
	<tr class="carttitle">
		<td rowspan="2">Qty</td>
		<td rowspan="2">Description</td>
		<td colspan="2">Price</td>
	</tr>
	<tr class="carttitle">
		<td>Each</td>
		<td>Total</td>
	</tr>
<%
for item in @items
	product = item.product
-%>
	<tr>
		<td><%= item.quantity %></td>
		<td><%= h(product.title) %></td>
		<td align="right"><%= fmt_dollars(item.unit_price) %></td>
		<td align="right"><%= fmt_dollars(item.unit_price * item.quantity) %></td>
	</tr>
<% end %>
	<tr>
		<td colspan="3" align="right"><strong>Total:</strong></td>
		<td id="totalcell"><%= fmt_dollars(@cart.total_price) %></td>
	</tr>
</table>


D:\work\depot\app\views\store\checkout.rhtml
<% @page_title = "Checkout" -%>
<%= error_messages_for("order") %>
<%= render_component(:acton => "display_cart",
                     :params => { :context => :checkout }) %>
<h3>Please enter your details below</h3>
<%= start_form_tag(:action => "save_order") %>
<table>
	<tr>
		<td>Name:</td>
		<td><%= text_field("order", "name", "size" => 40) %></td>
	</tr>
	<tr>
		<td>EMail:</td>
		<td><%= text_field("order", "email", "size" => 40) %></td>
	</tr>
	<tr valign="top">
		<td>Address:</td>
		<td><%= text_area("order", "address", "cols" => 40, "rows" => 5) %></td>
	</tr>
	<tr>
		<td>Pay using:</td>
		<td><%=
			options = [["Select a payment option", ""]] + Order::PAYMENT_TYPES
			select("order", "pay_type", options) %></td>
	</tr>
	<tr>
		<td></td>
		<td><%= submit_tag(" CHECKOUT ") %></td>
	</tr>
</table>
<%= end_form_tag %>


分享到:
评论

相关推荐

    ruby on rails 实践

    第一章“Ruby on Rails概述”,介绍了Ruby on Rails的基本概念和开发环境的搭建方法。通过这一章的学习,读者将对Rails框架有一个整体的认识,并了解如何搭建开发环境以及设计用户界面(UI)。 第二章“Rails中的...

    Ruby on Rails心得

    陈刚撰写的《Ruby on Rails心得_V0.1》是一份非常宝贵的资料,旨在记录作者在学习Ruby on Rails过程中的所见所得,包括读书笔记、心得体会、自创教程及一些常见问题的解决方案。作者通过写作这种方式不仅加深了对...

    ruby-on-the-way:学习 ruby 和 rails 相关资料

    本资料包“ruby-on-the-way”显然是一份用于学习Ruby和Rails的资源集合,旨在帮助初学者掌握这两项技术。 首先,让我们深入了解Ruby语言的关键特性: 1. 动态类型:Ruby不像Java或C++那样需要提前声明变量的类型,...

    ruby笔记2ruby笔记2ruby笔记2

    "ruby笔记2ruby笔记2ruby笔记2"可能是指一系列关于Ruby学习的笔记,这些笔记可能涵盖了Ruby的基础概念、核心特性以及进阶话题。在Ruby的学习过程中,理解和掌握以下几个关键知识点至关重要: 1. **面向对象编程...

    Ruby学习资料(含参考手册和Programming Ruby)-中文.rar

    其次,"Ruby初级教程(Ruby用户指南).chm"是针对初学者的教程,它详细解释了如何开始使用Ruby,包括安装Ruby环境、编写第一个程序、变量、控制结构等基础知识。对于刚接触Ruby的人来说,这是个很好的起点。 "Ruby...

    ROR 学习笔记系列一 Windows XP下环境安装配置(2)

    Ruby是Rails的基础,因此在Windows XP上安装Ruby是第一步。你可以访问Ruby官方网站(ruby-lang.org)下载适合Windows的Ruby安装包。确保下载与你的系统兼容的版本,通常是x86架构。安装过程中,记得勾选添加Ruby到...

    我的ror的第一天

    标题 "我的ror的第一天" 暗示了这是一个关于Ruby on Rails (RoR) 开发初体验的分享,其中可能涵盖了作者初次接触RoR时的学习过程、遇到的问题以及解决方法。Rails是Ruby的一个Web开发框架,它以MVC(模型-视图-控制...

    mytestrails

    尽管如此,我们可以从 "railstutorial4th-1.0.0.pdf" 这个文件名中推测,这可能是 Michael Hartl 的《Ruby on Rails 教程》第四版的早期版本。这本书是学习 Rails 的经典参考资料,涵盖了从基础到高级的许多主题。 ...

    learnRoR:艰难地学习RoR

    【描述】中的"#我的第一次ROR学习"表明这是一个初学者的学习笔记,记录了作者初次接触并尝试理解Rails的体验。提到"ando"可能是指作者在学习过程中参考了一位名叫Ando的人的教程或者资源。"ror教程"则可能指的是...

    Lin-Ether.github.io

    总结来说,"Lin-Ether.github.io" 是一个使用 Ruby on Rails 或相关静态站点生成器构建的个人博客项目,作者通过它分享学习笔记。博客尚未完成,未来可能有更多内容更新。对于对 Ruby 或 web 开发感兴趣的人来说,这...

    TIL:今天我学到了

    这个目录可能包含了一系列关于Ruby学习的笔记、代码示例、练习项目或其他资源。 详细知识点: 1. **面向对象编程**:Ruby是一种纯面向对象的语言,所有数据都是对象,每一个操作都可以看作是对对象的方法调用。 2...

    mastodon-main.zip

    Mastodon 的核心是 Ruby on Rails,这是一个流行的Web开发框架,基于Ruby编程语言。Rails 提供了一套完整的工具链,用于快速构建数据驱动的Web应用程序。它的MVC(模型-视图-控制器)架构模式使得开发者能够清晰地...

    基于WEB程序设计基础-浙江大学(13)

    3. **Web框架应用**:为了提高开发效率,Web开发者通常使用框架,如Java的Spring、Python的Django或Flask、Ruby on Rails等。这些框架提供了预设的结构和功能,如路由、模板引擎、ORM(对象关系映射)。学习框架能...

    java简易版开心农场源码-spring-boot-tut:弹簧靴

    话说我当年接触Spring的时候着实兴奋了好一阵,IoC的概念当初第一次听说,感觉有种开天眼的感觉。记得当时的web框架和如今的前端框架的局面差不多啊,都是群雄纷争。但一晃好多年没写过后端,代码这东西最怕手生,...

    java版商城源码下载-spring-boot-tut:MySpringBootTutorial--Focusingonminimizingt

    话说我当年接触Spring的时候着实兴奋了好一阵,IoC的概念当初第一次听说,感觉有种开天眼的感觉。记得当时的web框架和如今的前端框架的局面差不多啊,都是群雄纷争。但一晃好多年没写过后端,代码这东西最怕手生,...

    odinproject:我的Odin Project提交

    Ruby on Rails(简称Rails)是一个流行的Web应用框架,它遵循MVC(模型-视图-控制器)架构模式,大大简化了Web开发。 在压缩包"odinproject-master"中,你可能找到了以下类型的文件: - **练习和项目代码**:每个...

    MacEnvInit::smiling_face:OA的Mac重灌后环境建置笔记

    16. **Ruby on Rails**:基于Ruby语言的Web开发框架,以其"约定优于配置"的理念著称。 17. **Sublime Text 2**:广受欢迎的代码编辑器,拥有丰富的插件和快捷键,提高开发效率。 18. **SourceTree**:Git的图形化...

Global site tag (gtag.js) - Google Analytics