Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

merge from github

  • Loading branch information...
commit 5658d3a177355ba8b41d881a5a5c6e7e4b900ee0 2 parents 95e71dc + 8d5d7d8
@Tassandar authored
View
1,506 rails-tutorial-chapter1.markdown
751 additions, 755 deletions not shown
View
1,508 rails-tutorial-chapter2.markdown
@@ -1,753 +1,755 @@
-翻译 [ruby on rails Tutorial](http://ruby.railstutorial.org/chapters/a-demo-app#top),原作者 [Michael Hartl](http://michaelhartl.com/) .
-
-
-###第二章
-
-##示例程序
-
-在这一章里面,我们将会开发一个演示性的程序来展示 Rails 的强大。目的是为了能够从比较高的层面上理解如何通过 Ruby on Rails 的 scaffold generators 功能进行 rails 敏捷开发。在上一章的推荐书目中,有的书运用了相反的方法,通过一点点的增加新功能开发一个完整的应用程序,同时解释相关的概念。但是在我们的这个实例程序中,脚手架(scaffold)功能是无可替代的,它将迅速而全面的通过 URLs 来让我们了解rails的组成结构和 REST 特性。
-
-这个示例程序完成了用户和与用户关联的微博(像是超级简化的twitter)。由于这个程序用到的功能隐藏了许多细节,所以这里很多步骤可能会看起来像是魔法,但是别担心,我们会从第三章开始从底层开发一个类似的应用,保证会让你能学到rails最重要的特性的。所以现在,就请乖乖的从这里开始学习Rails,制作我们这章的, 超酷脚手架驱动(superficial, scaffold-driven )应用吧。
-
-###2.1 计划整个应用程序
-
-在这里我们先跳出我们的示例程序,和1.2.3节中一样,我们要用rails命令来建立一个rails的基本框架:
-
- $ cd ~/rails_projects
- $ rails new demo_app
- $ cd demo_app
-
-然后如同 2.1节,我们用文本编辑器来更改Gemfile:
-
- source 'http://rubygems.org'
-
- gem 'rails', '3.0.11'
- gem 'sqlite3', '1.3.3'
-
-我们接着安装被包括到Gemfile中的 bundle
-
- $ bundle install
-
-最后我们新建一个Git仓库并做一次确认
-
- $ git init
- $ git add .
- $ git commit -m "Initial commit"
-
-![Creating a demo app repository at GitHub. ](http://ruby.railstutorial.org/images/figures/create_demo_repo.png)
-
- $ git remote add origin git@github.com:<username>/demo_app.git
- $ git push origin master
-
-现在我们就已经做好了准备工作了,对于建立一个网络应用程序通常我们会先建立一个数据库模型来展现出这个应用的数据结构。对于我们来说,这个实例程序只有简单的一层关系:每个用户拥有许多微博。所以我们会先建立用户模型,然后为用户模型添加微博。
-<!--more-->
-####2.1.1 用户模型
-
-user不用的结构对应着在页面上会有不同的表格,我们用最简单的结构来创建User model,它有一个唯一的int类型的主键,id,和一个公共可见的名字,string类型,和一个email地址,可以看做用户的第二用户名。所以,user的数据模型如下图2.2所示,
-
-![user model](http://dl.iteye.com/upload/attachment/367717/04b466eb-0d36-36ba-84b5-96c28ee04ac8.png)
-
-图2.2
-
-我们将在6.1.1节中学到,上表中的Users标签,代表着在数据库中的一个users表,上表的属性就是它的字段。
-
-####2.1.2 微博模型
-
-
-micropost的数据模型比user的更简单,它只有一个id和一个string类型的content来代表发言的内容。有一个附加的关系,我们希望将micropost和特定的user联系起来,我们可以可以添加一个user_id来记录post的所有者,这样,micropost的最终结果如图2.3所示,
-
-![microposts model](http://dl.iteye.com/upload/attachment/367723/52b778a4-8e43-3074-b2c5-3d0738495adc.png)
-
-\ 图2.3
-
-我们可以在2.3.3节(更详细的在第11章)中找到user_id的属性如何可以让我们更简单的表达user和micropost之间一对多的关系。
-
-###2.2用户资源
-
-在这一节,我们将实现2.1.1节中User数据模型的网络接口。通过这个网络接口和模型的组合,使我们可以通过HTTP协议来实现对user资源的CRUD(添加,查询,更新,和删除)
-简介里面提到的,我们的User资源将会通过脚手架生成器(Scaffold generator)来产生。脚手架生成器是每一个Rails项目的标配;scaffold的参数是要产生的资源名称,在这里是User,后面可以的可选参数,可以使数据模型的属性和类型。
-
-``` bash
- $ rails generate scaffold User name:string email:string
- invoke active_record
- create db/migrate/20100615004000_create_users.rb
- create app/models/user.rb
- invoke test_unit
- create test/unit/user_test.rb
- create test/fixtures/users.yml
- route resources :users
- invoke scaffold_controller
- create app/controllers/users_controller.rb
- invoke erb
- create app/views/users
- create app/views/users/index.html.erb
- create app/views/users/edit.html.erb
- create app/views/users/show.html.erb
- create app/views/users/new.html.erb
- create app/views/users/_form.html.erb
- invoke test_unit
- create test/functional/users_controller_test.rb
- invoke helper
- create app/helpers/users_helper.rb
- invoke test_unit
- create test/unit/helpers/users_helper_test.rb
- invoke stylesheets
- create public/stylesheets/scaffold.css
-
-```
-
-命令后面跟上 name:string 和email:string,可以让我们在rails自己产生的页面表单中有这2个数据模型的属性。如图2.2,提示,在命令中没必要添加属性id,因为他会被rails自动创建。
-程序的第一步,我们应该使用rake运行数据库迁移,如下:
-
-``` bash
-
- $ rake db:migrate
- == CreateUsers: migrating ====================================================
- -- create_table(:users)
- -> 0.0017s
- == CreateUsers: migrated (0.0018s) ===========================================
-
-```
-就这样非常简单的更新了数据库,我们创建了一个新的users数据模型,我们将会在6.1.1节中学习数据库迁移migrations。
-(如果大家的数据库是空的,或者程序新建的话,先运行 rake db:create,他会创建开发环境和测试环境的数据库)
-之后我们可以通过命令 rails s(rails server的简写)来启动服务器,
-(该命令也可以带参数,可以设置启动的服务器,默认启动的是WEBrick,也可以设置启动的环境,默认是开发环境)
-
-``` bash
- $ rails s
- => Booting WEBrick
- => Rails 3.0.3 application starting on http://0.0.0.0:3000
- => Call with -d to detach
- => Ctrl-C to shutdown server
-```
-
-我们可以在 http://localhost:3000/上看到我们的演示程序。
-
-**Box 2.1**
->**Rake** :
->在Unix系统上,make工具在执行源代码上有着非常重要的作用,非常多的电脑黑客输下面的代码输到不用大脑了。。。(可以这样翻译吧。。。muscle memory)
-> $ ./configure && make && sudo make install
->通常这个使用与在unix(包括linux和Mac OS X)底下编译源码;
-
-rake可以说是ruby的make工具,他是用ruby写的类似make的语言或者说是工具;rake在rails里的运用非常广泛,特别是在开发有数据库支持的web程序中用于大量小任务的管理;
-rake db:migrate命令可能是最经常使用到的,但是这只是其中之一,你可以运行
- $ rake —T db
-的命令来查看rake命令中关于数据库的小任务;
- $ rake —T
-可以查看所有可用的任务;
-出现的列表可能让人觉得恶心,但是不要担心,现在你不必要知道列表中所有项(或者大部分)的意思,学完本书后,你会知道里面所有重要的任务项.
-
-####2.2.1 用户模块开发
-
-
-打开项目的根目录,http://localhost:3000/ 将会如图1.3(第一章的图。我挪过来了)所示的显示rails默认的根目录,
-
-![pic](http://dl.iteye.com/upload/attachment/367806/d7bba2bc-be01-3135-a5c6-441712dc19fb.png)
-
-\ 图1.3
-
-在生成User的资源的时候,我们也创建了很多的页面,用于操作这个用户;
-例如,用于列出所有用户的 “/users”页面,用于创建新用户的“/users/new”页面等,
-本节剩下的部分会用来快速的访问并解说这些页面,随着我们的进行,我们可以把页面和URL的关系列在下表中,
-
-<br>
-<table class="bbcode"><tbody><tr><td>URL</td><td> Action</td><td> Purpose</td></tr><tr><td>/users </td><td>index </td><td>page to list all users</td></tr><tr><td>/users/1</td><td> show </td><td>page to show user with id</td><td> </td></tr><tr><td>/users/new</td><td> new&nbsp;&nbsp;&nbsp;&nbsp; </td><td>page to make a new user</td></tr><tr><td>/users/1/edit</td><td> edit&nbsp;&nbsp;&nbsp; </td><td>page to edit user with id </td></tr></tbody></table>
-
-<br>Table 2.1: 用户资源和URL之间的关系对照
-
-我们从列出所有用户的index 页面开始吧,和你想的一样,一开始是什么都没有,如图2.4所示,
-
-![pict](http://dl.iteye.com/upload/attachment/368100/9187441f-a73a-367b-b2e6-e1ba2b5cd785.png)
-
-\ 图2.4 初始状态下的index页面(/users).
-
-
-我们通过"users/new"页面来创建新的用户,如图2.5所示
-
-![pic](http://dl.iteye.com/upload/attachment/368103/e2c436e2-53d1-3518-a4e2-53c6a9c13506.png)
-
-\ 图 2.5: 创建用户页面 (/users/new).
-
-我们可以在页面中输入用户name和email的值,然后点击Create按钮。
-成功之后呢会跳向show页面,如图2.6所示,(绿色的欢迎信息是成功创建后flash的信息,我们将在8.3.3中学习它)
-
-![pic](http://dl.iteye.com/upload/attachment/368106/eb735daa-d41b-3ca0-ae7f-78a6efd77ad4.png)
-
-\ 图2.6,显示一个用户信息的页面(/users/1)
-
-
-注意此时的URL是 “/users/1”,你可能想到,那个1个就是代表图2.2中用户的id属性。
-在7.3节中,这个页面就会变成用户的详细信息页。
-我们通过访问edit页面来修改用户信息,如图2.7所示,我们修改信息后点击更新按钮。在演示程序中,我们可以修改用户信息,我们将在第六章中详细的介绍,这些用户的信息是被存储在数据库中的。我们将会把添加编辑用户的功能加入第10.1节的示范程序中。
-
-![picc](http://dl.iteye.com/upload/attachment/368170/2cce9343-7ec9-367f-8963-2a103139a9ff.png)
-
-\ 图2.7 用户编辑页面(/users/1/edit).
-
-![pic](http://dl.iteye.com/upload/attachment/368179/89b60b5b-537a-3ef9-a146-bb217c4916e8.png)
-
-\ 图2.8 用户更新成功页面.
-
-
-现在我们可以通过new页面填入和提交信息再创建一个用户;所以,在index页面中就会如下图2.9所示。在第10.3节中巍峨哦门将开发一个更精致index页面来列出所有用户。
-
-![pic](http://dl.iteye.com/upload/attachment/368179/89b60b5b-537a-3ef9-a146-bb217c4916e8.png)
-
-\ 图2.9 加入了第二个用户的index页面(/users).
-
-在演示了如何创建,显示,修改单个用户之后,我们将要看看如何删掉他们。你必须验证下图中用于删除第二个用户的链接是正确的。如果它不能使用,首先应该保证你的浏览有把javascript打开,Rails用JavaScript来发送删除用户的请求的。
-我们将会把添加删除用户的功能加入到第10.4节的示例程序。在一个管理用户的类中小心的使用它。
-![pic](http://dl.iteye.com/upload/attachment/368196/01cf1ae1-3a89-38e5-800b-a36db253baf0.png)
-
-\ 图2.30 删除一个用户
-
-
-####2.2.2 上节操作的MVC应用
-
-现在我们基本完成了用户资源,让我们用一个过程来讲述第1.2.6中提到的MVC模式,这个模式可以只是浏览器上普通的一次点击。例如访问user的index页面“/users”;
-
-![pic](http://dl.iteye.com/upload/attachment/368202/23d6b46a-2b50-3cda-8352-732936b18ccc.png)
-
-
-\ 图2.11,Rails中MVC的详细图解
-
-
-\ 上表中步骤对应:
-
-
-1.The browser issues a request for the /users URL. 浏览器发送请求/users
-2.Rails routes /users to the index action in the Users controller. Rails的路由组建分析它为对应users 控制器,index 的方法。
-3.The index action asks the User model to retrieve all users (User.all). index通过User.all方法请求用户模型查找所有的用户。
-4.The User model pulls all the users from the database. User模型从数据库提取出所有需要的用户。
-5.The User model returns the list of users to the controller. User模型返回用户列表给控制器。
-6.The controller captures the users in the @users variable, which is passed to the index view. 控制器将这些用户注入@users的类变量中。该变量将会被传到视图中使用。
-7.The view uses Embedded Ruby to render the page as HTML. 视图利用内嵌的ruby代码来产生HTML文件;
-8.The controller passes the HTML back to the browser.7 控制器将HTML传回浏览器
-
-我从浏览器(如IE)的地址栏出入URL或者点击一个链接开始发出一个请求,这个请求将会先会请求rails的“路由器router”,路由器将会基于URL选择目标控制器和ACTION(在BOX3.1中我将看到请求的方法。)。下表中的代码会为用户资源创建一个URL到控制器action的映射,这些代码会创建如前面表2.1所示的那样URL/action 对应关系。
-
-*Listing 2.2. Rails的映射Users 资源的路由.*
-
-
-``` ruby config/routes.rb
-
- DemoApp::Application.routes.draw do
- resources :users
- .
- .
- .
- end
-
-```
-
-在第2.2.1中的页面对应了User控制器中的各个action。控制器是由Rails的scaffold生成器生产的,结构如listing 2.3所示。
-
-提示, class UsersController \< ApplicationController 的写法是Ruby中类继承的写法。(我们将会在第2.3.4中简短的介绍继承,在第4.4中详细介绍。)
-
-####Listing 2.3. Users控制器示意图。
-
-
-
-``` ruby app/controllers/users_controller.rb
- class UsersController < ApplicationController
-
- def index
- .
- .
- .
- end
-
- def show
- .
- .
- .
- end
-
- def new
- .
- .
- .
- end
-
- def create
- .
- .
- .
- end
-
- def edit
- .
- .
- .
- end
-
- def update
- .
- .
- .
- end
-
- def destroy
- .
- .
- .
- end
- end
-```
-###2.3Microposts资源
-
-在生成和探索了Users资源之后,让我们转过来看看另一个相关资源——Microposts。
-在这一节中,我建议对比一下2个资源中相似的元素。你会看到2个资源之间会有很多地方都是相同的。Rails程序的RESTful结构是这种重复结构最好的实现方式。的确,研究这种Users和Microposts资源早期的重复结构也是本章最初的动机。(我们将会明白写一个健壮的toy programe程序需要耗费相当多的精力、我将会在第11章再次见到microposts资源——其实我不想隔那么久。。。)。
-
-####2.3.1 Microposts初步探索
-
-
-和Users资源一样,我们先用Rails generate Scaffold创建Microposts资源的基本结构(Scaffold脚手架),如图2.3所示的那样,我们也创建了数据模型。
-
-``` bash
-
- $ rails generate scaffold Micropost content:string user_id:integer
- invoke active_record
- create db/migrate/20100615004429_create_microposts.rb
- create app/models/micropost.rb
- invoke test_unit
- create test/unit/micropost_test.rb
- create test/fixtures/microposts.yml
- route resources :microposts
- invoke scaffold_controller
- create app/controllers/microposts_controller.rb
- invoke erb
- create app/views/microposts
- create app/views/microposts/index.html.erb
- create app/views/microposts/edit.html.erb
- create app/views/microposts/show.html.erb
- create app/views/microposts/new.html.erb
- create app/views/microposts/_form.html.erb
- invoke test_unit
- create test/functional/microposts_controller_test.rb
- invoke helper
- create app/helpers/microposts_helper.rb
- invoke test_unit
- create test/unit/helpers/microposts_helper_test.rb
- invoke stylesheets
- identical public/stylesheets/scaffold.css
-
-```
-
-你可能注意到了,在这个控制器中已经有几个action存在。Index,show,new,和edit等几个action对应第2.2.1中提到的页面,但是同时还有附加的create,update和destroy三个方法,通常这三个方法是不会去产生页面(并不绝对),相反,他们的主要作用是去修改数据库中User的信息。如表2.2所示,这基本是一个控制器的所有action,表中还显示了,Rails的REST运用。从表中看,有的URL是重复的,例如,控制器的show和update方法对应URL:“/users/1”,不同之处只是两者之间响应的HTTP请求方式不同。我们将在第3.2.2中详细学习HTTP请求方式。
-
-<br><table class="bbcode"><tbody><tr><td>HTTP 请求方式</td><td> URL</td><td> Action</td><td> 目的</td></tr><tr><td>GET</td><td> /users </td><td>index </td><td>请求一个用于列出所有用户的页面</td></tr><tr><td>GET</td><td> /users/1 </td><td>show </td><td>请求显示id为1的用户的页面</td></tr><tr><td>GET</td><td> /users/new</td><td>new </td><td>请求创建用户的页面</td></tr><tr><td>POST</td><td> /users </td><td>create </td><td>根据前面表单中的信息,向数据库创建用户</td></tr><tr><td>GET</td><td> /users/1 </td><td>edit </td><td>请求编辑id为1的用户的页面</td></tr><tr><td>PUT</td><td> /users/1 </td><td>update </td><td>将更新的信息更新到数据库</td></tr><tr><td>DELETE</td><td> /users/1 </td><td>destroy </td><td>删除数据库中id为1的用户</td></tr></tbody></table>
-
-
-\ 表2.2 Listing 2.2 中提供的用户资源的RESTful架构的路由
-
->BOX 2.2
->**REpresentational State Transfer (REST)表述性状态转移**
->如果你阅读了很多关于Ruby on Rails的阅读材料,你就会发现有很多地方提到“REST”(表述性状态转移的简写)REST是一种开发分布式应用例如网络应用程序例如web程序的一种架构。
->REST原始的很抽象的,具体到Rails下的REST应用就是指大部分程序的组件(例如上文的users,microposts)都是可以视为资源,都是可以被创建,读取,更新和删除,这几>个动作就是关系数据库常说的CRUD操作和四个基本的HTTP请求方式:POST,GET,PUT和删除。(我们将在第3.2.2,特别是Box3.1更详细的学习);
-
-作为一个Rails运用程序的开发人员来说,RESTful的开发方式有助于知道写哪个控制器和哪个action,你可以使用资源的CRUD构造程序的简单结构。在上面的users,microposts中,只要他们是你权限范围内的资源,你都可以直接的CRUD。在12章中,我们将看到一个例子,REST原则允许我们自然方便地塑造一个微妙的问题,“following users”。
-
-检查user控制器和user模型之间的关系,让我们来看看精简版本的index 方法(action翻译成方法。)吧。如下代码2.4(listing 翻译成代码。前面的就不去改了)
-
-**代码2.4 演示程序中user简化版的index方法**
-
-``` ruby
-class UsersController < ApplicationController
- def index
- @users = User.all
- end
- .
- .
- .
-end
-```
-
-在index方法中有 @users = User.all,这是告诉User模型去数据库检索出所有的用户,并把值赋给@users变量(发音“at-users”),User模型的代码如下2.5所示。尽管他非常的简单,但是它却有着非常牛B的功能,因为它继承了那个东西(可见2.3.4节和4.4)。特别是,因为使用Rails的Actuve Record库,下面的代码已经可以接受User.all来返回所有的用户了。
-
-**代码2.5. 演示程序的user模型**
-
-``` ruby app/models/user.rb
- class User < ActiveRecord::Base
- end
-```
-
-一旦@users被定义(赋值)之后,控制器就可以条用视图(View),如代码2.6。以“@”符号开始的变量成为类变量,可以自动的在视图中调用,在这里,index.html.erb(代码2.6)中的游标将会遍历@users数组变量然后为每一项输出一串HTML代码。
-
-**代码2.6. 用户index的视图(现在你不明白没关系。)**
-
-
-``` ruby app/views/users/index.html.erb
- <h1>Listing users</h1>
-
- <table>
- <tr>
- <th>Name</th>
- <th>Email</th>
- <th></th>
- <th></th>
- <th></th>
- </tr>
-
- <% @users.each do |user| %>
- <tr>
- <td><%= user.name %></td>
- <td><%= user.email %></td>
- <td><%= link_to 'Show', user %></td>
- <td><%= link_to 'Edit', edit_user_path(user) %></td>
- <td><%= link_to 'Destroy', user, :confirm => 'Are you sure?',
- :method => :delete %></td>
- </tr>
- <% end %>
- </table>
-
- <br />
-
- <%= link_to 'New User', new_user_path %>
-```
-这个视图将会被转换成HTML然后传回给浏览器,显示给用户。
-
-####2.2.3 当前用户资源的缺陷
-
-
-初步了解了Rails生成用户资源的优势之后,我们也该知道,他目前存在着不少的缺陷;
-
-* 没有数据验证:模型接受一些非法的数据,例如空名字,不合法的email地址等。没有反馈
-* 没有认证:没有登录/退出的概念,这样我们就没办法阻止随便一个用户操作某些操作。
-* 没有测试:其实这不是非常准确,因为scaffolding会自己产生一些测试,但是生成的测试难看且死板,他们不会测试上面说的那2点或者其他用户自定义的一些需求。
- * 没有布局:没有一致的网站风格和导航。
-* 还没有正理解:其实你要是真的理解了scaffold的代码,你或许就不会来看这本书。
-
-###2.3 Microposts资源
-
-在生成和探索了Users资源之后,让我们转过来看看另一个相关资源——Microposts。
-在这一节中,我建议对比一下2个资源中相似的元素。你会看到2个资源之间会有很多地方都是相同的。Rails程序的RESTful结构是这种重复结构最好的实现方式。的确,研究这种Users和Microposts资源早期的重复结构也是本章最初的动机。(我们将会明白写一个不是toy programe的健壮程序需要耗费相当多的精力、我将会在第11章再次见到microposts资源——其实我不想隔那么久。。。)。
-
-####2.3.1 Microposts初步探索
-
-
-和Users资源一样,我们先用Rails generate Scaffold创建Microposts资源的基本结构(Scaffold脚手架),如图2.3所示的那样,我们也创建了数据模型。
-
-``` bash
- $ rails generate scaffold Micropost content:string user_id:integer
- invoke active_record
- create db/migrate/20100615004429_create_microposts.rb
- create app/models/micropost.rb
- invoke test_unit
- create test/unit/micropost_test.rb
- create test/fixtures/microposts.yml
- route resources :microposts
- invoke scaffold_controller
- create app/controllers/microposts_controller.rb
- invoke erb
- create app/views/microposts
- create app/views/microposts/index.html.erb
- create app/views/microposts/edit.html.erb
- create app/views/microposts/show.html.erb
- create app/views/microposts/new.html.erb
- create app/views/microposts/_form.html.erb
- invoke test_unit
- create test/functional/microposts_controller_test.rb
- invoke helper
- create app/helpers/microposts_helper.rb
- invoke test_unit
- create test/unit/helpers/microposts_helper_test.rb
- invoke stylesheets
- identical public/stylesheets/scaffold.css
-```
-
-如第2.2节,我们需要运行数据库迁移migration来更新数据库并添加新的数据模型。
-``` bash
- $ rake db:migrate
- == CreateMicroposts: migrating ===============================================
- -- create_table(:microposts)
- -> 0.0023s
- == CreateMicroposts: migrated (0.0026s) ======================================
-```
-
-我们已经如第2.2.1节创建Users那样创建了Microposts。你或许猜到了,Scaffold 生成器也为Microposts更新了Rails的routes文件。如代码2.7。 和Users一样, 代码:“resources:microposts”的路由规则映射了URL和对应的Microposts控制器方法。如表2.3所示。
-
-*代码2.7 新增了Microposts资源的Rails路由*
-
-``` ruby config/routes.rb
- DemoApp::Application.routes.draw do
- resources :microposts
- resources :users
- .
- .
- .
- end
-```
-
-<br><table class="bbcode"><tbody><tr><td>HTTP request</td><td> URL</td><td> Action</td><td> Purpose</td></tr><tr><td>GET</td><td> /microposts</td><td> index</td><td> page to list all microposts</td></tr><tr><td>GET</td><td> /microposts/1</td><td> show</td><td> page to show micropost with id 1</td></tr><tr><td>GET</td><td> /microposts/new</td><td> new</td><td> page to make a new micropost</td></tr><tr><td>POST</td><td> /microposts</td><td> create</td><td> create a new micropost</td></tr><tr><td>GET</td><td> /microposts/1/edit</td><td>edit</td><td> page to edit micropost with id 1</td></tr><tr><td>PUT</td><td> /microposts/1</td><td> update</td><td> update micropost with id 1</td></tr><tr><td>DELETE</td><td> /microposts/1</td><td> destroy</td><td> delete micropost with id 1</td></tr></tbody></table>
-
-
-
-*表2.3 代码2.7中,microposts资源提供的RESTful路由。*
-
-Microposts控制器示意代码如代码2.8所示。和代码2.3相比,除了用icropostsController替换掉UsersController之外基本一样,这是RESTful架构在2者只运用的体现。
-
-
-*代码2.8,Microposts的示意代码*
-
-``` ruby app/controllers/microposts_controller.rb
- class MicropostsController < ApplicationController
-
- def index
- .
- .
- .
- end
-
- def show
- .
- .
- .
- end
-
- def new
- .
- .
- .
- end
-
- def create
- .
- .
- .
- end
-
- def edit
- .
- .
- .
- end
-
- def update
- .
- .
- .
- end
-
- def destroy
- .
- .
- .
- end
- end
-```
-
-让我们在“/microposts/new”页面添加一些实际的microposts(微博),如图2.12
-
-![pic](http://dl.iteye.com/upload/attachment/369972/05fd9922-276e-39eb-992f-71eb189f1162.png)
-
-\ 图2.12 添加微博的页面(/microposts/new)
-
-就这样子,建立一两条微博,注意user_id为1是为了对应在2.2.1节中建立的第一个用户。结果如2.13图所示
-
-![pic](http://dl.iteye.com/upload/attachment/369978/cc2087d7-e57c-37d8-9aea-f923778d8d5f.png)
-
-\ 图2.13 Microposts的index页面(/microposts)
-
-####2.3.2 给微博真正的“微”
-
-
-任何敢叫微博的帖子要对得起他的称呼就要意味着要限制他的长度。要实现这个约束条件在Rails中是非常容易——使用模型验证(validations of rails)。我们可以使用length这个验证条件来限制微博的最大长度为140个字符(学习 Twitter)。你需要用你的IDE或者文本编辑器打开app/models/micropost.rb填入如代码2.9所示的代码(这个验证的使用是rails3的特性,如果你之前有使用Rails2.3.X版本,你可以对比一下“validates_length_of”的用法)。
-代码2.9 约束微博最大字符长度为140。
-
-``` ruby app/models/micropost.rb
- class Micropost < ActiveRecord::Base
- validates :content, :length => { :maximum => 140 }
- end
-```
-
-代码2.9看起来很神秘,不过不要紧,我们将在6.2节中学习更多的验证,但是如果我们回到New页面然后输入超过140个字符的微博就会发现他的影响已经出来了;Rails会渲染错误的信息并提示微博的内容过长(我们将在第8.2.3中学习更多的错误。)。
-
-![p](http://dl.iteye.com/upload/attachment/369988/7a511f79-f186-36d6-a3d7-73903ceeef16.png)
-
-图2.14:创建微博失败的错误信息
-
-####2.3.3 一个user可以有多条微博
-在两个不同的数据模型中创建关系是Rails最强大的功能之一。这里,用户模型中,每一个用户都可以多条的微博信息,我们可以如代码2.10和2.11那样更新User和Microposts模型的代码;
-
-**代码 2.10. 一个user可以有多条微博信息microposts**
-
-
-``` ruby app/models/user.rb
- class User < ActiveRecord::Base
- has_many :microposts
- end
-```
-
-**代码 2.11 每一条微博信息都是属于某一个用户的**
-
-``` ruby app/models/micropost.rb
- class Micropost < ActiveRecord::Base
- belongs_to :user
-
- validates :content, :length => { :maximum => 140 }
- end
-```
-
-我们可以想象以上的关系就如图2.15所示。因为microposts表中有user_id的字段,Rails(使用Active Record)可以猜测出微博信息microposts和用户的关系
-
-![pic](http://dl.iteye.com/upload/attachment/369992/c4c778f3-2b27-30c9-94e5-9cc21b404060.png)
-
-**图 2.15: 微博信息microposts和用户users之间的关系**
-
-在第11,12章中,我们将用这2者间的关系来显示所有用户的microposts信息和构建一个和Twitter类似的微博提要(microposts feed)。现在我们通过Rails的控制台(console)来验证user和microposts之间的关系,控制台是一个非常有用的工,他可以使我们和Rails程序之间进行交互。我们先从命令行输入“rails console”进入控制台,然后使用User.first从数据库检索出第一个user(将 结果赋值给变量first_user);
-
-``` bash
- $ rails console
- >> first_user = User.first
- => #<User id: 1, name: "Michael Hartl", email: "michael@example.org",
- created_at: "2010-04-03 02:01:31", updated_at: "2010-04-03 02:01:31">
- >> first_user.microposts
- => [#<Micropost id: 1, content: "First micropost!", user_id: 1, created_at:
- "2010-04-03 02:37:37", updated_at: "2010-04-03 02:37:37">, #<Micropost id: 2,
- content: "Second micropost", user_id: 1, created_at: "2010-04-03 02:38:54",
- updated_at: "2010-04-03 02:38:54">]
-```
-
-这样我们通过first_name.microposts获得了用户的微博信息:运行这个代码,Active Record 会自动返回所有user_id等于first_name的id(这里是1)。
-我们将在11,12章中学习ActiveRecord的更多关联结构。
-
-####2.3.4 继承的层次结构
-
-我们结束关于演示程序的讨论,我们花点时间,简短的介绍一下Rails中控制器类和模型类的继承问题。这个介绍只有在你有面向对象编程经验的时候才会有较多的意义。如过你还没学习OOP,大可以跳过这一节,特别是,你对类(在第4.4节中讨论)很不了解的时候,我建议在以后的时间跳回来看这一节。
-我们先从模型的继承结构开始。对比代码2.12和代码2.13,我们可以看到,User和Micropost两个模型都从ActiveRecord::Base类继承(通过尖括号“<”)。
-ActiveRecord::Base类是ActiveRecord提供的模型的基类。图2.16总结了这种关系;正式由于这种继承使我们的模型可以喝数据库交互,也可以将数据表的字段当成Ruby的属性对待,等等特性。
-
-**代码 2.12 继承的User类**
-
-``` ruby app/models/user.rb
- class User < ActiveRecord::Base
- .
- .
- .
- end
-```
-
-**代码 2.13 继承的Micropost类**
-
-``` ruby app/models/micropost.rb
- class Micropost < ActiveRecord::Base
- .
- .
- .
- end
-
-```
-
-![pic](http://dl.iteye.com/upload/attachment/370008/2119f47d-4fa9-3c59-9707-4a25863846b9.png)
-
-
-控制器继承的层次结构较复杂一点。对比代码2.14和代码2.15,我们可以看到两个控制器都从ApplicationController。从代码2.16中可以看到ApplicationController自己继承自ApplicationController::base;这个是Rails的Acton Pack 库提供给控制器的基类,类之间的关系如图2.17所示。
-
-
-**代码 2.14. UsersController继承自ApplicationController.**
-
-``` ruby app/controllers/users_controller.rb
- class UsersController < ApplicationController
- .
- .
- .
- end
-```
-
-
-**代码 2.15. MicropostsController 继承自ApplicationController.**
-
-``` ruby app/controllers/microposts_controller.rb
- class MicropostsController < ApplicationController
- .
- .
- .
- end
-```
-
-```ruby app/controllers/application_controller.rb
- class ApplicationController < ActionController::Base
- .
- .
- .
- end
-```
-
-![pic](http://dl.iteye.com/upload/attachment/370012/d53669cd-bc2a-3da3-91ad-6eb7e004518a.png)
-
-
-\ 图 2.17: Users和Microposts控制器的继承结构.
-
-就和模型的继承一样,因为最终都继承自 ActionController::Base ,Users和Microposts的控制都获得大量的功能,比如操作模型对象,过滤收到的请求和渲染HTML页面。因为所有的控制都继承自ApplicationController,所以所有定义在Application Controller 里面的规则都会被自动的运用到所有的方法(action)中去;例如在8.2.4节中我们将看到如何在Application controller中定义一个允许我们从所有的Rails 日志文件中过滤掉密码的规则,这样可以避免一些安全隐患。
-
-
-####2.3.5 部署演示程序
-我们完成了Microposts资源,现在正是我们把他push到GitHub库的时候;
-
-``` bash
- $ git add .
- $ git commit -a -m "Done with the demo app"
- $ git push
-```
-
-
-你也可以把演示程序部署到Heroku:
-
-``` bash
- $ heroku create
- $ git push heroku master
- $ heroku rake db:migrate
-```
-
-
-(如果上面的没有效果,你可以看看前面代码1.8,或许对你有帮助。)
-请注意这里在heroku运行数据库迁移的最后一行代码,这是只是在heroku上创建user/micropost的数据模型。如果你希望吧数据也上传,你可以使用 data up命令。前提是你有taps这个gem:
-
-``` bash
- $ [sudo] gem install taps
- $ heroku db:push
-```
-
-
-
-2.4 总结
-现在我们站在一个Rails 程序30000英尺远的地方观察他,这一章中按这个方法开发的演示程序有一些优势和一些主机缺点(不明白什么意思, a host of weaknesses。)
-
-优势
-
-* High-level overview of Rails 高水平的Rails概述
-
-* Introduction to MVC 介绍了MVC
-
-* First taste of the REST architecture 第一次尝试REST架构
-
-* Beginning data modeling 开始数据建模
-
-* A live, database-backed web application in production 制作了一个在线的数据库支持的Web程序
-
-
-弱点
-
-* No custom layout or styling 没有布局或者样式
-
-* No static pages (like “Home” or “About”) 没有静态页面,比如首页
-
-* No user passwords 用户没有密码
-
-* No user images 用户没有图片
-
-* No signing in 没有登录
-
-* No security 不安全
-
-* No automatic user/micropost association 没有自动关联user/micropost
-
-* No notion of “following” or “followed” 没有 “following” or “followed”的概念.
-
-* No micropost feed 没有微博提要
-
-* No test-driven development 没有测试驱动
-
-* No real understanding 还没弄明白
-
+翻译 [ruby on rails Tutorial](http://ruby.railstutorial.org/chapters/a-demo-app#top),原作者 [Michael Hartl](http://michaelhartl.com/) .
+
+
+###第二章
+
+##示例程序
+
+在这一章里面,我们将会开发一个演示性的程序来展示 Rails 的强大。目的是为了能够从比较高的层面上理解如何通过 Ruby on Rails 的 scaffold generators 功能进行 rails 敏捷开发。在上一章的推荐书目中,有的书运用了相反的方法,通过一点点的增加新功能开发一个完整的应用程序,同时解释相关的概念。但是在我们的这个实例程序中,脚手架(scaffold)功能是无可替代的,它将迅速而全面的通过 URLs 来让我们了解rails的组成结构和 REST 特性。
+
+这个示例程序完成了用户和与用户关联的微博(像是超级简化的twitter)。由于这个程序用到的功能隐藏了许多细节,所以这里很多步骤可能会看起来像是魔法,但是别担心,我们会从第三章开始从底层开发一个类似的应用,保证会让你能学到rails最重要的特性的。所以现在,就请乖乖的从这里开始学习Rails,制作我们这章的, 超酷脚手架驱动(superficial, scaffold-driven )应用吧。
+
+###2.1 计划整个应用程序
+
+在这里我们先跳出我们的示例程序,和1.2.3节中一样,我们要用rails命令来建立一个rails的基本框架:
+
+ $ cd ~/rails_projects
+ $ rails new demo_app
+ $ cd demo_app
+
+然后如同 2.1节,我们用文本编辑器来更改Gemfile:
+
+ source 'http://rubygems.org'
+
+ gem 'rails', '3.0.11'
+ gem 'sqlite3', '1.3.3'
+
+我们接着安装被包括到Gemfile中的 bundle
+
+ $ bundle install
+
+最后我们新建一个Git仓库并做一次确认
+
+ $ git init
+ $ git add .
+ $ git commit -m "Initial commit"
+
+![Creating a demo app repository at GitHub. ](http://ruby.railstutorial.org/images/figures/create_demo_repo.png)
+
+ $ git remote add origin git@github.com:<username>/demo_app.git
+ $ git push origin master
+
+现在我们就已经做好了准备工作了,对于建立一个网络应用程序通常我们会先建立一个数据库模型来展现出这个应用的数据结构。对于我们来说,这个实例程序只有简单的一层关系:每个用户拥有许多微博。所以我们会先建立用户模型,然后为用户模型添加微博。
+<!--more-->
+####2.1.1 用户模型
+
+user不用的结构对应着在页面上会有不同的表格,我们用最简单的结构来创建User model,它有一个唯一的int类型的主键,id,和一个公共可见的名字,string类型,和一个email地址,可以看做用户的第二用户名。所以,user的数据模型如下图2.2所示,
+
+![user model](http://dl.iteye.com/upload/attachment/367717/04b466eb-0d36-36ba-84b5-96c28ee04ac8.png)
+
+图2.2
+
+我们将在6.1.1节中学到,上表中的Users标签,代表着在数据库中的一个users表,上表的属性就是它的字段。
+
+####2.1.2 微博模型
+
+
+micropost的数据模型比user的更简单,它只有一个id和一个string类型的content来代表发言的内容。有一个附加的关系,我们希望将micropost和特定的user联系起来,我们可以可以添加一个user_id来记录post的所有者,这样,micropost的最终结果如图2.3所示,
+
+![microposts model](http://dl.iteye.com/upload/attachment/367723/52b778a4-8e43-3074-b2c5-3d0738495adc.png)
+
+\ 图2.3
+
+我们可以在2.3.3节(更详细的在第11章)中找到user_id的属性如何可以让我们更简单的表达user和micropost之间一对多的关系。
+
+###2.2用户资源
+
+在这一节,我们将实现2.1.1节中User数据模型的网络接口。通过这个网络接口和模型的组合,使我们可以通过HTTP协议来实现对user资源的CRUD(添加,查询,更新,和删除)
+简介里面提到的,我们的User资源将会通过脚手架生成器(Scaffold generator)来产生。脚手架生成器是每一个Rails项目的标配;scaffold的参数是要产生的资源名称,在这里是User,后面可以的可选参数,可以使数据模型的属性和类型。
+
+``` bash
+ $ rails generate scaffold User name:string email:string
+ invoke active_record
+ create db/migrate/20100615004000_create_users.rb
+ create app/models/user.rb
+ invoke test_unit
+ create test/unit/user_test.rb
+ create test/fixtures/users.yml
+ route resources :users
+ invoke scaffold_controller
+ create app/controllers/users_controller.rb
+ invoke erb
+ create app/views/users
+ create app/views/users/index.html.erb
+ create app/views/users/edit.html.erb
+ create app/views/users/show.html.erb
+ create app/views/users/new.html.erb
+ create app/views/users/_form.html.erb
+ invoke test_unit
+ create test/functional/users_controller_test.rb
+ invoke helper
+ create app/helpers/users_helper.rb
+ invoke test_unit
+ create test/unit/helpers/users_helper_test.rb
+ invoke stylesheets
+ create public/stylesheets/scaffold.css
+
+```
+
+命令后面跟上 name:string 和email:string,可以让我们在rails自己产生的页面表单中有这2个数据模型的属性。如图2.2,提示,在命令中没必要添加属性id,因为他会被rails自动创建。
+程序的第一步,我们应该使用rake运行数据库迁移,如下:
+
+``` bash
+
+ $ rake db:migrate
+ == CreateUsers: migrating ====================================================
+ -- create_table(:users)
+ -> 0.0017s
+ == CreateUsers: migrated (0.0018s) ===========================================
+
+```
+就这样非常简单的更新了数据库,我们创建了一个新的users数据模型,我们将会在6.1.1节中学习数据库迁移migrations。
+(如果大家的数据库是空的,或者程序新建的话,先运行 rake db:create,他会创建开发环境和测试环境的数据库)
+之后我们可以通过命令 rails s(rails server的简写)来启动服务器,
+(该命令也可以带参数,可以设置启动的服务器,默认启动的是WEBrick,也可以设置启动的环境,默认是开发环境)
+
+``` bash
+ $ rails s
+ => Booting WEBrick
+ => Rails 3.0.3 application starting on http://0.0.0.0:3000
+ => Call with -d to detach
+ => Ctrl-C to shutdown server
+```
+
+我们可以在 http://localhost:3000/上看到我们的演示程序。
+
+**Box 2.1**
+>**Rake** :
+>在Unix系统上,make工具在执行源代码上有着非常重要的作用,非常多的电脑黑客输下面的代码输到不用大脑了。。。(可以这样翻译吧。。。muscle memory)
+> $ ./configure && make && sudo make install
+>通常这个使用与在unix(包括linux和Mac OS X)底下编译源码;
+
+rake可以说是ruby的make工具,他是用ruby写的类似make的语言或者说是工具;rake在rails里的运用非常广泛,特别是在开发有数据库支持的web程序中用于大量小任务的管理;
+rake db:migrate命令可能是最经常使用到的,但是这只是其中之一,你可以运行
+ $ rake —T db
+的命令来查看rake命令中关于数据库的小任务;
+ $ rake —T
+可以查看所有可用的任务;
+出现的列表可能让人觉得恶心,但是不要担心,现在你不必要知道列表中所有项(或者大部分)的意思,学完本书后,你会知道里面所有重要的任务项.
+
+####2.2.1 用户模块开发
+
+
+打开项目的根目录,http://localhost:3000/ 将会如图1.3(第一章的图。我挪过来了)所示的显示rails默认的根目录,
+
+![pic](http://dl.iteye.com/upload/attachment/367806/d7bba2bc-be01-3135-a5c6-441712dc19fb.png)
+
+\ 图1.3
+
+在生成User的资源的时候,我们也创建了很多的页面,用于操作这个用户;
+例如,用于列出所有用户的 “/users”页面,用于创建新用户的“/users/new”页面等,
+本节剩下的部分会用来快速的访问并解说这些页面,随着我们的进行,我们可以把页面和URL的关系列在下表中,
+
+<br>
+<table class="bbcode"><tbody><tr><td>URL</td><td> Action</td><td> Purpose</td></tr><tr><td>/users </td><td>index </td><td>page to list all users</td></tr><tr><td>/users/1</td><td> show </td><td>page to show user with id</td><td> </td></tr><tr><td>/users/new</td><td> new&nbsp;&nbsp;&nbsp;&nbsp; </td><td>page to make a new user</td></tr><tr><td>/users/1/edit</td><td> edit&nbsp;&nbsp;&nbsp; </td><td>page to edit user with id </td></tr></tbody></table>
+
+<br>Table 2.1: 用户资源和URL之间的关系对照
+
+我们从列出所有用户的index 页面开始吧,和你想的一样,一开始是什么都没有,如图2.4所示,
+
+![pict](http://dl.iteye.com/upload/attachment/368100/9187441f-a73a-367b-b2e6-e1ba2b5cd785.png)
+
+\ 图2.4 初始状态下的index页面(/users).
+
+
+我们通过"users/new"页面来创建新的用户,如图2.5所示
+
+![pic](http://dl.iteye.com/upload/attachment/368103/e2c436e2-53d1-3518-a4e2-53c6a9c13506.png)
+
+\ 图 2.5: 创建用户页面 (/users/new).
+
+我们可以在页面中输入用户name和email的值,然后点击Create按钮。
+成功之后呢会跳向show页面,如图2.6所示,(绿色的欢迎信息是成功创建后flash的信息,我们将在8.3.3中学习它)
+
+![pic](http://dl.iteye.com/upload/attachment/368106/eb735daa-d41b-3ca0-ae7f-78a6efd77ad4.png)
+
+\ 图2.6,显示一个用户信息的页面(/users/1)
+
+
+注意此时的URL是 “/users/1”,你可能想到,那个1个就是代表图2.2中用户的id属性。
+在7.3节中,这个页面就会变成用户的详细信息页。
+我们通过访问edit页面来修改用户信息,如图2.7所示,我们修改信息后点击更新按钮。在演示程序中,我们可以修改用户信息,我们将在第六章中详细的介绍,这些用户的信息是被存储在数据库中的。我们将会把添加编辑用户的功能加入第10.1节的示范程序中。
+
+![picc](http://dl.iteye.com/upload/attachment/368170/2cce9343-7ec9-367f-8963-2a103139a9ff.png)
+
+\ 图2.7 用户编辑页面(/users/1/edit).
+
+![pic](http://dl.iteye.com/upload/attachment/368179/89b60b5b-537a-3ef9-a146-bb217c4916e8.png)
+
+\ 图2.8 用户更新成功页面.
+
+
+现在我们可以通过new页面填入和提交信息再创建一个用户;所以,在index页面中就会如下图2.9所示。在第10.3节中巍峨哦门将开发一个更精致index页面来列出所有用户。
+
+![pic](http://dl.iteye.com/upload/attachment/368179/89b60b5b-537a-3ef9-a146-bb217c4916e8.png)
+
+\ 图2.9 加入了第二个用户的index页面(/users).
+
+在演示了如何创建,显示,修改单个用户之后,我们将要看看如何删掉他们。你必须验证下图中用于删除第二个用户的链接是正确的。如果它不能使用,首先应该保证你的浏览有把javascript打开,Rails用JavaScript来发送删除用户的请求的。
+我们将会把添加删除用户的功能加入到第10.4节的示例程序。在一个管理用户的类中小心的使用它。
+![pic](http://dl.iteye.com/upload/attachment/368196/01cf1ae1-3a89-38e5-800b-a36db253baf0.png)
+
+\ 图2.30 删除一个用户
+
+
+####2.2.2 上节操作的MVC应用
+
+现在我们基本完成了用户资源,让我们用一个过程来讲述第1.2.6中提到的MVC模式,这个模式可以只是浏览器上普通的一次点击。例如访问user的index页面“/users”;
+
+![pic](http://dl.iteye.com/upload/attachment/368202/23d6b46a-2b50-3cda-8352-732936b18ccc.png)
+
+
+\ 图2.11,Rails中MVC的详细图解
+
+
+\ 上表中步骤对应:
+
+
+1.The browser issues a request for the /users URL. 浏览器发送请求/users
+2.Rails routes /users to the index action in the Users controller. Rails的路由组建分析它为对应users 控制器,index 的方法。
+3.The index action asks the User model to retrieve all users (User.all). index通过User.all方法请求用户模型查找所有的用户。
+4.The User model pulls all the users from the database. User模型从数据库提取出所有需要的用户。
+5.The User model returns the list of users to the controller. User模型返回用户列表给控制器。
+6.The controller captures the users in the @users variable, which is passed to the index view. 控制器将这些用户注入@users的类变量中。该变量将会被传到视图中使用。
+7.The view uses Embedded Ruby to render the page as HTML. 视图利用内嵌的ruby代码来产生HTML文件;
+8.The controller passes the HTML back to the browser.7 控制器将HTML传回浏览器
+
+我从浏览器(如IE)的地址栏出入URL或者点击一个链接开始发出一个请求,这个请求将会先会请求rails的“路由器router”,路由器将会基于URL选择目标控制器和ACTION(在BOX3.1中我将看到请求的方法。)。下表中的代码会为用户资源创建一个URL到控制器action的映射,这些代码会创建如前面表2.1所示的那样URL/action 对应关系。
+
+*Listing 2.2. Rails的映射Users 资源的路由.*
+
+
+``` ruby config/routes.rb
+
+ DemoApp::Application.routes.draw do
+ resources :users
+ .
+ .
+ .
+ end
+
+```
+
+在第2.2.1中的页面对应了User控制器中的各个action。控制器是由Rails的scaffold生成器生产的,结构如listing 2.3所示。
+
+提示, class UsersController \< ApplicationController 的写法是Ruby中类继承的写法。(我们将会在第2.3.4中简短的介绍继承,在第4.4中详细介绍。)
+
+####Listing 2.3. Users控制器示意图。
+
+
+
+``` ruby app/controllers/users_controller.rb
+ class UsersController < ApplicationController
+
+ def index
+ .
+ .
+ .
+ end
+
+ def show
+ .
+ .
+ .
+ end
+
+ def new
+ .
+ .
+ .
+ end
+
+ def create
+ .
+ .
+ .
+ end
+
+ def edit
+ .
+ .
+ .
+ end
+
+ def update
+ .
+ .
+ .
+ end
+
+ def destroy
+ .
+ .
+ .
+ end
+ end
+```
+###2.3Microposts资源
+
+在生成和探索了Users资源之后,让我们转过来看看另一个相关资源——Microposts。
+在这一节中,我建议对比一下2个资源中相似的元素。你会看到2个资源之间会有很多地方都是相同的。Rails程序的RESTful结构是这种重复结构最好的实现方式。的确,研究这种Users和Microposts资源早期的重复结构也是本章最初的动机。(我们将会明白写一个健壮的toy programe程序需要耗费相当多的精力、我将会在第11章再次见到microposts资源——其实我不想隔那么久。。。)。
+
+####2.3.1 Microposts初步探索
+
+
+和Users资源一样,我们先用Rails generate Scaffold创建Microposts资源的基本结构(Scaffold脚手架),如图2.3所示的那样,我们也创建了数据模型。
+
+``` bash
+
+ $ rails generate scaffold Micropost content:string user_id:integer
+ invoke active_record
+ create db/migrate/20100615004429_create_microposts.rb
+ create app/models/micropost.rb
+ invoke test_unit
+ create test/unit/micropost_test.rb
+ create test/fixtures/microposts.yml
+ route resources :microposts
+ invoke scaffold_controller
+ create app/controllers/microposts_controller.rb
+ invoke erb
+ create app/views/microposts
+ create app/views/microposts/index.html.erb
+ create app/views/microposts/edit.html.erb
+ create app/views/microposts/show.html.erb
+ create app/views/microposts/new.html.erb
+ create app/views/microposts/_form.html.erb
+ invoke test_unit
+ create test/functional/microposts_controller_test.rb
+ invoke helper
+ create app/helpers/microposts_helper.rb
+ invoke test_unit
+ create test/unit/helpers/microposts_helper_test.rb
+ invoke stylesheets
+ identical public/stylesheets/scaffold.css
+
+```
+
+你可能注意到了,在这个控制器中已经有几个action存在。Index,show,new,和edit等几个action对应第2.2.1中提到的页面,但是同时还有附加的create,update和destroy三个方法,通常这三个方法是不会去产生页面(并不绝对),相反,他们的主要作用是去修改数据库中User的信息。如表2.2所示,这基本是一个控制器的所有action,表中还显示了,Rails的REST运用。从表中看,有的URL是重复的,例如,控制器的show和update方法对应URL:“/users/1”,不同之处只是两者之间响应的HTTP请求方式不同。我们将在第3.2.2中详细学习HTTP请求方式。
+
+<br><table class="bbcode"><tbody><tr><td>HTTP 请求方式</td><td> URL</td><td> Action</td><td> 目的</td></tr><tr><td>GET</td><td> /users </td><td>index </td><td>请求一个用于列出所有用户的页面</td></tr><tr><td>GET</td><td> /users/1 </td><td>show </td><td>请求显示id为1的用户的页面</td></tr><tr><td>GET</td><td> /users/new</td><td>new </td><td>请求创建用户的页面</td></tr><tr><td>POST</td><td> /users </td><td>create </td><td>根据前面表单中的信息,向数据库创建用户</td></tr><tr><td>GET</td><td> /users/1 </td><td>edit </td><td>请求编辑id为1的用户的页面</td></tr><tr><td>PUT</td><td> /users/1 </td><td>update </td><td>将更新的信息更新到数据库</td></tr><tr><td>DELETE</td><td> /users/1 </td><td>destroy </td><td>删除数据库中id为1的用户</td></tr></tbody></table>
+
+
+\ 表2.2 Listing 2.2 中提供的用户资源的RESTful架构的路由
+
+>BOX 2.2
+>**REpresentational State Transfer (REST)表述性状态转移**
+>如果你阅读了很多关于Ruby on Rails的阅读材料,你就会发现有很多地方提到“REST”(表述性状态转移的简写)REST是一种开发分布式应用例如网络应用程序例如web程序的一种架构。
+>REST原始的很抽象的,具体到Rails下的REST应用就是指大部分程序的组件(例如上文的users,microposts)都是可以视为资源,都是可以被创建,读取,更新和删除,这几>个动作就是关系数据库常说的CRUD操作和四个基本的HTTP请求方式:POST,GET,PUT和删除。(我们将在第3.2.2,特别是Box3.1更详细的学习);
+
+作为一个Rails运用程序的开发人员来说,RESTful的开发方式有助于知道写哪个控制器和哪个action,你可以使用资源的CRUD构造程序的简单结构。在上面的users,microposts中,只要他们是你权限范围内的资源,你都可以直接的CRUD。在12章中,我们将看到一个例子,REST原则允许我们自然方便地塑造一个微妙的问题,“following users”。
+
+检查user控制器和user模型之间的关系,让我们来看看精简版本的index 方法(action翻译成方法。)吧。如下代码2.4(listing 翻译成代码。前面的就不去改了)
+
+**代码2.4 演示程序中user简化版的index方法**
+
+``` ruby
+class UsersController < ApplicationController
+ def index
+ @users = User.all
+ end
+ .
+ .
+ .
+end
+```
+
+在index方法中有 @users = User.all,这是告诉User模型去数据库检索出所有的用户,并把值赋给@users变量(发音“at-users”),User模型的代码如下2.5所示。尽管他非常的简单,但是它却有着非常牛B的功能,因为它继承了那个东西(可见2.3.4节和4.4)。特别是,因为使用Rails的Actuve Record库,下面的代码已经可以接受User.all来返回所有的用户了。
+
+**代码2.5. 演示程序的user模型**
+
+``` ruby app/models/user.rb
+ class User < ActiveRecord::Base
+ end
+```
+
+一旦@users被定义(赋值)之后,控制器就可以条用视图(View),如代码2.6。以“@”符号开始的变量成为类变量,可以自动的在视图中调用,在这里,index.html.erb(代码2.6)中的游标将会遍历@users数组变量然后为每一项输出一串HTML代码。
+
+**代码2.6. 用户index的视图(现在你不明白没关系。)**
+
+
+``` ruby app/views/users/index.html.erb
+ <h1>Listing users</h1>
+
+ <table>
+ <tr>
+ <th>Name</th>
+ <th>Email</th>
+ <th></th>
+ <th></th>
+ <th></th>
+ </tr>
+
+ <% @users.each do |user| %>
+ <tr>
+ <td><%= user.name %></td>
+ <td><%= user.email %></td>
+ <td><%= link_to 'Show', user %></td>
+ <td><%= link_to 'Edit', edit_user_path(user) %></td>
+ <td><%= link_to 'Destroy', user, :confirm => 'Are you sure?',
+ :method => :delete %></td>
+ </tr>
+ <% end %>
+ </table>
+
+ <br />
+
+ <%= link_to 'New User', new_user_path %>
+```
+这个视图将会被转换成HTML然后传回给浏览器,显示给用户。
+
+####2.2.3 当前用户资源的缺陷
+
+
+初步了解了Rails生成用户资源的优势之后,我们也该知道,他目前存在着不少的缺陷;
+
+* 没有数据验证:模型接受一些非法的数据,例如空名字,不合法的email地址等。没有反馈
+* 没有认证:没有登录/退出的概念,这样我们就没办法阻止随便一个用户操作某些操作。
+* 没有测试:其实这不是非常准确,因为scaffolding会自己产生一些测试,但是生成的测试难看且死板,他们不会测试上面说的那2点或者其他用户自定义的一些需求。
+ * 没有布局:没有一致的网站风格和导航。
+* 还没有正理解:其实你要是真的理解了scaffold的代码,你或许就不会来看这本书。
+
+###2.3 Microposts资源
+
+在生成和探索了Users资源之后,让我们转过来看看另一个相关资源——Microposts。
+在这一节中,我建议对比一下2个资源中相似的元素。你会看到2个资源之间会有很多地方都是相同的。Rails程序的RESTful结构是这种重复结构最好的实现方式。的确,研究这种Users和Microposts资源早期的重复结构也是本章最初的动机。(我们将会明白写一个不是toy programe的健壮程序需要耗费相当多的精力、我将会在第11章再次见到microposts资源——其实我不想隔那么久。。。)。
+
+####2.3.1 Microposts初步探索
+
+
+和Users资源一样,我们先用Rails generate Scaffold创建Microposts资源的基本结构(Scaffold脚手架),如图2.3所示的那样,我们也创建了数据模型。
+
+``` bash
+ $ rails generate scaffold Micropost content:string user_id:integer
+ invoke active_record
+ create db/migrate/20100615004429_create_microposts.rb
+ create app/models/micropost.rb
+ invoke test_unit
+ create test/unit/micropost_test.rb
+ create test/fixtures/microposts.yml
+ route resources :microposts
+ invoke scaffold_controller
+ create app/controllers/microposts_controller.rb
+ invoke erb
+ create app/views/microposts
+ create app/views/microposts/index.html.erb
+ create app/views/microposts/edit.html.erb
+ create app/views/microposts/show.html.erb
+ create app/views/microposts/new.html.erb
+ create app/views/microposts/_form.html.erb
+ invoke test_unit
+ create test/functional/microposts_controller_test.rb
+ invoke helper
+ create app/helpers/microposts_helper.rb
+ invoke test_unit
+ create test/unit/helpers/microposts_helper_test.rb
+ invoke stylesheets
+ identical public/stylesheets/scaffold.css
+```
+
+如第2.2节,我们需要运行数据库迁移migration来更新数据库并添加新的数据模型。
+``` bash
+ $ rake db:migrate
+ == CreateMicroposts: migrating ===============================================
+ -- create_table(:microposts)
+ -> 0.0023s
+ == CreateMicroposts: migrated (0.0026s) ======================================
+```
+
+我们已经如第2.2.1节创建Users那样创建了Microposts。你或许猜到了,Scaffold 生成器也为Microposts更新了Rails的routes文件。如代码2.7。 和Users一样, 代码:“resources:microposts”的路由规则映射了URL和对应的Microposts控制器方法。如表2.3所示。
+
+*代码2.7 新增了Microposts资源的Rails路由*
+
+``` ruby config/routes.rb
+ DemoApp::Application.routes.draw do
+ resources :microposts
+ resources :users
+ .
+ .
+ .
+ end
+```
+
+<br><table class="bbcode"><tbody><tr><td>HTTP request</td><td> URL</td><td> Action</td><td> Purpose</td></tr><tr><td>GET</td><td> /microposts</td><td> index</td><td> page to list all microposts</td></tr><tr><td>GET</td><td> /microposts/1</td><td> show</td><td> page to show micropost with id 1</td></tr><tr><td>GET</td><td> /microposts/new</td><td> new</td><td> page to make a new micropost</td></tr><tr><td>POST</td><td> /microposts</td><td> create</td><td> create a new micropost</td></tr><tr><td>GET</td><td> /microposts/1/edit</td><td>edit</td><td> page to edit micropost with id 1</td></tr><tr><td>PUT</td><td> /microposts/1</td><td> update</td><td> update micropost with id 1</td></tr><tr><td>DELETE</td><td> /microposts/1</td><td> destroy</td><td> delete micropost with id 1</td></tr></tbody></table>
+
+
+
+*表2.3 代码2.7中,microposts资源提供的RESTful路由。*
+
+Microposts控制器示意代码如代码2.8所示。和代码2.3相比,除了用icropostsController替换掉UsersController之外基本一样,这是RESTful架构在2者只运用的体现。
+
+
+*代码2.8,Microposts的示意代码*
+
+``` ruby app/controllers/microposts_controller.rb
+ class MicropostsController < ApplicationController
+
+ def index
+ .
+ .
+ .
+ end
+
+ def show
+ .
+ .
+ .
+ end
+
+ def new
+ .
+ .
+ .
+ end
+
+ def create
+ .
+ .
+ .
+ end
+
+ def edit
+ .
+ .
+ .
+ end
+
+ def update
+ .
+ .
+ .
+ end
+
+ def destroy
+ .
+ .
+ .
+ end
+ end
+```
+
+让我们在“/microposts/new”页面添加一些实际的microposts(微博),如图2.12
+
+![pic](http://dl.iteye.com/upload/attachment/369972/05fd9922-276e-39eb-992f-71eb189f1162.png)
+
+\ 图2.12 添加微博的页面(/microposts/new)
+
+就这样子,建立一两条微博,注意user_id为1是为了对应在2.2.1节中建立的第一个用户。结果如2.13图所示
+
+![pic](http://dl.iteye.com/upload/attachment/369978/cc2087d7-e57c-37d8-9aea-f923778d8d5f.png)
+
+\ 图2.13 Microposts的index页面(/microposts)
+
+####2.3.2 给微博真正的“微”
+
+
+任何敢叫微博的帖子要对得起他的称呼就要意味着要限制他的长度。要实现这个约束条件在Rails中是非常容易——使用模型验证(validations of rails)。我们可以使用length这个验证条件来限制微博的最大长度为140个字符(学习 Twitter)。你需要用你的IDE或者文本编辑器打开app/models/micropost.rb填入如代码2.9所示的代码(这个验证的使用是rails3的特性,如果你之前有使用Rails2.3.X版本,你可以对比一下“validates_length_of”的用法)。
+代码2.9 约束微博最大字符长度为140。
+
+``` ruby app/models/micropost.rb
+ class Micropost < ActiveRecord::Base
+ validates :content, :length => { :maximum => 140 }
+ end
+```
+
+代码2.9看起来很神秘,不过不要紧,我们将在6.2节中学习更多的验证,但是如果我们回到New页面然后输入超过140个字符的微博就会发现他的影响已经出来了;Rails会渲染错误的信息并提示微博的内容过长(我们将在第8.2.3中学习更多的错误。)。
+
+![p](http://dl.iteye.com/upload/attachment/369988/7a511f79-f186-36d6-a3d7-73903ceeef16.png)
+
+图2.14:创建微博失败的错误信息
+
+####2.3.3 一个user可以有多条微博
+在两个不同的数据模型中创建关系是Rails最强大的功能之一。这里,用户模型中,每一个用户都可以多条的微博信息,我们可以如代码2.10和2.11那样更新User和Microposts模型的代码;
+
+**代码 2.10. 一个user可以有多条微博信息microposts**
+
+
+``` ruby app/models/user.rb
+ class User < ActiveRecord::Base
+ has_many :microposts
+ end
+```
+
+**代码 2.11 每一条微博信息都是属于某一个用户的**
+
+```
+ ruby app/models/micropost.rb
+ class Micropost < ActiveRecord::Base
+ belongs_to :user
+
+ validates :content, :length => { :maximum => 140 }
+ end
+
+```
+
+我们可以想象以上的关系就如图2.15所示。因为microposts表中有user_id的字段,Rails(使用Active Record)可以猜测出微博信息microposts和用户的关系
+
+![pic](http://dl.iteye.com/upload/attachment/369992/c4c778f3-2b27-30c9-94e5-9cc21b404060.png)
+
+**图 2.15: 微博信息microposts和用户users之间的关系**
+
+在第11,12章中,我们将用这2者间的关系来显示所有用户的microposts信息和构建一个和Twitter类似的微博提要(microposts feed)。现在我们通过Rails的控制台(console)来验证user和microposts之间的关系,控制台是一个非常有用的工,他可以使我们和Rails程序之间进行交互。我们先从命令行输入“rails console”进入控制台,然后使用User.first从数据库检索出第一个user(将 结果赋值给变量first_user);
+
+``` bash
+ $ rails console
+ >> first_user = User.first
+ => #<User id: 1, name: "Michael Hartl", email: "michael@example.org",
+ created_at: "2010-04-03 02:01:31", updated_at: "2010-04-03 02:01:31">
+ >> first_user.microposts
+ => [#<Micropost id: 1, content: "First micropost!", user_id: 1, created_at:
+ "2010-04-03 02:37:37", updated_at: "2010-04-03 02:37:37">, #<Micropost id: 2,
+ content: "Second micropost", user_id: 1, created_at: "2010-04-03 02:38:54",
+ updated_at: "2010-04-03 02:38:54">]
+```
+
+这样我们通过first_name.microposts获得了用户的微博信息:运行这个代码,Active Record 会自动返回所有user_id等于first_name的id(这里是1)。
+我们将在11,12章中学习ActiveRecord的更多关联结构。
+
+####2.3.4 继承的层次结构
+
+我们结束关于演示程序的讨论,我们花点时间,简短的介绍一下Rails中控制器类和模型类的继承问题。这个介绍只有在你有面向对象编程经验的时候才会有较多的意义。如过你还没学习OOP,大可以跳过这一节,特别是,你对类(在第4.4节中讨论)很不了解的时候,我建议在以后的时间跳回来看这一节。
+我们先从模型的继承结构开始。对比代码2.12和代码2.13,我们可以看到,User和Micropost两个模型都从ActiveRecord::Base类继承(通过尖括号“<”)。
+ActiveRecord::Base类是ActiveRecord提供的模型的基类。图2.16总结了这种关系;正式由于这种继承使我们的模型可以喝数据库交互,也可以将数据表的字段当成Ruby的属性对待,等等特性。
+
+**代码 2.12 继承的User类**
+
+``` ruby app/models/user.rb
+ class User < ActiveRecord::Base
+ .
+ .
+ .
+ end
+```
+
+**代码 2.13 继承的Micropost类**
+
+``` ruby app/models/micropost.rb
+ class Micropost < ActiveRecord::Base
+ .
+ .
+ .
+ end
+
+```
+
+![pic](http://dl.iteye.com/upload/attachment/370008/2119f47d-4fa9-3c59-9707-4a25863846b9.png)
+
+
+控制器继承的层次结构较复杂一点。对比代码2.14和代码2.15,我们可以看到两个控制器都从ApplicationController。从代码2.16中可以看到ApplicationController自己继承自ApplicationController::base;这个是Rails的Acton Pack 库提供给控制器的基类,类之间的关系如图2.17所示。
+
+
+**代码 2.14. UsersController继承自ApplicationController.**
+
+``` ruby app/controllers/users_controller.rb
+ class UsersController < ApplicationController
+ .
+ .
+ .
+ end
+```
+
+
+**代码 2.15. MicropostsController 继承自ApplicationController.**
+
+``` ruby app/controllers/microposts_controller.rb
+ class MicropostsController < ApplicationController
+ .
+ .
+ .
+ end
+```
+
+```ruby app/controllers/application_controller.rb
+ class ApplicationController < ActionController::Base
+ .
+ .
+ .
+ end
+```
+
+![pic](http://dl.iteye.com/upload/attachment/370012/d53669cd-bc2a-3da3-91ad-6eb7e004518a.png)
+
+
+\ 图 2.17: Users和Microposts控制器的继承结构.
+
+就和模型的继承一样,因为最终都继承自 ActionController::Base ,Users和Microposts的控制都获得大量的功能,比如操作模型对象,过滤收到的请求和渲染HTML页面。因为所有的控制都继承自ApplicationController,所以所有定义在Application Controller 里面的规则都会被自动的运用到所有的方法(action)中去;例如在8.2.4节中我们将看到如何在Application controller中定义一个允许我们从所有的Rails 日志文件中过滤掉密码的规则,这样可以避免一些安全隐患。
+
+
+####2.3.5 部署演示程序
+我们完成了Microposts资源,现在正是我们把他push到GitHub库的时候;
+
+``` bash
+ $ git add .
+ $ git commit -a -m "Done with the demo app"
+ $ git push
+```
+
+
+你也可以把演示程序部署到Heroku:
+
+``` bash
+ $ heroku create
+ $ git push heroku master
+ $ heroku rake db:migrate
+```
+
+
+(如果上面的没有效果,你可以看看前面代码1.8,或许对你有帮助。)
+请注意这里在heroku运行数据库迁移的最后一行代码,这是只是在heroku上创建user/micropost的数据模型。如果你希望吧数据也上传,你可以使用 data up命令。前提是你有taps这个gem:
+
+``` bash
+ $ [sudo] gem install taps
+ $ heroku db:push
+```
+
+
+
+2.4 总结
+现在我们站在一个Rails 程序30000英尺远的地方观察他,这一章中按这个方法开发的演示程序有一些优势和一些主机缺点(不明白什么意思, a host of weaknesses。)
+
+优势
+
+* High-level overview of Rails 高水平的Rails概述
+
+* Introduction to MVC 介绍了MVC
+
+* First taste of the REST architecture 第一次尝试REST架构
+
+* Beginning data modeling 开始数据建模
+
+* A live, database-backed web application in production 制作了一个在线的数据库支持的Web程序
+
+
+弱点
+
+* No custom layout or styling 没有布局或者样式
+
+* No static pages (like “Home” or “About”) 没有静态页面,比如首页
+
+* No user passwords 用户没有密码
+
+* No user images 用户没有图片
+
+* No signing in 没有登录
+
+* No security 不安全
+
+* No automatic user/micropost association 没有自动关联user/micropost
+
+* No notion of “following” or “followed” 没有 “following” or “followed”的概念.
+
+* No micropost feed 没有微博提要
+
+* No test-driven development 没有测试驱动
+
+* No real understanding 还没弄明白
+
View
935 rails-tutorial-chapter3.markdown
@@ -1,469 +1,466 @@
-翻译 [ruby on rails Tutorial](http://ruby.railstutorial.org/chapters/a-demo-app#top),原作者 [Michael Hartl](http://michaelhartl.com/) .
-
-
-##第三章 Mostly static pages
-
-在这一章中我们将开始开发一个例子程序,这个程序就是本书中接下来的所使用的例子。
-尽管这个程序最终将会实现用户,微博信息,登录登出验证框架等,但是我们就从看起来蛮简单的开始——创建静态页面。尽管它很简单,但是创建静态页面是一项非常有意义和启发性的练习,对于我们新程序来说是一个完美的开端。
-Rails虽然是用来设计数据库支持的动态网站,但是它也擅长用原生的HTML文件来产生静态网页。实际上用Rails产生静态网页会有明显的优势:我们可以非常容易的添加一小部分的动态内容。在这一章中我们也将学习如何添加这些内容。继续下去我们就将会第一次亲密接触自动测试,它会让我们对我们写过的代码更有自信。此外,有一个好的测试工具会是我们重构代码的时候更有信心——只改结构和形式没有改变它应有的功能。
-
-如第二章所说,我们从新建一个Rails的应用程序开始,这次叫它:sample_app
-
-``` bash
- $ cd ~/rails_projects
- $ rails new sample_app -T
- $ cd sample_app
-```
-
-在这里的 -T 参数是告诉 Rails 不要生成使用 Test::Unit 工具测试test文件夹。这意思是我门不要测试,正好相反,在第3.2节中我们将使用Rspec测试框架来代替 Test::Unit。
-
-回到我们的项目,我们接下来要做的是使用文本编辑器去修改Gemfile文件。我们需要添加一些我们程序需要的gem包,和前一章中所声明的,sqlite3-ruby的gem的版本是1.2.5,这和以前一样,是我们在本地开发所需要的gem(重申:我的系统需要1.2.5版本,如果你无法使用它,你可以使用1.3.1版本),另一方面,对于这个示例次序来说,我们还需要2个以前没用的gem:Rspec和 Rails的rspec库,
-示例代码如代码3.1(提示:如果你想要提前把我们这个程序的所有gem都安装,我觉得你应该参考代码10.42):
-
-``` ruby 代码3.1:示例程序的Gemfile
- source 'http://rubygems.org'
-
- gem 'rails', '3.0.3'
- gem 'sqlite3-ruby', '1.3.2', :require => 'sqlite3'
-
- group :development do
- gem 'rspec-rails', '2.3.0'
- end
-
- group :test do
- gem 'rspec', '2.3.0'
- gem 'webrat', '0.7.1'
- end
-```
-上面代码的开发模式里包含了rspec-rails,所以我们可以使用Rspec-specific生成器,在测试模式下包含了rspec,所以我们可以运行那些测试。(我们也包含Webrat测试工具,以前的版本它会被当成一个依赖包自动的添加,但是现在我们需要手动的添加它,它是目前用来生成页面测试的工具,所以我们需要它)。然后我们用Bundle install来安装这些gem。
-
- $ bundle install
-
-为了让Rails知道我们使用Rspec代替Test::Unit,我们需要安装一些Rspec需要的文件。我们可以通过 rails generate:
-
- $ rails generate rspec:install
-
-到这里,我要做的只剩下初始化Git库了:
-
- $ git init
- $ git add .
- $ git commit -m "Initial commit"
-
-
-和第一程序一样,我还是建议更新“README”文件(位于程序的根目录。)。代码3.2的描述或许对你有些帮助。
-<!--more-->
-``` bash 代码 3.2 示例程序的README文件.
- # Ruby on Rails Tutorial: sample application
-
- This is the sample application for
- [*Ruby on Rails Tutorial: Learn Rails by Example*](http://railstutorial.org/)
- by [Michael Hartl](http://michaelhartl.com/).
-```
-
-
-接下来,我们给他添上markdown的后缀名,然后提交它:
-
- $ git mv README README.markdown
- $ git commit -a -m "Improved the README"
-
-
-![pic](http://ruby.railstutorial.org/images/figures/create_repository.png)
-
-图3.1: 创建示例程序的GitHub库
-
-
-为了将我们书中的程序放在github进行控制,增加一个新库是一个不错的主意。
-
- $ git remote add origin git@github.com:<username>/sample_app.git
- $ git push origin master
-
-(提示:到这一步 http://github.com/railstutorial/sample_app 库中的代码是示例程序所有的代码,欢迎咨询参考,但是有2点要注意:1,自己输入代码比使用现成的代码会学到更多的东西;2,书中提到Github库的代码有的会有差别,这主要是由于一方面这个库合并了本书中的练习和视频教程中的练习。)
-当然,我也可以在现在就部署到Heroku,
-
- $ heroku create
- $ git push heroku master
-
-
-(如果错误可以参考代码1.8试着修复。) 在接下来的教程中,我建议你可以定期的push和发布程序;
-
- $ git push
- $ git push heroku
-
-这样我们就可以开发示例程序了~
-
-
-###3.1 静态页面
-
-Rails有2个主要的方法产生静态网页。第一,Rails可以处理由原生的HTML文件组成的真正静态页面(我也不明白什么意思,看下去吧)。第二,Rails允许我们定义rails可以渲染的含有原生HTML的视图,这样服务器可以将它发送到浏览器。
-回忆一下第1.2.3(图1.2)节中所讲Rails的结构对我们把握中心是很有帮助的。这一节我们主要的工作目录是app/controllers 和 app/views,在3.2节中我们会接触到新的目录(我们甚至可以添加自己的目录.);
-
-####3.1.1 真正的静态页面
-
-让我们从真正的静态页面开始学习吧,回顾一下第1.2.5中关于每一个Rails程序一开始就就是一个非常小的程序(主要是Rails脚本的功劳,例如生成器)而且都有一个默认的欢迎页面(地址:http://localhost:3000/ .)
-
-![pic](http://ruby.railstutorial.org/images/figures/public_index_rails_3.png)
-
-图片3.2 public/index.html文件
-
-
-看一下上图中代码,我们学习一下这个页面是从哪里来的。因为这个页面把样式直接包括进去,所以看起来有点乱,但是他的主要功能是:Rails将会把public文件夹下面的任何文件提供给浏览器。其中index.html文件是非常特别的,当你没有指定url地址的时候(http://localhost:3000/)他就是默认提供给浏览器的页面。当然你也可以包含它(http://localhost:3000/index.html)是没有区别的。
-正如你所想的,如果我们喜欢,我们可以吧我们自己的静态网页像index.html文件一样放在public目录底下。所为例子,让我们创建一个问候用户的页面
-
- $ mate public/hello.html
-
-
-
-
-``` html 代码3.3问候的HTML页面
- <!DOCTYPE html>
- <html>
- <head>
- <title>Greeting</title>
- </head>
- <body>
- <p>Hello, world!</p>
- </body>
- </html>
-```
-
-在代码3.3中,我们看到一个典型的HTML文件:在头部声明document type(或者doctype),告诉浏览器HTML的版本(我们使用HTML5),在HTML的head中,我们设置“Greeting”作为title标签,在Body里面,我们在一个段落标签里放入了“Hello,world!”(上面的缩进可以不必理会,HTML的空格和tab键没影响。加上必要的排版可以让我们的文档更方便查看。)。好了,和上面说的一样,我们可访问地址:
-http://localhost:3000/hello.html,Rails将会直接将页面返回给我们(图3.3)。
-(HTML文本的title在浏览器的顶部。)
-
-![pic](http://ruby.railstutorial.org/images/figures/hello_world.png)
-
-图3.3我们自己的静态网页
-上述页面只是为了示范而已。它可不是我们程序的一部分,所以我们应该删除掉它。
-
- $ rm public/hello.html
-
-我们先把index.html文件放一边,当然我们最终是要删除掉它的,我们可不想我们程序的根目录总是如图1.3所示那样的Rails默认页面。我们将会在第5.2节中学习如何让我们的地址“http://localhost:3000/”不指向public/index.html
-
-3.1.2 Rails静态页面
-
-
-可以返回静态页面是值得让人兴奋地,但是这对于开发一个动态web程序的来说并不是很有用。在这一节,我们学习创建动态页面的第一步:创建一些Rails的action方法,这些方法定义URL的能力比静态页面强很多。Rails的action方法在控制器里。第二章惊鸿一瞥的REST架构,我们将要在第六章深入的学习。本质上,controller是一组网页页面(可能是动态)的容器。
-
-我们从回忆第1.3.5节中,我们如何使用Git开始,将我们工作的内容单独放在一个分支里面比直接在master分支更值得我们借鉴。如果你使用Git版本控制,你可以运行一下代码
-
- $ git checkout -b static-pages
-
-Rails里面我们可以使用一个Generate的脚本来创建控制器;他的神奇之处就在于我们所要做的只是想一个控制器的名称。
-由于我们的这个控制器主要用来处理静态页面,我们就叫他,Pages,而且我们希望给他几个action去响应Home page,contact page,和about page。我们可以在generate 脚本后面更上几个可选的参数作为actions,我们可以看到结果如下:
-
-``` ruby 代码3.4创建Pages控制器
- $ rails generate controller Pages home contact
- create app/controllers/pages_controller.rb
- route get "pages/contact"
- route get "pages/home"
- invoke erb
- create app/views/pages
- create app/views/pages/home.html.erb
- create app/views/pages/contact.html.erb
- invoke rspec
- create spec/controllers/pages_controller_spec.rb
- create spec/views/pages
- create spec/views/pages/home.html.erb_spec.rb
- create spec/views/pages/contact.html.erb_spec.rb
- invoke helper
- create app/helpers/pages_helper.rb
- invoke rspec
-```
-
-(注意,我们使用rails generate rspec:install来安装了Rspec所以,控制器自动在spec目录底下,生成了Rspec的测试文件。)。在这里,我故意遗忘了about page,我们可以在下一节3.2中学习如何手动添加它。
-代码3.4中生成控制器的时候已经更新了routes的文件(位于config/routes.rb),Rails用该文件来查找URL和网页之间的对应关系。这是我们第一次遇到config这个文件夹,所以我们应该来快速的过一遍这个文件夹(如图3.4)。这个文件夹是rails放置一些配置文件的目录,故称其名。
-
-![pic](http://ruby.railstutorial.org/images/figures/config_directory_rails_3.png)
-
-由于我们生成了home和contact的action方法,所以,routes文件已经为每一个action配置好了规则,如代码3.5:
-
-
-``` ruby config/routes.rb page控制器中home和contact的路由规则
-
- SampleApp::Application.routes.draw do
- get "pages/home"
- get "pages/contact"
- .
- .
- .
- end
-
-```
-
-规则:
-
-
- get "pages/home"
-
-
-
-映射了请求url:pages/home到Pages控制器的home方法。此外,使用get我们制定这个路由只会响应GET(一种HTTP协议(见Box3.1)支持的基础HTTP动作)的请求。对我们来说,我们在Pages的控制器中创建一个home的方法之后就自动的获得了一个页面地址“pages/home”,可以用Ctrl+C关闭服务器之后,重新启动(其实可以不用重启,rails的可以动态载入这些方法),然后访问pages/home(见图3.5)
-
-![pic](http://ruby.railstutorial.org/images/figures/raw_home_view.png)
-
-
->**Box 3.1.GET和其他.**
->HTTP协议定义了四种基本操作方式,分别是get,post, put, 和delete。这些是指在客户端和服务端之间的操作。(这个非常的重要,在开发中,一般客户端和服务器是同台机器,但是一般情况下,他们是不同的),强调HTTP动作是web框架(包括Rails)被REST架构影响的一个非常典型的特征。好处可以参考第2章,第八章会有深入的了解。
-GET is the most common HTTP operation, used for reading data on the web;
-get是HTTP操作中最常用的一个,一般用于请求数据。
-it just means “get a page”, and every time you visit a site like google.com or craigslist.org your browser is submitting a GET request.
-它的意思就是“获取页面”,所以每次你访问google.com 或者craigslist.org 的时候,你的浏览器都是提交一个Get的请求。
-POST is the next most common operation; it is the request sent by your browser when you submit a form.
-下一个常用的操作是Post,它一般在提交一个表单的时候使用。
-In Rails applications, POST requests are typically used for creating things (although HTTP also allows POST to perform updates);
-在rails里面Post的请求一般用于创建数据(尽管HTTP也允许post去实现更新。)
-for example, the POST request sent when you submit a registration form creates a new user on the remote site.
-比如,当你提交一个注册表单之后就会在服务器那边创建一个新的用户。
-The other two verbs, PUT and DELETE, are designed for updating and destroying things on the remote server.
-另外2个操作时put和delete,前者用来更新远程服务器数据,后者用来删除数据。
-These requests are less common than GET and POST since browsers are incapable of sending them natively, but some web frameworks (including Ruby on Rails) have clever ways of making it seem like browsers are issuing such requests.
-这2个没有前面2个操作那么普遍,有的浏览器没有支持发送这样的请求,但是一些web的框架(包括rails)有自己的方法去实现,让他发送这中请求。
-
-让我们从Pages的控制器开始看看,这些页面是哪里来的。如代码3.6所示(你可能注意到,这个和第二章中的Users和Microposts控制器有区别,这个控制器并没有遵循REST规则。)
-
-
-``` ruby 代码 3.6代码3.4产生的控制器代码。
- class PagesController < ApplicationController
-
- def home
- end
-
- def contact
- end
- end
-```
-
-我们看到pages_contoller.rb文件中定义了PagesController类。类是把功能(或方法,就像用def定义的home和contact方法一样。)组织起来的一种简单方法。尖括号“<”便是PacgesController从Rails的ApplicationContoller类;
-正如我们将看到,这说明了我们的网页装备了大量的Rails的特定功能(我们将会在第4.4节中学习类个继承。)
-在这里,控制器中页面的方法都是空的。
-在ruby里,这些方法什么都不做,但是在Rails里面却有点却别。PagesController是一个Ruby的类,但是由于他继承自ApplicationController。所以他的方法有一些特别。当我们访问URL /pages/home、 Rails寻找Pages的控制器,然后执行home的方法,然后渲染页面响应页面的动作。因为在上面home的方法是空的,所以他除了渲染页面之外什么也没做。所以页面应该什么样子,我们应该如何找到它呢。
-如果你再看看代码3.4的输出,你可能会猜出页面和方法之间的关系:一个方法如home页面对应一个视图如home.html.erb。我们将会在3.3中学“.erb”的意义。从".html"部分你也不用惊讶它看起来是基于HTML。
-
-``` html app/views/pages/contact.html.erb
- <h1>Pages#contact</h1>
- <p>Find me in app/views/pages/contact.html.erb</p>
-```
-
-
-
-contact方法类似:
-``` html app/views/pages/contact.html.erb
- <h1>Pages#contact</h1>
- <p>Find me in app/views/pages/contact.html.erb</p>
-```
-
-
-
-以上2个页面就类似占位符:一个顶级的h1标签,和一个包含了相关文件绝对路径的的P标签。我们从第3.3节开始学习添加一些动态(少量)的内容,但是他们说明了一个重要的知识:Rails的页面可以使只含有静态HTML的。只要浏览器链接,就很难区别开到底是由3.1.1中的静态页面显示,还是由控制器方法提供页面:因为浏览器都只看到HTML。
-在这一章剩下的内容,我们将学习在3.1.2中故意遗漏的“about”,添加非常少的动态内容,然后第一次涉及页面的CSS样式。在进入下面的学习之前,我们应该将变动添加到Git的库里面去。
-
-
- $ git add .
- $ git commit -am "Added a Pages controller"
-
-
-你或许想起来,我们再1.3.5节里面使用 git commit -a -m "Message"命令,用-a表示“all change”,用-m表示“信息”;git也允许我们将2个参数合到一起“-am”、我在本书中将会继续使用这种简写。
-
-###3.2 我们的第一个测试
-
-如果你去问五个 Rails 开发者如何去测试一段代码,你会得到15种不同的答案————不过他们都会认为写下测试代码是必要的。测试一段代码是一种精神,把一段心目中的想法写成测试而不用担心什么问题会让你的开发更佳完美。你也没有必要把 这里的测试方式当成是圣经,它们只不过是那些我从自己和我读到的代码中用到的东西。如果你想成为一个有经验的 Rails 开发者,你无疑在某日形成一个自己的测试开发风格的。
-
-另外,在我们的示例程序中我们编写测试程序用了一种最近很流行的方法 在开发前编写测试文件(when to write tests by writing them before the application code)————一种测试驱动开发的方法,也叫TDD。我们的应用将要增加一个 About 页面。不用担心,增加一个额外的页面并不难————你或许都已经通过上面的学习猜到答案了————但是这一次我们要著重于测试文件的编写。
-
-虽然为一个已经存在的界面进行测试似乎是有点闲的蛋疼,但是我的经验告诉我事实不是这样的。许多代码会写着写着就错了,有一个好的测试来约束你能够保证你的程序质量。另外,对于一个计算机程序来说,尤其是一个网络应用来说,扩展性是很重要的,这样每当你添加一个功能你都会面临一份程序写"跑题"了的危险。写下测试并不意味着程序中的bug会小时,而是让他们更容易被抓到和修复。而有的人确实会为抓bug而写测试。
- (正如我们在1.1.1中说的那样,如果你发现测试非常的让你头疼,你完全可以只把教程中的Ruby on Rails 抽出来先学习,然后再自行学习测试方面的技巧).
-
-####3.2.1 测试工具
-
- 为了给我们的示例程序进行测试,我们的主要工具是一个测试框架,叫做 [RSpec](http://rspec.info/),它使用“特别管理语言”来描述代码的行为,并判断代码是否完成了对应的工作。在Rails社区中,RSpec 测试Ruby程序十分高效,以至于 Obie Fernandez , The Rails 3 way 的作者把RSpec 叫做 “Rails必由之路”,我在这里也表示赞同。
-
-**autotest**
-
-Autotest 是一个在你更改程序的时候,在后台自动帮你进行测试的套件。例如,如果你把一个 controller 改了 ,Autoest 就立马会对那个controller对应的view进行测试,测试结果也会马上反馈回来。我们会在 3.2.2 学到更多关于 Autotest 的东西。
-
-安装 Autotest是可选的,不过安装Autotest 有点犯人,不过我保证当你发现它是多么的有用的时候你会觉得一些都是值得的。首先你要先安装一下 autotest 和 autotest-rails-pure 这两个gems
-
- $gem install autotest -v 4.4.6
- $gem install autotest-rails-pure -v 4.1.2
-
-(如果你在这里遇到了 “权限不够”的提示的话那你可能需要使用 sudo 命令来运行它们)。
-
-下一个步骤将要取决与你的系统平台,我会在这里用我的 OS X 来做演示,然后我会给出几篇关于安装在linux 和 windows方法 的 blog。在 OS X 上,你需要先安装 [Growl](http://growl.info/) 然后安装 auto-fsevent 和 autotest-growl 两个gems。
-
- $ gem install autotest-fsevent -v 0.2.4
- $ gem install autotest-growl -v 0.2.16
-
-如果fsevent安装除了问题的话 ,你最好检查一下 你机子上的 Xcode 是否正常工作。
-
-要想使用Growl 和 FSEvent 的Gem ,你需要把Autotest 的配置文件放到你的工作文件夹的根目录下面。并且在按如下方法添加一些文件内容:
-
- $ mate .autotest
-
-配置文件需要加入:
-
- require 'autotest/growl'
- require 'autotest/fsevent'
-
-或者你可以加入:
-
- require 'autotest-growl'
- require 'autotest-fsevent'
-
-(这个设置文件只对你当前的应用程序起作用,如果你想要让你的所有 ruby 和rails 项目共享这一配置,你可以把这个 <code> .autotest </code>放到你的个人文件根目录下面去)
-
- $ mate ~/.autotest
-
-如果你实在Linux的Gnome的桌面系统之下的话。我建议你尝试一下 这里([Automate Everything])的东西[http://automate-everything.com/2009/08/gnome-and-autospec-notifications/].通过它可以让你在 linux 上面运行和 OS X 差不多的 Growl 提示。至于 Windows 用户 ,你们可以尝试安装
-[Growl for Windows](http://www.growlforwindows.com/gfw/),然后跟着 [GitHub 的 autotest-growl页面](http://github.com/svoop/autotest-growl)来做。不管是linux还是windows的用户都应该看看[autotest-notification](http://github.com/carlosbrando/autotest-notification), Rails Tutorial 的读者 Fred Schoeneman 写了一篇[博文](http://fredschoeneman.posterous.com/pimp-your-autotest-notification)也很值得一看.
-
-####3.2.2 TDD:红灯,绿灯,重构
-
-对于测试驱动开发来说,我们通常会事先写一个失败的测试————失败意味着是不能通过。在我们这个例子当中,刚开始我们就会写一段验证:“应该会是 about page ”的页面测试代码,当然这个时候about页面没有出现,所以如果运行测试的就会失败。如果要想让测试通过,我们就应该加入和about页面对应的行为和视图。那为什么我们反过来做,先写功能,在做测试呢?这是为了保证我们确确实实加入了我们所需要的特性。在我刚开始使用 TDD 的时候,我先为我自己的程序中又那么多的错误感到惊讶,然后慢慢让测试出的错误消失,确保刚开始测试的失败然后再慢慢让它成功,我们就会慢慢对我们写出的代码更有信心。
-
-还有一点非常重要,TDD并非任何时候都使用的,尤其是,当你对某个问题还没有个确切的解决方法的时候。这时候通常会先忽略测试而直接完成功能代码(在极限编程 XP 中,这种试探性的步骤叫做 spike ),而一旦你发现了一个确切的方法去解决这个问题之后,你就可以重新用TDD来更优雅实现一个新的版本。
-
-“红,绿,重构 ”是在测试驱动开发中使用的方法,第一步:红,指的是写一个失败的测试,大部分测试工具会在这里以红色指出错误,第二步:绿,意味着测试通过,然后当我们的测试都成功通过之后我们就可以在不改变功能的条件下随意的重构我们的代码:删除重复,更改设计模式等等。
-
-当然现在我们还什么颜色都没有,让我们先从红色开始把,RSpec(其他的测试工具也一样)在刚开始可能又一些吓人,我们这里先从 rails generate controller pages (Listing3.4) 开始。这里因为我不太喜欢把 views/helpers 分离出来测试(我觉得这样很多余),我们的第一步就是把他们移除掉。如果你在使用 Git ,你可以这么做:
-
- $git rm -r spec/views
- $git rm -r spec/helpers
-
-然后我们再把文件也移除了:
-
- $ rm -rf spec/views
- $ rm -rf spec/helpers
-
-在开始前,我们来看看我们刚刚建立的 Page 的Controller 的 spec
-
-``` ruby spec/controllers/pages_controller_spec.rb
-require 'spec_helper'
-
-describe PagesController do
-
- describe "GET 'home'" do
- it "should be successful" do
- get 'home'
- response.should be_success
- end
- end
-
- describe "GET 'contact'" do
- it "should be successful" do
- get 'contact'
- response.should be_success
- end
- end
-end
-
-```
-
-这是纯粹的Ruby代码,但是即使你学习过Ruby你恐怕也不能看明白这些东西是什么意思。这是因为RSpec为了测试专门为Ruby语言进行了扩展,用的是一种 “domain-specific-language”(DSL)语言,这种语言的特点就是你完全不知道它的语法也可以使用RSpec,刚开始这或许看起来会有点不可思议,但是没有关系,Rspec 测试脚本读起来基本就和英语一样,如果你已经做了前面的那些 generate 和 实例程序之后我想搞定它也不难。
-
-上面的代码中包括了两个 <code> describe </code> 代码块,他们与我们的 example 一一对应,这里我们先来看看第一个 describe 是怎么回事。
-
-``` ruby
- describe "GET 'home'" do
- it "should be successful" do
- get 'home'
- response.should be_success
- end
- end
-```
-在这里,第一行指出我们正在对于 HOME 页面进行一个 GET 操作,这仅仅是一个描述性的语句,你完全可以在这里写任何你想要的东西,RSpec不会在乎的(其他人类会在乎的)。在这里 GET ‘home’ 指的是测试 HOME 相对应的 HTTP GET 请求,如同 上面 BOX 3.1 中讨论的那样。然后 RSpec 说如果你你访问了 HOME 页面,应该能够成功返回。这里的第一行其实和测试行为完全不相干的,仅仅是是对人类读者的一种描述行记录。第三行 <code>get ‘home’</code> 在这里RSpec才真正开始干活了,这里RSpec会先提交一个 GET 请求,换一句话说,在此时RSpec相当于打开浏览器并且链到你的网页上,这个网页就是你的 ** /PAGES/HOME ** (RSpec之所以知道控制器是 PAGES 因为我们在做的是 PAGES CONTROLLERS 的测试,访问HOME 则是因为你明确告诉了它)。最后,第四行告诉它这个页面应该会成功的返回(也就是说他应该返回一个状态码 200 )
-
->**Box 3.2 HTTP 返回码**
-
-
->在一个客户端(例如浏览器)发送了一个HTTP的动词请求的时候,网络服务器会在返回的时候加上一段数字代码来作为 HTTP 状态字。例如状态字 200 意味着 “成功”,状态字301 意味着 “静态跳转” ,如果你安装了 curl ,一个可以解析HTTP请求的命令行客户端,你就可以直接看到状态字。例如访问 <code> www.google.com </code>
-
-> $ curl --head www.google.com
-> HTTP/1.1 200 OK
-> .
-> .
-> .
-
->在这里谷歌就成功完成了你的请求并且返回了状态码 200 OK .同样, GOOGLE.com 会静态的跳转到 www.google.com 所以他会指向一条 301 的状态码 (301 跳转)
-
-> $ curl --head google.com
- HTTP/1.1 301 Moved Permanently
- Location: http://www.google.com/
- .
- .
- .
->(注意,这个范例将会随着你的国家不同而又很大差别。。。)
-
->当我们在RSpec 的测试文件里面写了 response.should be_success ,RSpec会识别出我们的应用返回了一个正确的 200代码。
-
-现在是时候让我们的测试跑起来了。这里有几种不同的方法来运行测试(但是总体上大同小异)。第一种方法是在命令行里运行 rspec 脚本,像这样
-
- $ bundle exec rspec spec/
- ....
-
- Finished in 0.07252 seconds
-
- 2 examples, 0 failures
-
-(不幸的事,很多事情可能让你在这个时候运行出 fail ,如果你中枪了,你可以尝试着用命令 “bundle exec rake db:migrate” 来 migrate 一下数据库。如果rspec还是不工作,那你恐怕就要重新卸载安装数据库了:
-
- $ gem uninstall rspec rspec-rails
- $ bundle install
-
-如果这也不行你那你恐怕就要用 RVM 来重新卸载安装你的 gems 了:
-
- $ rvm gemset delete rails3tutorial
- $ rvm --create use 1.9.2@rails3tutorial
- $ rvm --default 1.9.2@rails3tutorial
- $ gem install rails -v 3.0.11
- $ bundle install
-
-如果这也不行,那我也没办法了 -_- .)
-
-当你运行了 <code>bundle exec rspec spec/</code> 的时候, rspec 是作为一个由Rspec提供的程序来运行的,而 spec/ 是一个你所需要测试的目录。你也可以 rspec 只运行测试一个目录下的文件例如这个例子就运行spec测试了 controller :
-
- $ bundle exec rspec spec/controllers/
- ....
- Finished in 0.07502 seconds
-
- 2 examples, 0 failures
-
-你甚至可以运行一个单独的文件
-
- $ bundle exec rspec spec/controllers/pages_controller_spec.rb
- ....
- Finished in 0.07253 seconds
-
- 2 examples, 0 failures
-
-注意,在这里我们再一次运用了 bundle exec 来执行我们的命令(bundle exec 可以以Gemfile中指定的gems版本来执行命令),因为这样命令看起来有一点冗长,所以 Bundler 允许创建二进制的程序集例如这样:
-
- $ bundle install --binstubs
-
-这样一来所有需要的gems执行程序都将会生成到 bin/ 文件夹下面去。我们现在就可以直接这样运行:$
-
- bin/rspec spec/
-
-rake也一样:
-
- $ bin/rake db:migrate
-
-对于不想这么做的朋友们,那么在将来的课程里你们恐怕需要都用 bundle exec 来运行这些特定的命令了(当然也可以选择这个简单些的办法.)
-
-由于这个页面控制器目前是我们唯一的测试文件,所以这三个命令应该输出都是一样的。在剩下的教程里面,我们不会把运行test的命令行打出来,但是你自己要知道用bundle exec rspec spec/ (或者其他的东西),或者自己用autotest之类的东西。
-
-如果你安装了 Autotest 你可以自动进行的RSpec测试:
-
- $ autotest
-
-如果你用的是 Mac 的 Growl 测试工具,你可以向我一样,如下图一样,autotest在后台运行,Growl 会提醒你当前测试的状态,这样用 TDD 是会上瘾的。
-
-![autotest](http://ruby.railstutorial.org/images/figures/autotest_green.png)
-
-####Spork
-
-在前面的例子里你可能已经注意到了,用这样的套件运行一次测试非常的慢(the overhead involved in running a test suite can be considerable.不知道是不是这意思)。这是因为每次运行RSpec来进行一次测试都会 Reload 一次 Rails 环境。Spork test server 就是针对这个问题产生的。
-
-
-
-
-
+翻译 [ruby on rails Tutorial](http://ruby.railstutorial.org/chapters/a-demo-app#top),原作者 [Michael Hartl](http://michaelhartl.com/) .
+
+
+##第三章 Mostly static pages
+
+在这一章中我们将开始开发一个例子程序,这个程序就是本书中接下来的所使用的例子。
+尽管这个程序最终将会实现用户,微博信息,登录登出验证框架等,但是我们就从看起来蛮简单的开始——创建静态页面。尽管它很简单,但是创建静态页面是一项非常有意义和启发性的练习,对于我们新程序来说是一个完美的开端。
+Rails虽然是用来设计数据库支持的动态网站,但是它也擅长用原生的HTML文件来产生静态网页。实际上用Rails产生静态网页会有明显的优势:我们可以非常容易的添加一小部分的动态内容。在这一章中我们也将学习如何添加这些内容。继续下去我们就将会第一次亲密接触自动测试,它会让我们对我们写过的代码更有自信。此外,有一个好的测试工具会是我们重构代码的时候更有信心——只改结构和形式没有改变它应有的功能。
+
+如第二章所说,我们从新建一个Rails的应用程序开始,这次叫它:sample_app
+
+ bash
+ $ cd ~/rails_projects
+ $ rails new sample_app -T
+ $ cd sample_app
+
+在这里的 -T 参数是告诉 Rails 不要生成使用 Test::Unit 工具测试test文件夹。这意思是我门不要测试,正好相反,在第3.2节中我们将使用Rspec测试框架来代替 Test::Unit。
+
+回到我们的项目,我们接下来要做的是使用文本编辑器去修改Gemfile文件。我们需要添加一些我们程序需要的gem包,和前一章中所声明的,sqlite3-ruby的gem的版本是1.2.5,这和以前一样,是我们在本地开发所需要的gem(重申:我的系统需要1.2.5版本,如果你无法使用它,你可以使用1.3.1版本),另一方面,对于这个示例次序来说,我们还需要2个以前没用的gem:Rspec和 Rails的rspec库,
+示例代码如代码3.1(提示:如果你想要提前把我们这个程序的所有gem都安装,我觉得你应该参考代码10.42):
+
+
+ ruby 代码3.1:示例程序的Gemfile
+
+ source 'http://rubygems.org'
+
+ gem 'rails', '3.0.3'
+ gem 'sqlite3-ruby', '1.3.2', :require => 'sqlite3'
+
+ group :development do
+ gem 'rspec-rails', '2.3.0'
+ end
+
+ group :test do
+ gem 'rspec', '2.3.0'
+ gem 'webrat', '0.7.1'
+ end
+
+上面代码的开发模式里包含了rspec-rails,所以我们可以使用Rspec-specific生成器,在测试模式下包含了rspec,所以我们可以运行那些测试。(我们也包含Webrat测试工具,以前的版本它会被当成一个依赖包自动的添加,但是现在我们需要手动的添加它,它是目前用来生成页面测试的工具,所以我们需要它)。然后我们用Bundle install来安装这些gem。
+
+ $ bundle install
+
+为了让Rails知道我们使用Rspec代替Test::Unit,我们需要安装一些Rspec需要的文件。我们可以通过 rails generate:
+
+ $ rails generate rspec:install
+
+到这里,我要做的只剩下初始化Git库了:
+
+ $ git init
+ $ git add .
+ $ git commit -m "Initial commit"
+
+
+和第一程序一样,我还是建议更新“README”文件(位于程序的根目录。)。代码3.2的描述或许对你有些帮助。
+<!--more-->
+
+ bash 代码 3.2 示例程序的README文件.
+
+ # Ruby on Rails Tutorial: sample application
+
+ This is the sample application for
+ [*Ruby on Rails Tutorial: Learn Rails by Example*](http://railstutorial.org/)
+ by [Michael Hartl](http://michaelhartl.com/).
+
+
+接下来,我们给他添上markdown的后缀名,然后提交它:
+
+ $ git mv README README.markdown
+ $ git commit -a -m "Improved the README"
+
+
+![pic](http://ruby.railstutorial.org/images/figures/create_repository.png)
+
+图3.1: 创建示例程序的GitHub库
+
+
+为了将我们书中的程序放在github进行控制,增加一个新库是一个不错的主意。
+
+ $ git remote add origin git@github.com:<username>/sample_app.git
+ $ git push origin master
+
+(提示:到这一步 http://github.com/railstutorial/sample_app 库中的代码是示例程序所有的代码,欢迎咨询参考,但是有2点要注意:1,自己输入代码比使用现成的代码会学到更多的东西;2,书中提到Github库的代码有的会有差别,这主要是由于一方面这个库合并了本书中的练习和视频教程中的练习。)
+当然,我也可以在现在就部署到Heroku,
+
+ $ heroku create
+ $ git push heroku master
+
+
+(如果错误可以参考代码1.8试着修复。) 在接下来的教程中,我建议你可以定期的push和发布程序;
+
+ $ git push
+ $ git push heroku
+
+这样我们就可以开发示例程序了~
+
+
+###3.1 静态页面
+
+Rails有2个主要的方法产生静态网页。第一,Rails可以处理由原生的HTML文件组成的真正静态页面(我也不明白什么意思,看下去吧)。第二,Rails允许我们定义rails可以渲染的含有原生HTML的视图,这样服务器可以将它发送到浏览器。
+回忆一下第1.2.3(图1.2)节中所讲Rails的结构对我们把握中心是很有帮助的。这一节我们主要的工作目录是app/controllers 和 app/views,在3.2节中我们会接触到新的目录(我们甚至可以添加自己的目录.);
+
+####3.1.1 真正的静态页面
+
+让我们从真正的静态页面开始学习吧,回顾一下第1.2.5中关于每一个Rails程序一开始就就是一个非常小的程序(主要是Rails脚本的功劳,例如生成器)而且都有一个默认的欢迎页面(地址:http://localhost:3000/ .)
+
+![pic](http://ruby.railstutorial.org/images/figures/public_index_rails_3.png)
+
+图片3.2 public/index.html文件
+
+
+看一下上图中代码,我们学习一下这个页面是从哪里来的。因为这个页面把样式直接包括进去,所以看起来有点乱,但是他的主要功能是:Rails将会把public文件夹下面的任何文件提供给浏览器。其中index.html文件是非常特别的,当你没有指定url地址的时候(http://localhost:3000/)他就是默认提供给浏览器的页面。当然你也可以包含它(http://localhost:3000/index.html)是没有区别的。
+正如你所想的,如果我们喜欢,我们可以吧我们自己的静态网页像index.html文件一样放在public目录底下。所为例子,让我们创建一个问候用户的页面
+
+ $ mate public/hello.html
+&nbsp;
+
+ html 代码3.3问候的HTML页面
+
+ <!DOCTYPE html>
+ <html>
+ <head>
+ <title>Greeting</title>
+ </head>
+ <body>
+ <p>Hello, world!</p>
+ </body>
+ </html>
+
+
+在代码3.3中,我们看到一个典型的HTML文件:在头部声明document type(或者doctype),告诉浏览器HTML的版本(我们使用HTML5),在HTML的head中,我们设置“Greeting”作为title标签,在Body里面,我们在一个段落标签里放入了“Hello,world!”(上面的缩进可以不必理会,HTML的空格和tab键没影响。加上必要的排版可以让我们的文档更方便查看。)。好了,和上面说的一样,我们可访问地址:
+http://localhost:3000/hello.html,Rails将会直接将页面返回给我们(图3.3)。
+(HTML文本的title在浏览器的顶部。)
+
+![pic](http://ruby.railstutorial.org/images/figures/hello_world.png)
+
+图3.3我们自己的静态网页
+上述页面只是为了示范而已。它可不是我们程序的一部分,所以我们应该删除掉它。
+
+ $ rm public/hello.html
+
+我们先把index.html文件放一边,当然我们最终是要删除掉它的,我们可不想我们程序的根目录总是如图1.3所示那样的Rails默认页面。我们将会在第5.2节中学习如何让我们的地址“http://localhost:3000/”不指向public/index.html
+
+3.1.2 Rails静态页面
+
+
+可以返回静态页面是值得让人兴奋地,但是这对于开发一个动态web程序的来说并不是很有用。在这一节,我们学习创建动态页面的第一步:创建一些Rails的action方法,这些方法定义URL的能力比静态页面强很多。Rails的action方法在控制器里。第二章惊鸿一瞥的REST架构,我们将要在第六章深入的学习。本质上,controller是一组网页页面(可能是动态)的容器。
+
+我们从回忆第1.3.5节中,我们如何使用Git开始,将我们工作的内容单独放在一个分支里面比直接在master分支更值得我们借鉴。如果你使用Git版本控制,你可以运行一下代码
+
+ $ git checkout -b static-pages
+
+Rails里面我们可以使用一个Generate的脚本来创建控制器;他的神奇之处就在于我们所要做的只是想一个控制器的名称。
+由于我们的这个控制器主要用来处理静态页面,我们就叫他,Pages,而且我们希望给他几个action去响应Home page,contact page,和about page。我们可以在generate 脚本后面更上几个可选的参数作为actions,我们可以看到结果如下:
+
+ ruby 代码3.4创建Pages控制器
+
+ $ rails generate controller Pages home contact
+ create app/controllers/pages_controller.rb
+ route get "pages/contact"
+ route get "pages/home"
+ invoke erb
+ create app/views/pages
+ create app/views/pages/home.html.erb
+ create app/views/pages/contact.html.erb
+ invoke rspec
+ create spec/controllers/pages_controller_spec.rb
+ create spec/views/pages
+ create spec/views/pages/home.html.erb_spec.rb
+ create spec/views/pages/contact.html.erb_spec.rb
+ invoke helper
+ create app/helpers/pages_helper.rb
+ invoke rspec
+
+
+(注意,我们使用rails generate rspec:install来安装了Rspec所以,控制器自动在spec目录底下,生成了Rspec的测试文件。)。在这里,我故意遗忘了about page,我们可以在下一节3.2中学习如何手动添加它。
+代码3.4中生成控制器的时候已经更新了routes的文件(位于config/routes.rb),Rails用该文件来查找URL和网页之间的对应关系。这是我们第一次遇到config这个文件夹,所以我们应该来快速的过一遍这个文件夹(如图3.4)。这个文件夹是rails放置一些配置文件的目录,故称其名。
+
+![pic](http://ruby.railstutorial.org/images/figures/config_directory_rails_3.png)
+
+由于我们生成了home和contact的action方法,所以,routes文件已经为每一个action配置好了规则,如代码3.5:
+
+
+ ruby config/routes.rb page控制器中home和contact的路由规则
+
+ SampleApp::Application.routes.draw do
+ get "pages/home"
+ get "pages/contact"
+ .
+ .
+ .
+ end
+
+
+
+规则:
+
+
+ get "pages/home"
+
+
+
+映射了请求url:pages/home到Pages控制器的home方法。此外,使用get我们制定这个路由只会响应GET(一种HTTP协议(见Box3.1)支持的基础HTTP动作)的请求。对我们来说,我们在Pages的控制器中创建一个home的方法之后就自动的获得了一个页面地址“pages/home”,可以用Ctrl+C关闭服务器之后,重新启动(其实可以不用重启,rails的可以动态载入这些方法),然后访问pages/home(见图3.5)
+
+![pic](http://ruby.railstutorial.org/images/figures/raw_home_view.png)
+
+
+>**Box 3.1.GET和其他.**
+>HTTP协议定义了四种基本操作方式,分别是get,post, put, 和delete。这些是指在客户端和服务端之间的操作。(这个非常的重要,在开发中,一般客户端和服务器是同台机器,但是一般情况下,他们是不同的),强调HTTP动作是web框架(包括Rails)被REST架构影响的一个非常典型的特征。好处可以参考第2章,第八章会有深入的了解。
+
+>get是HTTP操作中最常用的一个,一般用于请求数据。
+它的意思就是“获取页面”,所以每次你访问google.com 或者craigslist.org 的时候,你的浏览器都是提交一个Get的请求。
+
+>下一个常用的操作是Post,它一般在提交一个表单的时候使用。
+
+>在rails里面Post的请求一般用于创建数据(尽管HTTP也允许post去实现更新。)
+
+>比如,当你提交一个注册表单之后就会在服务器那边创建一个新的用户。
+
+>另外2个操作时put和delete,前者用来更新远程服务器数据,后者用来删除数据。
+
+>这2个没有前面2个操作那么普遍,有的浏览器没有支持发送这样的请求,但是一些web的框架(包括rails)有自己的方法去实现,让他发送这中请求。
+
+>让我们从Pages的控制器开始看看,这些页面是哪里来的。如代码3.6所示(你可能注意到,这个和第二章中的Users和Microposts控制器有区别,这个控制器并没有遵循REST规则。)
+
+
+ ruby 代码 3.6代码3.4产生的控制器代码。
+ class PagesController < ApplicationController
+
+ def home
+ end
+
+ def contact
+ end
+ end
+
+我们看到pages_contoller.rb文件中定义了PagesController类。类是把功能(或方法,就像用def定义的home和contact方法一样。)组织起来的一种简单方法。尖括号“<”便是PacgesController从Rails的ApplicationContoller类;
+正如我们将看到,这说明了我们的网页装备了大量的Rails的特定功能(我们将会在第4.4节中学习类个继承。)
+在这里,控制器中页面的方法都是空的。
+在ruby里,这些方法什么都不做,但是在Rails里面却有点却别。PagesController是一个Ruby的类,但是由于他继承自ApplicationController。所以他的方法有一些特别。当我们访问URL /pages/home、 Rails寻找Pages的控制器,然后执行home的方法,然后渲染页面响应页面的动作。因为在上面home的方法是空的,所以他除了渲染页面之外什么也没做。所以页面应该什么样子,我们应该如何找到它呢。
+如果你再看看代码3.4的输出,你可能会猜出页面和方法之间的关系:一个方法如home页面对应一个视图如home.html.erb。我们将会在3.3中学“.erb”的意义。从".html"部分你也不用惊讶它看起来是基于HTML。
+
+ html app/views/pages/contact.html.erb
+ <h1>Pages#contact</h1>
+ <p>Find me in app/views/pages/contact.html.erb</p>
+
+
+
+
+contact方法类似:
+ html app/views/pages/contact.html.erb
+ <h1>Pages#contact</h1>
+ <p>Find me in app/views/pages/contact.html.erb</p>
+
+
+
+以上2个页面就类似占位符:一个顶级的h1标签,和一个包含了相关文件绝对路径的的P标签。我们从第3.3节开始学习添加一些动态(少量)的内容,但是他们说明了一个重要的知识:Rails的页面可以使只含有静态HTML的。只要浏览器链接,就很难区别开到底是由3.1.1中的静态页面显示,还是由控制器方法提供页面:因为浏览器都只看到HTML。
+在这一章剩下的内容,我们将学习在3.1.2中故意遗漏的“about”,添加非常少的动态内容,然后第一次涉及页面的CSS样式。在进入下面的学习之前,我们应该将变动添加到Git的库里面去。
+
+
+ $ git add .
+ $ git commit -am "Added a Pages controller"
+
+
+你或许想起来,我们再1.3.5节里面使用 git commit -a -m "Message"命令,用-a表示“all change”,用-m表示“信息”;git也允许我们将2个参数合到一起“-am”、我在本书中将会继续使用这种简写。
+
+###3.2 我们的第一个测试
+
+如果你去问五个 Rails 开发者如何去测试一段代码,你会得到15种不同的答案————不过他们都会认为写下测试代码是必要的。测试一段代码是一种精神,把一段心目中的想法写成测试而不用担心什么问题会让你的开发更佳完美。你也没有必要把 这里的测试方式当成是圣经,它们只不过是那些我从自己和我读到的代码中用到的东西。如果你想成为一个有经验的 Rails 开发者,你无疑在某日形成一个自己的测试开发风格的。
+
+另外,在我们的示例程序中我们编写测试程序用了一种最近很流行的方法 在开发前编写测试文件(when to write tests by writing them before the application code)————一种测试驱动开发的方法,也叫TDD。我们的应用将要增加一个 About 页面。不用担心,增加一个额外的页面并不难————你或许都已经通过上面的学习猜到答案了————但是这一次我们要著重于测试文件的编写。
+
+虽然为一个已经存在的界面进行测试似乎是有点闲的蛋疼,但是我的经验告诉我事实不是这样的。许多代码会写着写着就错了,有一个好的测试来约束你能够保证你的程序质量。另外,对于一个计算机程序来说,尤其是一个网络应用来说,扩展性是很重要的,这样每当你添加一个功能你都会面临一份程序写"跑题"了的危险。写下测试并不意味着程序中的bug会小时,而是让他们更容易被抓到和修复。而有的人确实会为抓bug而写测试。
+ (正如我们在1.1.1中说的那样,如果你发现测试非常的让你头疼,你完全可以只把教程中的Ruby on Rails 抽出来先学习,然后再自行学习测试方面的技巧).
+
+####3.2.1 测试工具
+
+ 为了给我们的示例程序进行测试,我们的主要工具是一个测试框架,叫做 [RSpec](http://rspec.info/),它使用“特别管理语言”来描述代码的行为,并判断代码是否完成了对应的工作。在Rails社区中,RSpec 测试Ruby程序十分高效,以至于 Obie Fernandez , The Rails 3 way 的作者把RSpec 叫做 “Rails必由之路”,我在这里也表示赞同。
+
+**autotest**
+
+Autotest 是一个在你更改程序的时候,在后台自动帮你进行测试的套件。例如,如果你把一个 controller 改了 ,Autoest 就立马会对那个controller对应的view进行测试,测试结果也会马上反馈回来。我们会在 3.2.2 学到更多关于 Autotest 的东西。
+
+安装 Autotest是可选的,不过安装Autotest 有点犯人,不过我保证当你发现它是多么的有用的时候你会觉得一些都是值得的。首先你要先安装一下 autotest 和 autotest-rails-pure 这两个gems
+
+ $gem install autotest -v 4.4.6
+ $gem install autotest-rails-pure -v 4.1.2
+
+(如果你在这里遇到了 “权限不够”的提示的话那你可能需要使用 sudo 命令来运行它们)。
+
+下一个步骤将要取决与你的系统平台,我会在这里用我的 OS X 来做演示,然后我会给出几篇关于安装在linux 和 windows方法 的 blog。在 OS X 上,你需要先安装 [Growl](http://growl.info/) 然后安装 auto-fsevent 和 autotest-growl 两个gems。
+
+ $ gem install autotest-fsevent -v 0.2.4
+ $ gem install autotest-growl -v 0.2.16
+
+如果fsevent安装除了问题的话 ,你最好检查一下 你机子上的 Xcode 是否正常工作。
+
+要想使用Growl 和 FSEvent 的Gem ,你需要把Autotest 的配置文件放到你的工作文件夹的根目录下面。并且在按如下方法添加一些文件内容:
+
+ $ mate .autotest
+
+配置文件需要加入:
+
+ require 'autotest/growl'
+ require 'autotest/fsevent'
+
+或者你可以加入:
+
+ require 'autotest-growl'
+ require 'autotest-fsevent'
+
+(这个设置文件只对你当前的应用程序起作用,如果你想要让你的所有 ruby 和rails 项目共享这一配置,你可以把这个 <code> .autotest </code>放到你的个人文件根目录下面去)
+
+ $ mate ~/.autotest
+
+如果你实在Linux的Gnome的桌面系统之下的话。我建议你尝试一下 这里([Automate Everything])的东西[http://automate-everything.com/2009/08/gnome-and-autospec-notifications/].通过它可以让你在 linux 上面运行和 OS X 差不多的 Growl 提示。至于 Windows 用户 ,你们可以尝试安装
+[Growl for Windows](http://www.growlforwindows.com/gfw/),然后跟着 [GitHub 的 autotest-growl页面](http://github.com/svoop/autotest-growl)来做。不管是linux还是windows的用户都应该看看[autotest-notification](http://github.com/carlosbrando/autotest-notification), Rails Tutorial 的读者 Fred Schoeneman 写了一篇[博文](http://fredschoeneman.posterous.com/pimp-your-autotest-notification)也很值得一看.
+
+####3.2.2 TDD:红灯,绿灯,重构
+
+对于测试驱动开发来说,我们通常会事先写一个失败的测试————失败意味着是不能通过。在我们这个例子当中,刚开始我们就会写一段验证:“应该会是 about page ”的页面测试代码,当然这个时候about页面没有出现,所以如果运行测试的就会失败。如果要想让测试通过,我们就应该加入和about页面对应的行为和视图。那为什么我们反过来做,先写功能,在做测试呢?这是为了保证我们确确实实加入了我们所需要的特性。在我刚开始使用 TDD 的时候,我先为我自己的程序中又那么多的错误感到惊讶,然后慢慢让测试出的错误消失,确保刚开始测试的失败然后再慢慢让它成功,我们就会慢慢对我们写出的代码更有信心。
+
+还有一点非常重要,TDD并非任何时候都使用的,尤其是,当你对某个问题还没有个确切的解决方法的时候。这时候通常会先忽略测试而直接完成功能代码(在极限编程 XP 中,这种试探性的步骤叫做 spike ),而一旦你发现了一个确切的方法去解决这个问题之后,你就可以重新用TDD来更优雅实现一个新的版本。
+
+“红,绿,重构 ”是在测试驱动开发中使用的方法,第一步:红,指的是写一个失败的测试,大部分测试工具会在这里以红色指出错误,第二步:绿,意味着测试通过,然后当我们的测试都成功通过之后我们就可以在不改变功能的条件下随意的重构我们的代码:删除重复,更改设计模式等等。
+
+当然现在我们还什么颜色都没有,让我们先从红色开始把,RSpec(其他的测试工具也一样)在刚开始可能又一些吓人,我们这里先从 rails generate controller pages (Listing3.4) 开始。这里因为我不太喜欢把 views/helpers 分离出来测试(我觉得这样很多余),我们的第一步就是把他们移除掉。如果你在使用 Git ,你可以这么做:
+
+ $git rm -r spec/views
+ $git rm -r spec/helpers
+
+然后我们再把文件也移除了:
+
+ $ rm -rf spec/views
+ $ rm -rf spec/helpers
+
+在开始前,我们来看看我们刚刚建立的 Page 的Controller 的 spec
+
+ ruby spec/controllers/pages_controller_spec.rb
+ require 'spec_helper'
+
+ describe PagesController do
+
+ describe "GET 'home'" do
+ it "should be successful" do
+ get 'home'
+ response.should be_success
+ end
+ end
+
+ describe "GET 'contact'" do
+ it "should be successful" do
+ get 'contact'
+ response.should be_success
+ end
+ end
+ end
+
+这是纯粹的Ruby代码,但是即使你学习过Ruby你恐怕也不能看明白这些东西是什么意思。这是因为RSpec为了测试专门为Ruby语言进行了扩展,用的是一种 “domain-specific-language”(DSL)语言,这种语言的特点就是你完全不知道它的语法也可以使用RSpec,刚开始这或许看起来会有点不可思议,但是没有关系,Rspec 测试脚本读起来基本就和英语一样,如果你已经做了前面的那些 generate 和 实例程序之后我想搞定它也不难。
+
+上面的代码中包括了两个 <code> describe </code> 代码块,他们与我们的 example 一一对应,这里我们先来看看第一个 describe 是怎么回事。
+
+ ruby
+ describe "GET 'home'" do
+ it "should be successful" do
+ get 'home'
+ response.should be_success
+ end
+ end
+
+在这里,第一行指出我们正在对于 HOME 页面进行一个 GET 操作,这仅仅是一个描述性的语句,你完全可以在这里写任何你想要的东西,RSpec不会在乎的(其他人类会在乎的)。在这里 GET ‘home’ 指的是测试 HOME 相对应的 HTTP GET 请求,如同 上面 BOX 3.1 中讨论的那样。然后 RSpec 说如果你你访问了 HOME 页面,应该能够成功返回。这里的第一行其实和测试行为完全不相干的,仅仅是是对人类读者的一种描述行记录。第三行 <code>get ‘home’</code> 在这里RSpec才真正开始干活了,这里RSpec会先提交一个 GET 请求,换一句话说,在此时RSpec相当于打开浏览器并且链到你的网页上,这个网页就是你的 ** /PAGES/HOME ** (RSpec之所以知道控制器是 PAGES 因为我们在做的是 PAGES CONTROLLERS 的测试,访问HOME 则是因为你明确告诉了它)。最后,第四行告诉它这个页面应该会成功的返回(也就是说他应该返回一个状态码 200 )
+
+>**Box 3.2 HTTP 返回码**
+
+
+>在一个客户端(例如浏览器)发送了一个HTTP的动词请求的时候,网络服务器会在返回的时候加上一段数字代码来作为 HTTP 状态字。例如状态字 200 意味着 “成功”,状态字301 意味着 “静态跳转” ,如果你安装了 curl ,一个可以解析HTTP请求的命令行客户端,你就可以直接看到状态字。例如访问 <code> www.google.com </code>
+
+> $ curl --head www.google.com
+> HTTP/1.1 200 OK
+> .
+> .
+> .
+
+>在这里谷歌就成功完成了你的请求并且返回了状态码 200 OK .同样, GOOGLE.com 会静态的跳转到 www.google.com 所以他会指向一条 301 的状态码 (301 跳转)
+
+> $ curl --head google.com
+ HTTP/1.1 301 Moved Permanently
+ Location: http://www.google.com/
+ .
+ .
+ .
+>(注意,这个范例将会随着你的国家不同而又很大差别。。。)
+
+>当我们在RSpec 的测试文件里面写了 response.should be_success ,RSpec会识别出我们的应用返回了一个正确的 200代码。
+
+现在是时候让我们的测试跑起来了。这里有几种不同的方法来运行测试(但是总体上大同小异)。第一种方法是在命令行里运行 rspec 脚本,像这样
+
+ $ bundle exec rspec spec/
+ ....
+
+ Finished in 0.07252 seconds
+
+ 2 examples, 0 failures
+
+(不幸的事,很多事情可能让你在这个时候运行出 fail ,如果你中枪了,你可以尝试着用命令 “bundle exec rake db:migrate” 来 migrate 一下数据库。如果rspec还是不工作,那你恐怕就要重新卸载安装数据库了:
+
+ $ gem uninstall rspec rspec-rails
+ $ bundle install
+
+如果这也不行你那你恐怕就要用 RVM 来重新卸载安装你的 gems 了:
+
+ $ rvm gemset delete rails3tutorial
+ $ rvm --create use 1.9.2@rails3tutorial
+ $ rvm --default 1.9.2@rails3tutorial
+ $ gem install rails -v 3.0.11
+ $ bundle install
+
+如果这也不行,那我也没办法了 -_- .)
+
+当你运行了 <code>bundle exec rspec spec/</code> 的时候, rspec 是作为一个由Rspec提供的程序来运行的,而 spec/ 是一个你所需要测试的目录。你也可以 rspec 只运行测试一个目录下的文件例如这个例子就运行spec测试了 controller :
+
+ $ bundle exec rspec spec/controllers/
+ ....
+ Finished in 0.07502 seconds
+
+ 2 examples, 0 failures
+
+你甚至可以运行一个单独的文件
+
+ $ bundle exec rspec spec/controllers/pages_controller_spec.rb
+ ....
+ Finished in 0.07253 seconds
+
+ 2 examples, 0 failures
+
+注意,在这里我们再一次运用了 bundle exec 来执行我们的命令(bundle exec 可以以Gemfile中指定的gems版本来执行命令),因为这样命令看起来有一点冗长,所以 Bundler 允许创建二进制的程序集例如这样:
+
+ $ bundle install --binstubs
+
+这样一来所有需要的gems执行程序都将会生成到 bin/ 文件夹下面去。我们现在就可以直接这样运行:$
+
+ bin/rspec spec/
+
+rake也一样:
+
+ $ bin/rake db:migrate
+
+对于不想这么做的朋友们,那么在将来的课程里你们恐怕需要都用 bundle exec 来运行这些特定的命令了(当然也可以选择这个简单些的办法.)
+
+由于这个页面控制器目前是我们唯一的测试文件,所以这三个命令应该输出都是一样的。在剩下的教程里面,我们不会把运行test的命令行打出来,但是你自己要知道用bundle exec rspec spec/ (或者其他的东西),或者自己用autotest之类的东西。
+
+如果你安装了 Autotest 你可以自动进行的RSpec测试:
+
+ $ autotest
+
+如果你用的是 Mac 的 Growl 测试工具,你可以向我一样,如下图一样,autotest在后台运行,Growl 会提醒你当前测试的状态,这样用 TDD 是会上瘾的。
+
+![autotest](http://ruby.railstutorial.org/images/figures/autotest_green.png)
+
+####Spork
+
+在前面的例子里你可能已经注意到了,用这样的套件运行一次测试非常的慢(the overhead involved in running a test suite can be considerable.不知道是不是这意思)。这是因为每次运行RSpec来进行一次测试都会 Reload 一次 Rails 环境。Spork test server 就是针对这个问题产生的。
+
+
+
@wentGH
wentGH added a note

fff

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
+
+
Please sign in to comment.
Something went wrong with that request. Please try again.