续上篇:

一. 有点内容的静态页面

rails new 命令创建了一个布局文件, 不过现在最好不用。我们重命名这个文件:

$ mv app/views/layouts/application.html.erb layout_file    # 临时改动

注:在真实的应用中你不需要这么做,不过没有这个文件能让你更好地理解它的作用。

注:关于表题所需变动的部分

1. 添加标题

添加标题之前,我们要知道网页的一般结构,如下图所示:

我们要使用 assert_select 方法分别为app/views/static_pages中的每个标题编写简单的测试。assert_select 方法的作用是检查有没有指定的 HTML 标签。这种方法有时也叫“选择符”(selector),因此才为这个方法取这么一个名称。

assert_select "title", "Home | Ruby on Rails Tutorial Sample App"

这行代码的作用是检查有没有 <title> 标签,以及其中的内容是不是“Home | Ruby on Rails Tutorial Sample App”字符串。把这样的代码分别放到三个页面的测试中。

接下来测试 RED:

rails test

注:测试结果表明三个都没有

2.添加页面标题 Green:

打开文件:app/views/static_pages/home.html.erb(具有完整 HTML 结构的首页)

打开文件:app/views/static_pages/help.html.erb(具有完整 HTML 结构的“帮助”页面)

打开文件:app/views/static_pages/about.html.erb(具有完整 HTML 结构的“关于”页面)

现在再测试(Green):

注:通过!不过你可能注意到了, StaticPages 控制器的测试中有些重复,每个标题测试中都有“Ru-by on Rails Tutorial Sample App”。我们可以使用特殊的函数 setup 去除重复。这个函数在每个测试运行之前执行。下面有具体说明自己确认代码清单中的测试仍能通过。

打开文件:test/controllers/static_pages_controller_test.rb(使用一个基标题的 StaticPages 控制器测试)

3.布局和嵌入式 Ruby(重构)

到目前为止,我们已经做了很多事情,我们使用 Rails 控制器和动作生成了三个可用的页面,不过这些页面中的内容都是纯静态的 HTML,没有体现出 Rails 的强大之处。而且,代码中有大量重复:
• 页面的标题几乎(但不完全)是一模一样的;
• 每个标题中都有“Ruby on Rails Tutorial Sample App”;
• 整个 HTML 结构在每个页面都重复地出现了。
重复的代码违反了很重要的“不要自我重复”(Don’t Repeat Yourself,简称 DRY)原则。本节要遵照 DRY 原则,去掉重复的代码。最后,我们要运行前面编写的测试,确认显示的标题仍然正确。不过,去除重复的第一步却是要增加一些代码,让页面的标题看起来是一样的。这样我们就能更容易地去掉重复的代码了。在这个过程中,我们要在视图中使用嵌入式 Ruby(Embedded Ruby)。既然首页、“帮助”页面和“关于”页面的标题中有一个变动的部分,那我们就使用 Rails 提供的一个特别的函数 provide ,在每个页面中设定不同的标题。通过把 home.html.erb 视图中标题的“Home”换成下图所示的代码,我们可以看一下这个函数的作用。

打开文件:app/views/static_pages/home.html.erb(标题中使用了嵌入式 Ruby 代码的首页视图)

在这段代码中我们第一次使用了嵌入式 Ruby(简称 ERb)。(现在你应该知道为什么 HTML 视图文件的扩展名是 .html.erb 了。)ERb 是为网页添加动态内容使用的主要模板系统。下面的代码
<% provide(:title, 'Home') %>
通过 <% ... %> 调用 Rails 提供的 provide 函数,把字符串 "Home" 赋给 :title 。然后,在标题中,我们使用类似的符号 <%= ... %> ,通过 Ruby 的 yield 函数把标题插入模板中:
<title><%= yield(:title) %> | Ruby on Rails Tutorial Sample App</title>
(这两种嵌入式 Ruby 代码的区别在于, <% ... %> 只执行执行其中的代码; <%= ... %> 除了执行其中的代码,还会把执行的结果插入模板中。)最终得到的页面跟以前一样,不过,现在标题中变动的部分通过 ERb 动态生成。

注:相当于Python Django框架中的模板语法

现在运行一下测试,还是能通过的(Green)

注:既然可以,那就把"帮助"和"关于"页面也给改了呗

打开文件:app/views/static_pages/help.html.erb(标题中使用了嵌入式 Ruby 代码的“帮助”页面视图)

打开文件:app/views/static_pages/about.html.erb(标题中使用了嵌入式 Ruby 代码的“关于”页面视图)

