# 4.1 导言
从前一章得知,即使完全不懂 Ruby 语言,我们也可以创建 Rails 应用的骨架,以及编写测试。我们依赖于书中提供的测试代码,得到错误信息,然后让测试组件通过。但是我们不能总是这样,所以这一章暂时不讲网站开发,而要正视我们的短肋——Ruby 语言。
前一章末尾我们修改了几乎是静态内容的页面,让它们使用 Rails 布局,去除视图中的重复。我们使用的布局如[代码清单 4.1](#listing-application-layout-redux) 所示(和[代码清单 3.32](chapter3.html#listing-application-layout) 一样)。
##### 代码清单 4.1:演示应用的网站布局
app/views/layouts/application.html.erb
```
<!DOCTYPE html>
<html>
<head>
<title><%= yield(:title) %> | Ruby on Rails Tutorial Sample App</title>
<%= stylesheet_link_tag 'application', media: 'all',
'data-turbolinks-track' => true %>
<%= javascript_include_tag 'application', 'data-turbolinks-track' => true %>
<%= csrf_meta_tags %>
</head>
<body>
<%= yield %>
</body>
</html>
```
我们把注意力集中在上述代码中的这一行:
```
<%= stylesheet_link_tag "application", media: "all",
"data-turbolinks-track" => true %>
```
这行代码使用 Rails 内置的方法 `stylesheet_link_tag`(详细信息参见 [Rails API 文档](http://api.rubyonrails.org/classes/ActionView/Helpers/AssetTagHelper.html#method-i-stylesheet_link_tag)),在所有[媒介类型](http://www.w3.org/TR/CSS2/media.html)中引入 `application.css`。对有经验的 Rails 开发者来说,这行代码看起来很简单,但是其中至少有四个 Ruby 知识点可能会让你困惑:内置的 Rails 方法,调用方法时不用括号,符号和哈希。这几点本章都会介绍。
Rails 除了提供很多内置的方法供我们在视图中使用之外,还允许我们自己定义。自己定义的方法叫辅助方法(helper)。为了说明如何自己定义辅助方法,我们来看看[代码清单 4.1](#listing-application-layout-redux) 中标题那一行:
```
<%= yield(:title) %> | Ruby on Rails Tutorial Sample App
```
这行代码要求每个视图都要使用 `provide` 方法定义标题,例如:
```
<% provide(:title, "Home") %>
<h1>Sample App</h1>
<p>
This is the home page for the
<a href="http://www.railstutorial.org/">Ruby on Rails Tutorial</a>
sample application.
</p>
```
那么,如果我们不提供标题会怎样呢?标题一般都包含一个公共部分,如果想更具体些,可以再加上变动的部分。我们在布局中用了个小技巧,基本上已经实现了这样的标题。如果在视图中不调用 `provide` 方法,也就是不提供变动的部分,那么得到的标题会变成:
```
| Ruby on Rails Tutorial Sample App
```
标题中有公共部分,但前面还显示了竖线。
为了解决这个问题,我们要自定义一个辅助方法,命名为 `full_title`。如果视图中没有定义页面的标题,`full_title` 返回标题的公共部分,即“Ruby on Rails Tutorial Sample App”;如果定义了,则在变动部分后面加上一个竖线,如[代码清单 4.2](#listing-title-helper) 所示。[[1](#fn-1)]
##### 代码清单 4.2:定义 `full_title` 辅助方法
app/helpers/application_helper.rb
```
module ApplicationHelper
# 根据所在的页面返回完整的标题
def full_title(page_title = '')
base_title = "Ruby on Rails Tutorial Sample App"
if page_title.empty?
base_title
else
page_title + " | " + base_title
end
end
end
```
现在,这个辅助方法定义好了,我们可以用它来简化布局。把下面这行:
```
<title><%= yield(:title) %> | Ruby on Rails Tutorial Sample App</title>
```
改成:
```
<title><%= full_title(yield(:title)) %></title>
```
如[代码清单 4.3](#listing-application-layout-full-title) 所示。
##### 代码清单 4.3:使用 `full_title` 辅助方法的网站布局 GREEN
app/views/layouts/application.html.erb
```
<!DOCTYPE html>
<html>
<head>
<title><%= full_title(yield(:title)) %></title>
<%= stylesheet_link_tag 'application', media: 'all',
'data-turbolinks-track' => true %>
<%= javascript_include_tag 'application', 'data-turbolinks-track' => true %>
<%= csrf_meta_tags %>
</head>
<body>
<%= yield %>
</body>
</html>
```
为了让这个辅助方法起作用,我们要在首页的视图中把不必要的单词“Home”删掉,只保留标题的公共部分。首先,我们要修改测试代码,如[代码清单 4.4](#listing-home-base-title-spec) 所示,确认标题中没有 `"Home"`。
##### 代码清单 4.4:修改首页的标题测试 RED
test/controllers/static_pages_controller_test.rb
```
require 'test_helper'
class StaticPagesControllerTest < ActionController::TestCase
test "should get home" do
get :home
assert_response :success
assert_select "title", "Ruby on Rails Tutorial Sample App" end
test "should get help" do
get :help
assert_response :success
assert_select "title", "Help | Ruby on Rails Tutorial Sample App"
end
test "should get about" do
get :about
assert_response :success
assert_select "title", "About | Ruby on Rails Tutorial Sample App"
end
end
```
我们要运行测试组件,确认有一个测试失败:
##### 代码清单 4.5:**RED**
```
$ bundle exec rake test
3 tests, 6 assertions, 1 failures, 0 errors, 0 skips
```
为了让测试通过,我们要把首页视图中的 `provide` 那行删除,如[代码清单 4.6](#listing-home-page-base-title) 所示。
##### 代码清单 4.6:没定义页面标题的首页视图 GREEN
app/views/static_pages/home.html.erb
```
<h1>Sample App</h1>
<p>
This is the home page for the
<a href="http://www.railstutorial.org/">Ruby on Rails Tutorial</a>
sample application.
</p>
```
现在测试应该可以通过了:
##### 代码清单 4.7:**GREEN**
```
$ bundle exec rake test
```
(注意,之前运行 `rake test` 时都显示了通过和失败测试的数量,为了行文简洁,从这以后都会省略这些数据。)
和引入应用的样式表那行代码一样,[代码清单 4.2](#listing-title-helper) 的内容对有经验的 Rails 开发者来说也很简单,但其中很多重要的 Ruby 知识:模块,方法定义,可选的方法参数,注释,本地变量赋值,布尔值,流程控制,字符串拼接和返回值。本章会一一介绍这些知识。
- Ruby on Rails 教程
- 致中国读者
- 序
- 致谢
- 作者译者简介
- 版权和代码授权协议
- 第 1 章 从零开始,完成一次部署
- 1.1 简介
- 1.2 搭建环境
- 1.3 第一个应用
- 1.4 使用 Git 做版本控制
- 1.5 部署
- 1.6 小结
- 1.7 练习
- 第 2 章 玩具应用
- 2.1 规划应用
- 2.2 用户资源
- 2.3 微博资源
- 2.4 小结
- 2.5 练习
- 第 3 章 基本静态的页面
- 3.1 创建演示应用
- 3.2 静态页面
- 3.3 开始测试
- 3.4 有点动态内容的页面
- 3.5 小结
- 3.6 练习
- 3.7 高级测试技术
- 第 4 章 Rails 背后的 Ruby
- 4.1 导言
- 4.2 字符串和方法
- 4.3 其他数据类型
- 4.4 Ruby 类
- 4.5 小结
- 4.6 练习
- 第 5 章 完善布局
- 5.1 添加一些结构
- 5.2 Sass 和 Asset Pipeline
- 5.3 布局中的链接
- 5.4 用户注册:第一步
- 5.5 小结
- 5.6 练习
- 第 6 章 用户模型
- 6.1 用户模型
- 6.2 用户数据验证
- 6.3 添加安全密码
- 6.4 小结
- 6.5 练习
- 第 7 章 注册
- 7.1 显示用户的信息
- 7.2 注册表单
- 7.3 注册失败
- 7.4 注册成功
- 7.5 专业部署方案
- 7.6 小结
- 7.7 练习
- 第 8 章 登录和退出
- 8.1 会话
- 8.2 登录
- 8.3 退出
- 8.4 记住我
- 8.5 小结
- 8.6 练习
- 第 9 章 更新,显示和删除用户
- 9.1 更新用户
- 9.2 权限系统
- 9.3 列出所有用户
- 9.4 删除用户
- 9.5 小结
- 9.6 练习
- 第 10 章 账户激活和密码重设
- 10.1 账户激活
- 10.2 密码重设
- 10.3 在生产环境中发送邮件
- 10.4 小结
- 10.5 练习
- 10.6 证明超时失效的比较算式
- 第 11 章 用户的微博
- 11.1 微博模型
- 11.2 显示微博
- 11.3 微博相关的操作
- 11.4 微博中的图片
- 11.5 小结
- 11.6 练习
- 第 12 章 关注用户
- 12.1 “关系”模型
- 12.2 关注用户的网页界面
- 12.3 动态流
- 12.4 小结
- 12.5 练习