- 浏览: 32365 次
- 性别:
- 来自: 福建
文章分类
最新评论
Agile Web Development with Rails 4E 2011.03
========zqhxuyuan@gmail.com 2011.10========
===========================================
Chapter6. Task A: Creating the Application
1.1 创建Rails项目depot:
> rails new depot
1.2 切换到depot目录下:
> cd depot
使用Rails3默认的数据库SQLite3
1.3 创建项目的脚手架:
> rails generate scaffold Product
title:string description:text image_url:string price:decimal
生成数据库脚本: db/migrate/create_products.rb 如果想查看表结构:db/schema.rb
Model: app/models/product.rb
View: app/views/products/*.html.erb
Controller: app/controllers/products_controller.rb
test: test/unit/product_test.rb test/functional/products_controller_test.rb
(注意:Model是单数,以及Model的单元测试test/unit/product_test.rb
复数的有:View:products/
Controller:products_controller.rb 以及Controller的Fucntional测试:products_controller_test.rb)
1.4 修改Product对应的表的某个字段的长度和精度,修改后需要和原先的数据库进行migrate:
-> db/migrate/create_products.rb
class CreateProducts < ActiveRecord::Migration
t.decimal :price, :precision => 8, :scale => 2
end
> rake db:migrate
1.5 启动Rails内置服务器WEBrick,访问以上URL,查看Products列表:
> rails server
@ http://localhost:3000/products
点击列表页面的New Product进入http://localhost:3000/products/new
在新增页面输入数据,提交,并返回 http://localhost:3000/products 则可以看到新增的记录
分析CRUD的流程1--页面跳转:
http://localhost:3000/products/ 满足app/controllers/products_controller.rb ProductsController
的URL命名约定: GET /products 对应的方法是: index
在index方法里取得所有的products: @products = Product.all
页面指向respond_to -> format.html # index.html.erb 即app/views/products/index.html.erb
(# index.html.erb是注释,因为该方法名为index,所以format.html的值为:index.html.erb)
在index.html.erb中@products.each do |product|取出所有的products循环输出每个Product的信息
数据的获取是通过Json方式,Controller中在指向index.html.erb时获取到了Json数据: format.json { render json: @products }
新增Product,路径为:link_to new_product_path 根据Rails的命名约定满足
GET /products/new 的URL(link_to: Get; new_product_path: /products/new ). 会调用Controller的new方法并指向new.html.erb
new.html.erb 只有一行代码: <%= render 'form' %> 指向_form.html.erb
_form.html.erb 有两部分组成,一是错误信息的显示,比如提交时数据验证失败显示错误信息;第二部分即是表单的数据了
在新增页面提交表单 最终会调用到Controller的create方法,保存数据...
1.7 测试以上所写的代码是否正确:
> rake test
This is for the unit, functional, and integration tests that
Rails generates along with the scaffolding. 注意当修改了Controller,Model中的代码时,
运行rake test可能会报错,这时候需要对test/中相应的测试文件进行修改.
1.8 在服务器启动时,进行初始化数据的导入.下面这种方式更加对象化,而不是用insert SQL语句:
-> db/seeds.rb
Product.create(:title=>'sth',:description=>'sth',:image_url=>'spath',:price=>11.22)
> rake db:seed
@ http://localhost:3000/products
1.9 关于全局Layout:
app/views/layouts/application.html.erb
所有的views/*/*.html.erb都将继承application.html.erb的布局.可以在这里写每个页面固定的开头和结尾.
Rails keeps a separate file that is used to create a standard page environment for the entire application
application.html.erb, be the layout used for all views for all controllers that don’t otherwise provide a layout.
除非Controller有自己的Layout会覆盖掉全局的Layout.否则Application Layout会应用到所有的视图里.
We loaded some test data into the database(1.8), we rewrote the index.html.erb file
that displays the listing of products, we added a depot.css stylesheet, and that
stylesheet was loaded into our page by the layout file application.html.erb(1.9).
===========================================
Chapter 7. Task B: Validation and Unit Testing
2.1 给Product Model添加字段验证:
-> app/models/product.rb
class Product < ActiveRecord::Base
validates :title, :description, :image_url, :presence => true
validates :price, :numericality => {:greater_than_or_equal_to => 0.01}
validates :title, :uniqueness => true
validates :image_url, :format => {
:with => %r{\.(gif|jpg|png)$}i,
:message => 'must be a URL for GIF, JPG or PNG image.'
}
end
访问http://localhost:3000/products/new 提交时会对输入域进行验证 如果验证失败则会在页面顶部显示错误信息.
2.2 给Model添加验证后的单元测试:
> rake test
运行测试脚本,会发现报错test/functional/products_controller_test.rb:
test_should_create_product test_should_update_product
很显然当我们增加了Model的验证代码,测试部分也需要更改:
在测试脚本文件中ProductsControllerTest 的setup方法里初始化一个Product对象@update
并在2个报错的方法里把product: @product.attributes 改为 :product => @update指向初始化的product对象
setup方法第一行: @product = products(:one) 获取test/fixtures/products.yml中的数据
这是测试文件初始化加载的数据,正如seeds.rb是项目启动时初始化加载的数据
2.3 test类型有2种:
unit针对Model测试 test/unit/product_test.rb
class ProductsControllerTest < ActionController::TestCase
可以运行:> rake test:units
functional针对Controller测试 test/functional/products_controller_test.rb
class ProductTest < ActiveSupport::TestCase
可以运行命令:>rake test:functionals
rake test 会测试整个项目是否有错误
===========================================
Chapter 8. Task C: Catalog Display
3.1 创建前台Product展示的控制器和页面:
> rails generate controller store index
创建StroeController和对应的Controller的index方法
和rails generate scaffold不同的是创建脚手架会创建Model,Controller,View,数据库脚本,测试文件等
而generate controller则只创建Controller:
app/controllers/store_controller.rb
app/views/store/index.html.erb
test/functional/store_controller_test.rb
还有一点区别是用generate scaffold创建的View和Controller是复数形式,Model是单数;
而generate controller则是单数.
3.2 上面的命令创建了StoreContoller以及index方法,通过URL:
http://localhost:3000/store/index则会调用对应的方法.进入views/store/index.html.erb
-> config/routes.rb
root :to => 'store#index', :as => 'store'
3.3 删除原先根目录下对应的文件:
> rm public/index.html
当访问 http://localhost:3000 等价于上面的http://localhost:3000/store/index
进入的页面是: views/store/index.html.erb
3.4 访问规则测试:
http://localhost:3000/products 进入后台ProductList的显示页面views/products/index.html.erb
http://localhost:3000/products/index 则会报错:
ActiveRecord::RecordNotFound in ProductsController#show Couldn't find Product with id=index
http://localhost:3000/store 报错:Routing Error No route matches [GET] "/store"
由此可见通过generate scaffold,URL:/products代表访问的是ProductsController的index方法.
但是不能这样子访问:/products/index.
而通过generate controller,contoller中定义了哪些方法,
要访问该方法对应的页面则在controller后加上/方法名即可对应.
===========================================
Chapter 9. Task D: Cart Creation
4.1 创建购物车对象脚手架.但是没有给Cart指定字段:
> rails generate scaffold cart
> rake db:migrate
-> app/controllers/application_controller.rb
class ApplicationController < ActionController::Base
protect_from_forgery
private
def current_cart
Cart.find(session[:cart_id])
rescue ActiveRecord::RecordNotFound
cart = Cart.create
session[:cart_id] = cart.id
cart
end
4.2 创建购物项的脚手架:
> rails generate scaffold line_item product_id:integer cart_id:integer
> rake db:migrate
4.3 目前为止的数据库脚本(schema.rb):
create_table "carts"
end
create_table "line_items"
t.integer "product_id"
t.integer "cart_id"
end
create_table "products"
t.string "title"
t.text "description"
t.string "image_url"
t.decimal "price", :precision => 8, :scale => 2
end
由此可见line_items可以当做carts和products的中间表.
4.3 Connecting Products to Carts: 将Product和Cart互相关联
-> app/models/cart.rb
Cart
has_many :line_items
-> app/models/line_item.rb
LineItem
belongs_to :product
belongs_to :cart
-> app/models/product.rb
Product
has_many :line_items
Cart 1---->N LineItem N<----1 Product ...Order
一个Cart可能有多个LineItem,一个Product也可能有多个LineItem(多个LineItem可能对应一个Product)
4.4 line_items涉及到的级联删除:
4.5 给前台的每个Product添加一个购买按钮:
-> app/views/store/index.html.erb
<%= button_to 'Add to Cart', line_items_path(:product_id => product) %>
button_to line_items_path(:product_id => product) 是如何调用到LineItemsController的create方法?
button_to : POST ; line_items_path : /line_items
LineItemsController中满足POST /line_items的只有create方法
如果是link_to line_items_path. link_to : GET line_items_path 则对应的方法为index
-> app/controllers/line_items_controller.rb
def create
@cart = current_cart
product = Product.find(params[:product_id])
@line_item = @cart.line_items.build(:product => product)
#...
end
为什么是LineItemsController.create而不是CartsController.create.
而且ApplicationController中Cart.create是在哪里定义的?(这个稍后解释)
把Product加入购物车中,即创建了一个购物项.所以使用的是LineItemsController.create.
find the shopping cart for the current session(@cart = current_cart),
add the selected product to that cart(@cart.line_items.build), and display the cart contents.
pass that product we found into @cart.line_items.build.
This causes a new line item relationship to be built between the @cart object and the product.
4.6 添加一个购物项后指向Cart页面,而不是购物项本身:
在LineItemsController.create方法中,
if @line_item.save #保存后
format.html { redirect_to @line_item.cart }
Since the line item object knows how to find the cart object,
all we need to do is add .cart to the method call
那么调用的是CartsController的哪个方法index? show? 换句话说进入的是哪个页面?
@line_item.cart 通过LineItem得到Cart对象,所以实际上是传递了cart_id这个参数.
所以URL的形式应该是/carts/cart_id 类型为GET.满足的方法是show
可以这么理解:将一个购物项加入购物车中,而且这个购物车是Session中唯一的.
如果是/casts即所有的购物车List.显然在我们的应用中是说不通的.
所以app/views/carts/show.html.erb 通过Cart取出当前购物车中所有的购物项
<% @cart.line_items.each do |item| %>
<li><%= item.product.title %></li>
<% end %>
4.7 添加购物项的Functional测试:
因为LineItemsController修改的是create方法.接收参数:product_id
所以test/functional/line_items_controller_test.rb 修改的也是对应的create方法并传递需要的参数:
post :create, :product_id => products(:ruby).id
products(:ruby)是test/fixtures/products.yml中的ruby:对应的记录.
测试重定向: assert_redirected_to cart_path(assigns(:line_item).cart)
cart_path:/carts/ assigns(:line_item).cart把购物项对应的购物车对象的id取出来并设置值,即cart_id
运行测试命令: rake test:functionals
有点不明白这里的Functional测试,在前台Product展示页面添加一个购物项到购物车中,
这里能调用到测试的代码吗?
4.8 测试Session:
在Window上跑Ruby有点慢.有时候启动服务器,刷页面,但是没有反应.
还有更奇怪的问题是,有时候点击Add To Cart,浏览器的地址不是:http://localhost:3000/carts/3
而是http://localhost:3000/line_items?product_id=1 页面会报错说没有line_items这个方法.
这时候可以对服务器Ctrl+C终止下. 然后他就会报一堆的错,但页面却恢复正常了. 这里估计没有完全中止服务器.
测试Session,可以这样子做.关掉浏览器.Session中保留的cart_id消失.
重新访问http://localhost:3000. 点击某个Product购买,URL变为: http://localhost:3000/carts/4
这里的4是新生成的Session中的cart_id.因为如果Session中找不到cart_id
则会重新创建一个新的Cart对象,并把cart_id放入Session中.
同时购物车中的数据只会显示当前添加的Product.
关掉浏览器之前的那次会话的数据(sessionId=3)是不会存在在当前的这个Session中(sessionId=4).
4.9 查看别的数据:
如果想看LineItems,即所有Cart对应哪些Product. 访问:http://localhost:3000/line_items
似乎有点难以理解. 因为一般来说一个浏览器在当前只会有一个Cart,即一个Session中只能有一个Cart.
不过这个结果可以理解为另一种概念: 浏览器的访问历史记录.
如果访问http://localhost:3000/carts 则是看不到数据的.
但是会有多个Show Edit Destroy链接.不过这样的URL没有什么意义了.
相关推荐
在《Agile Web Development with Rails》中,读者可以学习到如何运用敏捷方法来规划项目,实施增量式开发,并通过频繁的反馈来提高产品质量。 Ruby on Rails(简称Rails)是一个基于Ruby语言的开源Web开发框架,它...
Ruby on Rails helps you produce high-quality, beautiful-looking web applications quickly. You concentrate on creating the application, and Rails takes care of the details., Tens of thousands of ...
《Agile Web Development with Rails》(敏捷Web开发:Ruby on Rails)这本书,作为Rails开发新手的教材,强调了敏捷开发方法,并以其帮助开发者建立起一个实用的Web应用。从给出的文件信息来看,这本书正在编写过程...
Agile Web Development with Rails 1-14节_ppt(老师发的修正版)
agile web development with rails 5(英文电子书).............................................................................................................................................................
《敏捷Web开发与Rails》是一本深度探讨如何利用Ruby on Rails框架进行敏捷Web开发的指导书籍,由Dave Thomas、David Heinemeier Hansson等多位在Rails社区有着深厚贡献的作者共同编写。本书不仅覆盖了Rails的基本...
### 敏捷Web开发与Rails 3:关键知识点解析 #### 一、Rails版本与兼容性 本书《敏捷Web开发与Rails》第三版是基于Rails 2编写的。截至本书印刷时,当前可用的Rails Gem版本为2.1。书中所包含的所有代码均已在该...
《敏捷Web开发与Rails:程序指南 第四版》是一本深度探讨使用Ruby on Rails框架进行敏捷Web应用开发的专业书籍。本书旨在帮助开发者充分利用Rails 4的特性,提高开发效率,实现快速迭代和高质量的代码编写。 Rails是...
《敏捷Web开发与Rails》第四版是一本专为软件开发者设计的权威指南,全面涵盖了使用Ruby on Rails框架进行敏捷Web应用开发的知识。Rails 3是该版本的重点,它引入了许多新特性和改进,使得开发过程更为高效且灵活。...
在学习这两本书时,你可以从Pragmatic Programmer - Agile Web Development With Ruby On Rails_05.12.24.pdf和Pragmatic.Bookshelf.Agile.Web.Development.with.Rails.2nd.Edition.pdf中获取详细教程。这些PDF文件...
《Pragmatic - Agile Web Development with Rails》是Ruby on Rails框架的经典教材,旨在引导初学者高效地学习敏捷Web开发。这本书的第三版于2009年发布,它结合了Pragmatic Programmers的实用主义理念与Ruby on ...
Agile Web Development with Rails, 2nd Edition <br>有两份PDF文件,大小分别是7.39MB和6.55MB <br>作者: Dave Thomas , David Heinemeier Hansson , Leon Breedt , Mike Clark , James Duncan Davidson ,...
### Agile Web Development with Rails for Rails 3.2 #### 核心知识点概览 - **Rails 3.2概述** - **敏捷开发方法论** - **Model-View-Controller (MVC) 模式** - **Ruby on Rails基础与高级特性** - **面向对象...
Agile Web Development with Rails 4th(正式版).pdf
### Agile Web Development with Rails 第四版 #### 书籍概述与价值 《Agile Web Development with Rails》第四版是一本经典的Rails开发指南,旨在为开发者提供一套全面、实用且高效的敏捷开发方法论。本书由Sam ...