至此,我们把页面标题中的变动部分都换成了 ERb。现在,各个页面的内容类似下面这样:

注:也就是说,所有页面的结构都是一样的,包括 title 标签中的内容,只有 body 标签中的内容有些差别

为了提取出共用的结构,Rails 提供了一个特别的布局文件,名为 application.html.erb 。我们在 3.4 节的开头重命名了这个文件,现在改回来:

$ mv layout_file app/views/layouts/application.html.erb

若想使用这个布局,我们要把默认的标题换成前面几段代码中使用的嵌入式 Ruby:

<title><%= yield(:title) %> | Ruby on Rails Tutorial Sample App</title>

修改后得到的布局文件如下所示。

注意,其中有一行比较特殊:
<%= yield %>
这行代码的作用是,把每个页面的内容插入布局中。没必要了解它的具体实现过程, 我们只需知道, 在布局中使用这行代码后, 访问 /static_pages/home 时会把 home.html.erb 中的内容转换成 HTML,然后插入 <%=yield %> 所在的位置。 还要注意,默认的 Rails 布局文件中有下面这几行代码:
<%= csrf_meta_tags %>
<%= stylesheet_link_tag ... %>
<%= javascript_include_tag "application", ... %>
这几行代码的作用是, 引入应用的样式表和 JavaScript 文件;Rails 提供的 csrf_meta_tags 方法,作用是避免跨站请求伪造(Cross-Site Request Forgery,简称 CSRF,一种恶意网络攻击)。
现在, "首页", "帮助", "关于"的内容还是和布局文件中的 HTML 结构类似,所以我们要把完整的结构删除, 只保留需要的内容。清理后的视图如下所示:

打开文件:app/views/static_pages/home.html.erb(去除完整的 HTML 结构后的首页)

打开文件:app/views/static_pages/help.html.erb(去除完整的 HTML 结构后的“帮助”页面)

打开文件:app/views/static_pages/about.html.erb(去除完整的 HTML 结构后的“关于”页面)

注:修改这几个视图后, “首页”, “帮助”页面和“关于”页面显示的内容还和之前一样, 但是没有多少重复内容了。

经验告诉我们, 即便是十分简单的重构, 也容易出错, 所以才要认真编写测试组件。有了测试, 我们就无需手动检查每个页面, 看有没有错误。初期阶段手动检查还不算难, 但是当应用不断变大之后, 情况就不同了。我们只需验证测试组件是否还能通过即可:

注:测试不能证明代码完全正确,但至少能提高正确的可能性,而且还提供了安全防护措施,能避免以后出问题。

自己尝试着添加一个“联系”页面:

4.设置根路由

我们修改了网站中的页面,也顺利开始编写测试了,在继续之前,我们要设置应用的根路由。与前面的做法一样,我们要修改 routes.rb 文件,把根路径 / 指向我们选择的页面。这里我们要指向前面创建的首页。(我还建议把前面节添加的 hello 动作从 Application 控制器中删除。)如下所示,我们要把 root 规则由
root 'application#hello'
改成
root 'static_pages#home'
这样对 / 的请求就交给 StaticPages 控制器的 home 动作处理了。修改路由后,首页如下图所示。

添加上图中的根路由后, 会得到一个名为 root_url 的辅助方法(与 static_pages_home_url类似)。修改测试文件, 测试根路由

。。。

今天先到这吧,做个总结:

二. 总结

• 执行 rails generate controller ControllerName <optional action names> 命令会生成一个新控制器;
• 在 config/routes.rb 文件中定义了新路由;
• Rails 的视图中可以包含静态 HTML 或嵌入式 Ruby(ERb);
• 测试组件能驱动我们开发新功能, 给我们重构的自信, 还能捕获回归;
• 测试驱动开发使用“遇红-变绿-重构”循环;
• Rails 的布局定义应用中页面共用的模板, 可以去除重复。

Ruby Rails学习中:有点内容的静态页面的更多相关文章

  1. Ruby Rails学习中:Sass 和 Asset Pipeline,布局中的链接(Rails路由,具名路由),用户注册: 第一步

    接上篇: 一.Sass 和 Asset Pipeline Rails 中最有用的功能之一是 Asset Pipeline, 它极大地简化了静态资源文件(CSS.JavaScript 和图像)的生成和管 ...

  2. Ruby Rails学习中:网站导航,Bootstrap和自定义的CSS,局部视图

    添加一些结构 一.网站导航 1.添加一些结构后的网站布局文件 打开文件:app/views/layouts/application.html.erb 简单介绍一下,添加的代码: 我们从上往下看一下这段 ...

  3. Ruby Rails学习中:登陆

    登陆 一. Sessions 控制器 登录和退出功能由 Sessions 控制器中相应的 REST 动作处理 : 登录表单在 new 动作中处理, 登录的过程是向 create 动作发送 POST 请 ...

  4. Ruby Rails学习中:注册表单,注册失败,注册成功

    接上篇 一. 注册表单 用户资料页面已经可以访问了, 但内容还不完整.下面我们要为网站创建一个注册表单. 1.使用 form_for 注册页面的核心是一个表单, 用于提交注册相关的信息(名字.电子邮件 ...

  5. Ruby Rails学习中:调试信息和 Rails 的三种环境,Users 资源,调试器,Gravatar 头像和侧边栏

    注册 一.调试信息和 Rails 环境 现在咱们要实现的用户资料页面是我们这个应用中第一个真正意义上的动态页面.虽然视图的代码不会动态改变, 不过每个用户资料页面显示的内容却是从数据库中读取的.添加动 ...

  6. Ruby Rails学习中:添加安全密码

    接上篇 一. 添加安全密码 我们已经为 name 和 email 字段添加了验证规则, 现在要加入用户所需的最后一个常规属性: 安全密码.每个用户都要设置一个密码(还要二次确认), 数据库中则存储经过 ...

  7. Ruby Rails学习中:Ruby内置的辅助方法,基础内容回顾补充

    一. Ruby内置的辅助方法 1.打开文件:app/views/layouts/application.html.erb(演示应用的网站布局) 来咱把注意力放在圈起来的那一行: 这行代码使用 Rail ...

  8. Ruby Rails学习中:User 模型,验证用户数据

    用户建模 一. User 模型 实现用户注册功能的第一步是,创建一个数据结构,用于存取用户的信息. 在 Rails 中,数据模型的默认数据结构叫模型(model,MVC 中的 M).Rails 为解决 ...

  9. Ruby Rails学习中:关于测试的补充,MiniTest报告程序,Guard自动测试

    一. 关于测试的补充 1.MiniTest报告程序 为了让 Rails 应用的测试适时显示红色和绿色,我建议你在测试辅助文件中加入以下内容: (1).打开文件:test/test_helper.rb ...

随机推荐

  1. DOM操作的性能优化

    DOM操作的真正问题在于 每次操作都会出发布局的改变.DOM树的修改和渲染. React解决了大面积的DOM操作的性能问题,实现了一个虚拟DOM,即virtual DOM,这个我们一条条讲. 所以关于 ...

  2. 解决“mysql不是内部/外部命令,也不是可执行程序,也不是批处理文件”

    解决方案: 1.切换到mysql.exe文件所在目录: 2.将mysql.exe文件所在目录添加到操作系统内的环境变量中: 如何添加环境变量: 1.右击“我的电脑”——>属性——>高级—— ...

  3. 1.ibatis核心类

  4. WordPress窗体化侧边栏

    窗体化侧边栏是一个支持 Widget 的侧边栏或者说是窗体化(widgetized)的侧边栏几乎是 WordPress 主题的标准. 首先,什么是窗体化(widgetizing)呢?简单的说,窗体化就 ...

  5. jQuery九类选择器

    目的:通过选择器,能定位web页面(HTML/JSP/XML)中的任何标签, 注意:项目中,通常是多种选择器一起使用 基本选择器 <html> <head> <meta ...

  6. grivaty,margin和padding的区别

    layout_margn是指组件距离父窗体的距离, padding是指组件中的内容距离组件边缘的距离 Layout_grivaty与grivaty的区别 layout_grivaty是指组件相对父窗体 ...

  7. Rvm 进行gem安装时必须输入密码Your user account isn't allowed to install to the system RubyGems 解决方案

    今天开发过程中,从master拉下代码后重启项目,想用控制台时,却发现需要密码??并且三次密码确认后还是疯狂报错. 当时第一想到是rvm版本不一致,随即则检查了版本跟gem生成,当确认rvm版本无误时 ...

  8. 一百二十三:CMS系统之登录功能

    配置文件中加入前台用户的身份标识 form class SigninForm(BaseForm): telephone = StringField(validators=[Regexp(r'1[345 ...

  9. Python新利器之pipenv

    前言 之前学习异步asyncio库的时候,因为asyncio库支持Python3.5以上的版本,而我的Ubuntu14.04只有Python3.4,虽然下载了Python3.6,但是想直接利用ipyt ...

  10. Scala语法01 - 基础语法