- 浏览: 10743 次
- 来自: ...
最新评论
据说这是欧莱礼下一版的封面。。。
创建静态页面
静态页面,究竟要干啥的?我们的页面总需要添加一些,这网站谁做的阿 (about),这网站怎么用阿 (help),这网站怎么回首页阿 (home)。。。等等,这些比较不会变化的页面,吾人称之为静态页面。
首先就先来实现刚刚说的这些页面,让我们先来创一个平行时空吧,沈佳怡。。。:
git checkout -b static_pages
-b 是新建分支并切换到该分支。
再来让我们复习一下 MVC,当一个尊敬的用户,打开浏览器,浏览你的网站时,会发送请求给你,Rails 有一个 Rails 路由,看了看你要去哪,交给相对应的控制器的动作,控制器跟模型要资料(如果需要的话),模型去数据库取出来,丢回给控制器,控制器传给视图,视图返回 HTML 给控制器,控制器再丢回给尊敬的用户。
创建 HOME 与 HELP 页面
当你创建一个 Rails 应用时,路由已经是标配了,你所需要做的呢,是产生控制器、视图以及模型。好的,先让我们产生一个控制器,让它来帮我们处理这些静态页面的请求:
rails generate controller StaticPages home help --no-test-framework
就跟买咖啡一样,说你要什么、不要什么。。。我们产生了什么呢:
create app/controllers/static_pages_controller.rb
route get "static_pages/help"
route get "static_pages/home"
invoke erb
create app/views/static_pages
create app/views/static_pages/home.html.erb
create app/views/static_pages/help.html.erb
invoke helper
create app/helpers/static_pages_helper.rb
invoke assets
invoke coffee
create app/assets/javascripts/static_pages.js.coffee
invoke scss
create app/assets/stylesheets/static_pages.css.scss
首先呢,产生了一个控制器,叫做 StaticPages 带有 home、help 动作,以及相对应的路由、视图,一个 helper、一个 coffeescript 及 sass 文件,不要缺省的测试框架,换了谭浩强来输入上面那条命令也是一样的结果,嘿嘿。。。
谭浩强:中国 C 语言之父。
假如有一天,你因为不明原因,只能用右手打字,哎呀、、、手误了,该怎么办?放心,有 generate 也有相对的 destroy 可以让你还原产生的东东:
rails destroy controller StaticPages home help
模型比照办理,如 rails destroy model Foo
让我们打开一下 config/routes.rb 看看,到底路由是加没加(注释暂时忽略)?
XWeibo::Application.routes.draw do
get "static_pages/home"
get "static_pages/help"
end
阿哈,它替我们创好了当有一个要到 URI static_pages/home 这样的 GET 请求时,把它交给 StaticPages 控制器的 home 动作处理。
HTTP 动词复习
这是用户(通常是浏览器,如火狐、Safari)与服务器(Apache、Nginx)之间的用语,请注意,你的电脑可以同时扮演两个角色。他们之间的沟通用语就是 GET, POST, PUT, DELETE。
GET 请求: 读取 ,比如到某个网站的首页,要求页面
POST 请求: 创建 ,比如填入表单所发送的请求
PUT 请求: 更新 ,比如更新用户信息。
DELETE 请求: 摧毁 ,比如不喜欢这个帐号?删除它。
有的人会说 PUT 跟 POST,也可以花插儿著用,恩可以,HTTP 允许 POST 来做更新。但在 Rails 应用的上下文里,POST 通常是拿来创建新东西。
好了,让我们再来看看控制器里有些什么:
class StaticPagesController < ApplicationController
def home
end
def help
end
end
这里可以看到,定义了一个类别 StaticPagesController 继承 (<)自 ApplicationController,并带有两个方法,方法由 def 关键字定义,这其实隐含了很多 Rails 帮你写好的代码。
然而这两个动作怎么啥都没有呢?在 Ruby 里,这两个方法啥也不干。在 Rails 呢,即便是没写内容的方法 home,最基本也会去渲染一个视图 ( app/views/static_pages/home.html.erb )。
让我们打开服务器一探究竟,我们总是有著无止尽的好奇心:
rails server
打开浏览器,看看这两个页面
http://localhost:3000/static_pages/home.html
http://localhost:3000/static_pages/help.html
home-help
这两个页面实际上就是 Rails 替我们产生的,相当简单的 HTML,各有一个 h1 标题标签,以及一个段落标签 p。
<h1>StaticPages#home</h1>
<p>Find me in app/views/static_pages/home.html.erb</p>
<h1>StaticPages#help</h1>
<p>Find me in app/views/static_pages/help.html.erb</p>
而 http://localhost:3000/ 是 Rails 标准的欢迎画面,相信你已经相当熟悉了。
很好、很好,到这里先存档一下吧、我得去上个厕所:
git add .
git commit -m 'Add a StaticPages controller'
撰写第一个测试
厕所上回来啦。。。还买了罐啤酒,BDD (aka Beer-driven Development) 嘛。。。啤酒少不了的。
如同之前说过的,这个应用会是由 BDD 的方式来做开发。所以现在让我们来写测试吧,当然,不用先写测试也可以,要理解到,虽然写测试有很多好处,但是人是活的,码是死的,我管不住你。。。
之后的流程,我们会先写一个失败的测试,撰写代码使其通过,再进行重构。
测试、编码、修改、重构。
第一步让我们先来产生测试:
rails generate integration_test static_pages
可以看到 Rails 调用了 rspec 帮我们产生了一个测试文件:
invoke rspec
create spec/requests/static_pages_spec.rb
让我们加入 Home 页面的测试代码,你会发现里面已经有代码了,使用如下代码替换:
spec/requests/static_pages_spec.rb
require 'spec_helper'
describe "Static pages" do
describe "Home page" do
it "should have the content '新微博'" do
visit '/static_pages/home'
page.should have_content('新微博')
end
end
end
让我来解释一下这个测试,我们有一个测试静态页面的 describe 区块
describe "Static pages" do
首先我们测的是 Home 页面
describe "Home page" do
里面有一个测试:
it "should have the content '新微博'" do
visit '/static_pages/home'
page.should have_content('新微博')
end
这个测试就跟英文一样,它说当我们来到 /static_pages/home 这个页面时,应该要看到新微博这个内容。这里的 visit 使用到了,我们之前安装的 capybara gem 的一个 visit 方法、page 也是由 capybara gem 提供的变量。
这些 describe, it 高抽象化的语言是 RSpec 写好,供你使用的 DSL 方法,搭配 capybara 使用来达到测试驱动开发的目的,一开始可能会觉得不太自在,但先不要纠结于是怎么实现的,用的熟练后回头看,自然而然就理解了。
OK,现在让我们来运行看看
bin/rspec spec/requests/static_pages_spec.rb
first-fail
阿哈,我们有了第一个失败测试,很好,这样让我们知道下一步该怎么走。
错误信息告诉我们 Home 页面缺少了 新微博 这个内容,让我们打开 app/views/static_pages/home.html.erb ,并添加如下内容:
<h1>新微博</h1>
<p>
神秘的X项目<a href="http://ruby-china.org">新微博</a> Rails 示例教学
</p>
再运行一次测试:
bin/rspec spec/requests/static_pages_spec.rb
这时候应该看到测试通过:
first-pass
接下来让我们加入帮助信息的页面,一样先写个测试,在 static_pages_spec.rb 的 describe "Static pages" 区块中加入:
describe "Help page" do
it "should have the content '帮助'" do
visit '/static_pages/help'
page.should have_content('帮助')
end
end
呵呵,这个测试基本上跟刚刚一样,只不过改了几个小地方,下一步要做什么呢?让我们运行测试看看:
bin/rspec spec/requests/static_pages_spec.rb
help-fail
到这会儿你应该可以体会出,我很傻帽或者是测试带来的好处,首先我们构思我们的页面要实现什么功能,撰写一个测试,运行测试、编码。而每个测试之间的相似性很高,互相可以重用。
好的,现在让我们打开 app/views/static_pages/help.html.erb,添加:
app/views/static_pages/help.html.erb
<h1>帮助</h1>
<p>
更多相关 Ruby on Rails 帮助,请莅临
<a href="http://ruby-china.org">Ruby-china</a>.
本示例教程教学文章:
<a href="http://ruby-china.org/topics/3239">1000 小时学会 Rails 系列</a>.
</p>
呵呵,有了测试以后就像是傻瓜开发一样,so simple!
我们的 Home 与 Help 页面做好啦!
加入关于页面
现在让我们加入一下关于页面,哎呀,看起来我刚刚似乎产生控制器的时候,忘了加入 about 页面了:
rails generate controller StaticPages home help --no-test-framework
呵呵,其实我是故意的,我们自己走一遍这个流程就可以了解 rails 命令背后到底偷偷摸摸干了啥,一样我们先来写个测试:
describe "About page" do
it "should have the content '关于新微博" do
visit '/static_pages/about'
page.should have_content('关于新微博')
end
end
这个测试跟刚刚两个基本一模一样,将这个测试加至 static_pages_spec.rb ,你懂得,运行:
about-fail-no-route
哦,这次的错误信息不太一样,报错的是没有相应的路由:
No route matches [GET] "/static_pages/about"
若是 Rails 自动帮我们产生的话,Rails 会自动替你加路由、加相应的控制器动作、对应的视图。
让我们现在把这个路由加上,打开 config/routes.rb ,添加:
get "static_pages/about"
若是使用了 Spork 进阶配置的朋友,可能得重启 DRb 服务器哦,亲!
再运行测试看看,相信聪明如你已经猜到我们还没实现控制器的 about 动作:
about-fail-no-action
打开 app/controller/static_pages 添加 about 动作:
def about
end
现在先留白就很够用了,我们已经有从 Rails 的 ApplicationController 继承来的一堆东西可用了,这算不算是某种程度上的靠爸族呢。。。
about-fail-no-view
添加缺少的视图,在 app/views/static_pages 目录下创建 about.html.erb ,并填入:
<h1>关于新微博</h1>
<p>
新微博是使用 <a href="http://rubyonrails.org">Ruby on Rails</a> 技术所开发的微博,网络新纪元,微博新时代,你今天微勃了吗?
</p>
OK! 现在运行测试:
bin/rspec spec/requests/static_pages_spec.rb
都变成绿油油的一片,没有红色可怕的 F 了!这也就是为什么这个流程叫做 Red-Green-Refactor 。
现在让我们来看看有哪儿可以重构的。。。
重构!将 DRY 进行到底。。。
恩,我们都不喜欢单调,尤其是姿势,点缀生活,网站当然也一样,你发现到我们的标题老是一样么?Home, Help, About 页面的标题都是一样的,这样有点闷...
让我们看看如何让不同的页面有不同的标题,我们想要的是
title-table
OK. 现在让我们看看如何实现这个功能,首先我们先写个测试,来免去手动刷新的开发范式 (paradigm)...
打开 spec/requests/static_pages_spec.rb :
让我们添加一个新测试:
it "should have the title 'Home'" do
visit '/static_pages/home'
page.should have_selector('title',
:text => "Home | X Weibo")
end
这个测试该加在哪呢?这是一个关于 Home 页面的测试,合理地我们可以放在 describe "Home" 区块里。
我们首先访问首页 visit '/static_pages/home' ,页面应该有内容为 Home | X Weibo 的标题。
这个 have_selector 方法确认 title 标签的内容是不是 Home | X Weibo ...
这里 :text => "Home | X Weibo" 是 Ruby 的嘻哈哈希语法。
:text 是 Ruby 里的符号,作为哈希的键值使用。
另一件要提及的是代码的可读性。注意到:
page.should have_selector('title',
:text => "Home | X Weibo")
我们将
:text => "Home | X Weibo"
移到第二行,增加可读性。适当的缩排是提高可读性的不二法门。Ruby 不在乎多出来的空白及新行,最好是保持 每行 < 72 个字符,否则有可能会被 Linus 喷的体无完肤,呵呵。
让我们也添加 Help, About 页面的测试,现在整个 static_pages_spec.rb 看起来:
spec/requests/static_pages_spec.rb
# encoding: UTF-8
require 'spec_helper'
describe "Static pages" do
describe "Home page" do
it "should have the h1 '新微博'" do
visit '/static_pages/home'
page.should have_selector('h1', :text => '新微博')
end
it "should have the title 'Home'" do
visit '/static_pages/home'
page.should have_selector('title',
:text => "Home | X Weibo")
end
end
describe "Help page" do
it "should have the h1 '帮助'" do
visit '/static_pages/help'
page.should have_selector('h1', :text => '帮助')
end
it "should have the title 'Help'" do
visit '/static_pages/help'
page.should have_selector('title',
:text => "Help | X Weibo")
end
end
describe "About page" do
it "should have the h1 '关于新微博'" do
visit '/static_pages/about'
page.should have_selector('h1', :text => '关于新微博')
end
it "should have the title 'About'" do
visit '/static_pages/about'
page.should have_selector('title',
:text => "About | X Weibo")
end
end
end
注意我把每个页面比较暧昧不明的 have_content 换成 have_selector 。
好了,让我们运行测试看看:
bin/rspec spec/requests/static_pages_spec.rb
会看到三个测试 Fail 了,有著相似的错误信息:
Failure/Error: page.should have_selector('title',
expected css "title" with text "Home | X Weibo" to return something
阿哈,我们要对红通通失败的测试感到开心,因为我们知道错在那,可以改,不像谈恋爱那般。。。
在这之前,让我们回想一下之前,我们创建项目时输入的命令么:
rails new x_weibo --skip-test-unit --skip-bundle
这个命令也替我们产生了一个 app/views/layouts/application.html.erb layout 文件:
app/views/static_pages/application.html.erb
<!DOCTYPE html>
<html>
<head>
<title>XWeibo</title>
<%= stylesheet_link_tag "application", :media => "all" %>
<%= javascript_include_tag "application" %>
<%= csrf_meta_tags %>
</head>
<body>
<%= yield %>
</body>
</html>
这个文件就是咱 Rails 应用的骨架了,注意到中间的 <%= yield %>,我们的 Home, Help, About 页面会在调用 yield 时产生出来,这是 Rails 能够摆脱 那些年我们一起在网页里塞 PHP 代码 的精妙之处。
让我们先暂时把这个文件更名一下,先让它不起作用
mv app/views/layouts/application.html.erb foo
Windows 的命令貌似是 rename,不那么 Geek 手动更名也成。
好了,现在你启动服务器 (rails s),打开每个页面看看:
http://localhost:3000/static_pages/home
http://localhost:3000/static_pages/help
http://localhost:3000/static_pages/about
可以看到本来一样的标题都不见了,检视原始码发现甚至 HTML, DOCTYPE 那些标签都没了,相信你已经知道是怎么回事儿了,呵呵。
现在让我们分别实现每个页面的标题,首先是 Home 页面,打开 app/views/static_pages/home.html.erb ,让我们加上需要的 HTML ,让它成为一个完整的网页,并把标题改为我们要的样子:
app/views/static_pages/home.html.erb
<!DOCTYPE html>
<html>
<head>
<title>Home | X Weibo</title>
</head>
<body>
<h1>新微博</h1>
<p>
神秘的X项目<a href="http://ruby-china.org">新微博</a> Rails 示例教学
</p>
</body>
</html>
现在运行测试会发现失败的测试少了一个,让我们依样画葫芦改动 About 以及 Help 页面:
app/views/static_pages/help.html.erb
<!DOCTYPE html>
<html>
<head>
<title>Help | X Weibo</title>
</head>
<body>
<h1>帮助</h1>
<p>
更多相关 Ruby on Rails 帮助,请莅临
<a href="http://ruby-china.org">Ruby-china</a>.
本示例教程教学文章:
<a href="http://ruby-china.org/topics/3239">1000 小时学会 Rails 系列</a>.
</p>
</body>
</html>
app/views/static_pages/about.html.erb
<!DOCTYPE html>
<html>
<head>
<title>About | X Weibo</title>
</head>
<body>
<h1>关于新微博</h1>
<p>
新微博是使用 <a href="http://rubyonrails.org">Ruby on Rails</a> 技术所开发的微博,网络新纪元,微博新时代,你今天微勃了吗?
</p>
</body>
</html>
这时你再运行测试,会发现是绿油油的通过:
title-all-pass
但是,这样子我们不是大大的重复了代码么?没错,现在让我们看看如何 DRY...(Don't Repeat Yourself)
有一个 Rails 提供的函数叫做 provide,怎么用呢:
app/views/static_pages/home.html.erb
<% provide(:title, 'Home') %>
<!DOCTYPE html>
<html>
<head>
<title><%= yield(:title) %> | X Weibo</title>
</head>
<body>
<h1>新微博</h1>
<p>
神秘的X项目<a href="http://ruby-china.org">新微博</a> Rails 示例教学
</p>
</body>
</html>
上面我们使用了 Rails 给的 provide 方法来把 :title 与传入的字串做关联。
这样到这行的时候:
<title><%= yield(:title) %> | X Weibo</title>
就会替换成
<title>Home | X Weibo</title>
<%= ... %> 会将结果显示至页面、<% %> 不会。
运行测试看看对不对:
bin/rspec spec/requests/static_pages_spec.rb
绿色!正是我们想要的结果,让我们再次依样画葫芦改动 About, Help 页面:
app/views/static_pages/about.html.erb
<% provide(:title, 'About') %>
<!DOCTYPE html>
<html>
<head>
<title><%= yield(:title) %> | X Weibo</title>
</head>
<body>
<h1>关于新微博</h1>
<p>
新微博是使用 <a href="http://rubyonrails.org">Ruby on Rails</a> 技术所开发的微博,网络新纪元,微博新时代,你今天微勃了吗?
</p>
</body>
</html>
app/views/static_pages/help.html.erb
<% provide(:title, 'Help') %>
<!DOCTYPE html>
<html>
<head>
<title><%= yield(:title) %> | X Weibo</title>
</head>
<body>
<h1>帮助</h1>
<p>
更多相关 Ruby on Rails 帮助,请莅临
<a href="http://ruby-china.org">Ruby-china</a>.
本示例教程教学文章:
<a href="http://ruby-china.org/topics/3239">1000 小时学会 Rails 系列</a>.
</p>
</body>
</html>
运行测试看看是否有打错字:
bin/rspec spec/requests/static_pages.spec.rb
......
Finished in 0.50721 seconds
6 examples, 0 failures
OK! 没有打错字或是奇怪的错误。
但是我们还是大大的重复了代码,每一页我们都重复了一堆相同的 HTML 代码,这就是为什么我们有一个 application.html.erb,现在我们先把刚刚更名的名字换回来 application.html.erb,:
mv foo app/views/layouts/application.html.erb
并依照刚刚的逻辑把 application.html.erb 改为:
<!DOCTYPE html>
<html>
<head>
<title><%= yield(:title) %> | X Weibo</title>
<%= stylesheet_link_tag "application", :media => "all" %>
<%= javascript_include_tag "application" %>
<%= csrf_meta_tags %>
</head>
<body>
<%= yield %>
</body>
</html>
我们一样在 title 标签 yield 不同的标题出来。
接下来把之前重复的部份拿掉,拿掉后的 Home, Help, About 页面:
app/views/static_pages/home.html.erb
<% provide(:title, 'Home') %>
<h1>新微博</h1>
<p>
神秘的X项目<a href="http://ruby-china.org">新微博</a> Rails 示例教学
</p>
app/views/static_pages/help.html.erb
<% provide(:title, 'Help') %>
<h1>帮助</h1>
<p>
更多相关 Ruby on Rails 帮助,请莅临
<a href="http://ruby-china.org">Ruby-china</a>.
本示例教程教学文章:
<a href="http://ruby-china.org/topics/3239">1000 小时学会 Rails 系列</a>.
</p>
app/views/static_pages/about.html.erb
<% provide(:title, 'About') %>
<h1>关于新微博</h1>
<p>
新微博是使用 <a href="http://rubyonrails.org">Ruby on Rails</a> 技术所开发的微博,网络新纪元,微博新时代,你今天微勃了吗?
</p>
运行测试依旧是青山绿水一片:
......
Finished in 0.52661 seconds
6 examples, 0 failures
好了,这样子我们的静态页面就做好了,有三个页面:Home, Help, About、并有不同的标题。。。
先存个档,存档之前记得先运行所有的测试确保无误:
git add .
git commit -m "Finish static pages"
git checkout master
git merge static_pages
喔耶!我们首先 commit, 切回主分支 (master),并把劳动成果都合并过来。
接下来 push 到 Github 上:
git push
这个示例项目可以在 Github 上找到:神秘的 X 项目 Github
演示页面:神秘的 X 项目 Heroku (拜托不要给太多人知道,流量暴了会收钱的)
存档完毕。
不过现在还是弱暴了,但是慢慢来,不著急,还有 920 个小时。。。
让我们继续看看如何实现........
等等,五十一区的暴乳摔角格斗开始了,我要去观赛啦,今天就到这儿啦。。。
待续。。。
习题:
依照刚刚的思路写一个 contact 页面,先写个测试、创建 contact.html.erb、根据测试的报错慢慢调试、并加入适当的 title: Contact | X Weibo 。
我们的 static_pages_spec.rb 有著重复的基本标题用例:| X Weibo,试著去查询 RSpec 的 let 方法,看要怎么样 DRY。
(选择性)参考 004 文章,将你的应用布署至 Heroku,你可能得用 PostgreSQL 才行,并在回应晒出你的 URL。
创建静态页面
静态页面,究竟要干啥的?我们的页面总需要添加一些,这网站谁做的阿 (about),这网站怎么用阿 (help),这网站怎么回首页阿 (home)。。。等等,这些比较不会变化的页面,吾人称之为静态页面。
首先就先来实现刚刚说的这些页面,让我们先来创一个平行时空吧,沈佳怡。。。:
git checkout -b static_pages
-b 是新建分支并切换到该分支。
再来让我们复习一下 MVC,当一个尊敬的用户,打开浏览器,浏览你的网站时,会发送请求给你,Rails 有一个 Rails 路由,看了看你要去哪,交给相对应的控制器的动作,控制器跟模型要资料(如果需要的话),模型去数据库取出来,丢回给控制器,控制器传给视图,视图返回 HTML 给控制器,控制器再丢回给尊敬的用户。
创建 HOME 与 HELP 页面
当你创建一个 Rails 应用时,路由已经是标配了,你所需要做的呢,是产生控制器、视图以及模型。好的,先让我们产生一个控制器,让它来帮我们处理这些静态页面的请求:
rails generate controller StaticPages home help --no-test-framework
就跟买咖啡一样,说你要什么、不要什么。。。我们产生了什么呢:
create app/controllers/static_pages_controller.rb
route get "static_pages/help"
route get "static_pages/home"
invoke erb
create app/views/static_pages
create app/views/static_pages/home.html.erb
create app/views/static_pages/help.html.erb
invoke helper
create app/helpers/static_pages_helper.rb
invoke assets
invoke coffee
create app/assets/javascripts/static_pages.js.coffee
invoke scss
create app/assets/stylesheets/static_pages.css.scss
首先呢,产生了一个控制器,叫做 StaticPages 带有 home、help 动作,以及相对应的路由、视图,一个 helper、一个 coffeescript 及 sass 文件,不要缺省的测试框架,换了谭浩强来输入上面那条命令也是一样的结果,嘿嘿。。。
谭浩强:中国 C 语言之父。
假如有一天,你因为不明原因,只能用右手打字,哎呀、、、手误了,该怎么办?放心,有 generate 也有相对的 destroy 可以让你还原产生的东东:
rails destroy controller StaticPages home help
模型比照办理,如 rails destroy model Foo
让我们打开一下 config/routes.rb 看看,到底路由是加没加(注释暂时忽略)?
XWeibo::Application.routes.draw do
get "static_pages/home"
get "static_pages/help"
end
阿哈,它替我们创好了当有一个要到 URI static_pages/home 这样的 GET 请求时,把它交给 StaticPages 控制器的 home 动作处理。
HTTP 动词复习
这是用户(通常是浏览器,如火狐、Safari)与服务器(Apache、Nginx)之间的用语,请注意,你的电脑可以同时扮演两个角色。他们之间的沟通用语就是 GET, POST, PUT, DELETE。
GET 请求: 读取 ,比如到某个网站的首页,要求页面
POST 请求: 创建 ,比如填入表单所发送的请求
PUT 请求: 更新 ,比如更新用户信息。
DELETE 请求: 摧毁 ,比如不喜欢这个帐号?删除它。
有的人会说 PUT 跟 POST,也可以花插儿著用,恩可以,HTTP 允许 POST 来做更新。但在 Rails 应用的上下文里,POST 通常是拿来创建新东西。
好了,让我们再来看看控制器里有些什么:
class StaticPagesController < ApplicationController
def home
end
def help
end
end
这里可以看到,定义了一个类别 StaticPagesController 继承 (<)自 ApplicationController,并带有两个方法,方法由 def 关键字定义,这其实隐含了很多 Rails 帮你写好的代码。
然而这两个动作怎么啥都没有呢?在 Ruby 里,这两个方法啥也不干。在 Rails 呢,即便是没写内容的方法 home,最基本也会去渲染一个视图 ( app/views/static_pages/home.html.erb )。
让我们打开服务器一探究竟,我们总是有著无止尽的好奇心:
rails server
打开浏览器,看看这两个页面
http://localhost:3000/static_pages/home.html
http://localhost:3000/static_pages/help.html
home-help
这两个页面实际上就是 Rails 替我们产生的,相当简单的 HTML,各有一个 h1 标题标签,以及一个段落标签 p。
<h1>StaticPages#home</h1>
<p>Find me in app/views/static_pages/home.html.erb</p>
<h1>StaticPages#help</h1>
<p>Find me in app/views/static_pages/help.html.erb</p>
而 http://localhost:3000/ 是 Rails 标准的欢迎画面,相信你已经相当熟悉了。
很好、很好,到这里先存档一下吧、我得去上个厕所:
git add .
git commit -m 'Add a StaticPages controller'
撰写第一个测试
厕所上回来啦。。。还买了罐啤酒,BDD (aka Beer-driven Development) 嘛。。。啤酒少不了的。
如同之前说过的,这个应用会是由 BDD 的方式来做开发。所以现在让我们来写测试吧,当然,不用先写测试也可以,要理解到,虽然写测试有很多好处,但是人是活的,码是死的,我管不住你。。。
之后的流程,我们会先写一个失败的测试,撰写代码使其通过,再进行重构。
测试、编码、修改、重构。
第一步让我们先来产生测试:
rails generate integration_test static_pages
可以看到 Rails 调用了 rspec 帮我们产生了一个测试文件:
invoke rspec
create spec/requests/static_pages_spec.rb
让我们加入 Home 页面的测试代码,你会发现里面已经有代码了,使用如下代码替换:
spec/requests/static_pages_spec.rb
require 'spec_helper'
describe "Static pages" do
describe "Home page" do
it "should have the content '新微博'" do
visit '/static_pages/home'
page.should have_content('新微博')
end
end
end
让我来解释一下这个测试,我们有一个测试静态页面的 describe 区块
describe "Static pages" do
首先我们测的是 Home 页面
describe "Home page" do
里面有一个测试:
it "should have the content '新微博'" do
visit '/static_pages/home'
page.should have_content('新微博')
end
这个测试就跟英文一样,它说当我们来到 /static_pages/home 这个页面时,应该要看到新微博这个内容。这里的 visit 使用到了,我们之前安装的 capybara gem 的一个 visit 方法、page 也是由 capybara gem 提供的变量。
这些 describe, it 高抽象化的语言是 RSpec 写好,供你使用的 DSL 方法,搭配 capybara 使用来达到测试驱动开发的目的,一开始可能会觉得不太自在,但先不要纠结于是怎么实现的,用的熟练后回头看,自然而然就理解了。
OK,现在让我们来运行看看
bin/rspec spec/requests/static_pages_spec.rb
first-fail
阿哈,我们有了第一个失败测试,很好,这样让我们知道下一步该怎么走。
错误信息告诉我们 Home 页面缺少了 新微博 这个内容,让我们打开 app/views/static_pages/home.html.erb ,并添加如下内容:
<h1>新微博</h1>
<p>
神秘的X项目<a href="http://ruby-china.org">新微博</a> Rails 示例教学
</p>
再运行一次测试:
bin/rspec spec/requests/static_pages_spec.rb
这时候应该看到测试通过:
first-pass
接下来让我们加入帮助信息的页面,一样先写个测试,在 static_pages_spec.rb 的 describe "Static pages" 区块中加入:
describe "Help page" do
it "should have the content '帮助'" do
visit '/static_pages/help'
page.should have_content('帮助')
end
end
呵呵,这个测试基本上跟刚刚一样,只不过改了几个小地方,下一步要做什么呢?让我们运行测试看看:
bin/rspec spec/requests/static_pages_spec.rb
help-fail
到这会儿你应该可以体会出,我很傻帽或者是测试带来的好处,首先我们构思我们的页面要实现什么功能,撰写一个测试,运行测试、编码。而每个测试之间的相似性很高,互相可以重用。
好的,现在让我们打开 app/views/static_pages/help.html.erb,添加:
app/views/static_pages/help.html.erb
<h1>帮助</h1>
<p>
更多相关 Ruby on Rails 帮助,请莅临
<a href="http://ruby-china.org">Ruby-china</a>.
本示例教程教学文章:
<a href="http://ruby-china.org/topics/3239">1000 小时学会 Rails 系列</a>.
</p>
呵呵,有了测试以后就像是傻瓜开发一样,so simple!
我们的 Home 与 Help 页面做好啦!
加入关于页面
现在让我们加入一下关于页面,哎呀,看起来我刚刚似乎产生控制器的时候,忘了加入 about 页面了:
rails generate controller StaticPages home help --no-test-framework
呵呵,其实我是故意的,我们自己走一遍这个流程就可以了解 rails 命令背后到底偷偷摸摸干了啥,一样我们先来写个测试:
describe "About page" do
it "should have the content '关于新微博" do
visit '/static_pages/about'
page.should have_content('关于新微博')
end
end
这个测试跟刚刚两个基本一模一样,将这个测试加至 static_pages_spec.rb ,你懂得,运行:
about-fail-no-route
哦,这次的错误信息不太一样,报错的是没有相应的路由:
No route matches [GET] "/static_pages/about"
若是 Rails 自动帮我们产生的话,Rails 会自动替你加路由、加相应的控制器动作、对应的视图。
让我们现在把这个路由加上,打开 config/routes.rb ,添加:
get "static_pages/about"
若是使用了 Spork 进阶配置的朋友,可能得重启 DRb 服务器哦,亲!
再运行测试看看,相信聪明如你已经猜到我们还没实现控制器的 about 动作:
about-fail-no-action
打开 app/controller/static_pages 添加 about 动作:
def about
end
现在先留白就很够用了,我们已经有从 Rails 的 ApplicationController 继承来的一堆东西可用了,这算不算是某种程度上的靠爸族呢。。。
about-fail-no-view
添加缺少的视图,在 app/views/static_pages 目录下创建 about.html.erb ,并填入:
<h1>关于新微博</h1>
<p>
新微博是使用 <a href="http://rubyonrails.org">Ruby on Rails</a> 技术所开发的微博,网络新纪元,微博新时代,你今天微勃了吗?
</p>
OK! 现在运行测试:
bin/rspec spec/requests/static_pages_spec.rb
都变成绿油油的一片,没有红色可怕的 F 了!这也就是为什么这个流程叫做 Red-Green-Refactor 。
现在让我们来看看有哪儿可以重构的。。。
重构!将 DRY 进行到底。。。
恩,我们都不喜欢单调,尤其是姿势,点缀生活,网站当然也一样,你发现到我们的标题老是一样么?Home, Help, About 页面的标题都是一样的,这样有点闷...
让我们看看如何让不同的页面有不同的标题,我们想要的是
title-table
OK. 现在让我们看看如何实现这个功能,首先我们先写个测试,来免去手动刷新的开发范式 (paradigm)...
打开 spec/requests/static_pages_spec.rb :
让我们添加一个新测试:
it "should have the title 'Home'" do
visit '/static_pages/home'
page.should have_selector('title',
:text => "Home | X Weibo")
end
这个测试该加在哪呢?这是一个关于 Home 页面的测试,合理地我们可以放在 describe "Home" 区块里。
我们首先访问首页 visit '/static_pages/home' ,页面应该有内容为 Home | X Weibo 的标题。
这个 have_selector 方法确认 title 标签的内容是不是 Home | X Weibo ...
这里 :text => "Home | X Weibo" 是 Ruby 的嘻哈哈希语法。
:text 是 Ruby 里的符号,作为哈希的键值使用。
另一件要提及的是代码的可读性。注意到:
page.should have_selector('title',
:text => "Home | X Weibo")
我们将
:text => "Home | X Weibo"
移到第二行,增加可读性。适当的缩排是提高可读性的不二法门。Ruby 不在乎多出来的空白及新行,最好是保持 每行 < 72 个字符,否则有可能会被 Linus 喷的体无完肤,呵呵。
让我们也添加 Help, About 页面的测试,现在整个 static_pages_spec.rb 看起来:
spec/requests/static_pages_spec.rb
# encoding: UTF-8
require 'spec_helper'
describe "Static pages" do
describe "Home page" do
it "should have the h1 '新微博'" do
visit '/static_pages/home'
page.should have_selector('h1', :text => '新微博')
end
it "should have the title 'Home'" do
visit '/static_pages/home'
page.should have_selector('title',
:text => "Home | X Weibo")
end
end
describe "Help page" do
it "should have the h1 '帮助'" do
visit '/static_pages/help'
page.should have_selector('h1', :text => '帮助')
end
it "should have the title 'Help'" do
visit '/static_pages/help'
page.should have_selector('title',
:text => "Help | X Weibo")
end
end
describe "About page" do
it "should have the h1 '关于新微博'" do
visit '/static_pages/about'
page.should have_selector('h1', :text => '关于新微博')
end
it "should have the title 'About'" do
visit '/static_pages/about'
page.should have_selector('title',
:text => "About | X Weibo")
end
end
end
注意我把每个页面比较暧昧不明的 have_content 换成 have_selector 。
好了,让我们运行测试看看:
bin/rspec spec/requests/static_pages_spec.rb
会看到三个测试 Fail 了,有著相似的错误信息:
Failure/Error: page.should have_selector('title',
expected css "title" with text "Home | X Weibo" to return something
阿哈,我们要对红通通失败的测试感到开心,因为我们知道错在那,可以改,不像谈恋爱那般。。。
在这之前,让我们回想一下之前,我们创建项目时输入的命令么:
rails new x_weibo --skip-test-unit --skip-bundle
这个命令也替我们产生了一个 app/views/layouts/application.html.erb layout 文件:
app/views/static_pages/application.html.erb
<!DOCTYPE html>
<html>
<head>
<title>XWeibo</title>
<%= stylesheet_link_tag "application", :media => "all" %>
<%= javascript_include_tag "application" %>
<%= csrf_meta_tags %>
</head>
<body>
<%= yield %>
</body>
</html>
这个文件就是咱 Rails 应用的骨架了,注意到中间的 <%= yield %>,我们的 Home, Help, About 页面会在调用 yield 时产生出来,这是 Rails 能够摆脱 那些年我们一起在网页里塞 PHP 代码 的精妙之处。
让我们先暂时把这个文件更名一下,先让它不起作用
mv app/views/layouts/application.html.erb foo
Windows 的命令貌似是 rename,不那么 Geek 手动更名也成。
好了,现在你启动服务器 (rails s),打开每个页面看看:
http://localhost:3000/static_pages/home
http://localhost:3000/static_pages/help
http://localhost:3000/static_pages/about
可以看到本来一样的标题都不见了,检视原始码发现甚至 HTML, DOCTYPE 那些标签都没了,相信你已经知道是怎么回事儿了,呵呵。
现在让我们分别实现每个页面的标题,首先是 Home 页面,打开 app/views/static_pages/home.html.erb ,让我们加上需要的 HTML ,让它成为一个完整的网页,并把标题改为我们要的样子:
app/views/static_pages/home.html.erb
<!DOCTYPE html>
<html>
<head>
<title>Home | X Weibo</title>
</head>
<body>
<h1>新微博</h1>
<p>
神秘的X项目<a href="http://ruby-china.org">新微博</a> Rails 示例教学
</p>
</body>
</html>
现在运行测试会发现失败的测试少了一个,让我们依样画葫芦改动 About 以及 Help 页面:
app/views/static_pages/help.html.erb
<!DOCTYPE html>
<html>
<head>
<title>Help | X Weibo</title>
</head>
<body>
<h1>帮助</h1>
<p>
更多相关 Ruby on Rails 帮助,请莅临
<a href="http://ruby-china.org">Ruby-china</a>.
本示例教程教学文章:
<a href="http://ruby-china.org/topics/3239">1000 小时学会 Rails 系列</a>.
</p>
</body>
</html>
app/views/static_pages/about.html.erb
<!DOCTYPE html>
<html>
<head>
<title>About | X Weibo</title>
</head>
<body>
<h1>关于新微博</h1>
<p>
新微博是使用 <a href="http://rubyonrails.org">Ruby on Rails</a> 技术所开发的微博,网络新纪元,微博新时代,你今天微勃了吗?
</p>
</body>
</html>
这时你再运行测试,会发现是绿油油的通过:
title-all-pass
但是,这样子我们不是大大的重复了代码么?没错,现在让我们看看如何 DRY...(Don't Repeat Yourself)
有一个 Rails 提供的函数叫做 provide,怎么用呢:
app/views/static_pages/home.html.erb
<% provide(:title, 'Home') %>
<!DOCTYPE html>
<html>
<head>
<title><%= yield(:title) %> | X Weibo</title>
</head>
<body>
<h1>新微博</h1>
<p>
神秘的X项目<a href="http://ruby-china.org">新微博</a> Rails 示例教学
</p>
</body>
</html>
上面我们使用了 Rails 给的 provide 方法来把 :title 与传入的字串做关联。
这样到这行的时候:
<title><%= yield(:title) %> | X Weibo</title>
就会替换成
<title>Home | X Weibo</title>
<%= ... %> 会将结果显示至页面、<% %> 不会。
运行测试看看对不对:
bin/rspec spec/requests/static_pages_spec.rb
绿色!正是我们想要的结果,让我们再次依样画葫芦改动 About, Help 页面:
app/views/static_pages/about.html.erb
<% provide(:title, 'About') %>
<!DOCTYPE html>
<html>
<head>
<title><%= yield(:title) %> | X Weibo</title>
</head>
<body>
<h1>关于新微博</h1>
<p>
新微博是使用 <a href="http://rubyonrails.org">Ruby on Rails</a> 技术所开发的微博,网络新纪元,微博新时代,你今天微勃了吗?
</p>
</body>
</html>
app/views/static_pages/help.html.erb
<% provide(:title, 'Help') %>
<!DOCTYPE html>
<html>
<head>
<title><%= yield(:title) %> | X Weibo</title>
</head>
<body>
<h1>帮助</h1>
<p>
更多相关 Ruby on Rails 帮助,请莅临
<a href="http://ruby-china.org">Ruby-china</a>.
本示例教程教学文章:
<a href="http://ruby-china.org/topics/3239">1000 小时学会 Rails 系列</a>.
</p>
</body>
</html>
运行测试看看是否有打错字:
bin/rspec spec/requests/static_pages.spec.rb
......
Finished in 0.50721 seconds
6 examples, 0 failures
OK! 没有打错字或是奇怪的错误。
但是我们还是大大的重复了代码,每一页我们都重复了一堆相同的 HTML 代码,这就是为什么我们有一个 application.html.erb,现在我们先把刚刚更名的名字换回来 application.html.erb,:
mv foo app/views/layouts/application.html.erb
并依照刚刚的逻辑把 application.html.erb 改为:
<!DOCTYPE html>
<html>
<head>
<title><%= yield(:title) %> | X Weibo</title>
<%= stylesheet_link_tag "application", :media => "all" %>
<%= javascript_include_tag "application" %>
<%= csrf_meta_tags %>
</head>
<body>
<%= yield %>
</body>
</html>
我们一样在 title 标签 yield 不同的标题出来。
接下来把之前重复的部份拿掉,拿掉后的 Home, Help, About 页面:
app/views/static_pages/home.html.erb
<% provide(:title, 'Home') %>
<h1>新微博</h1>
<p>
神秘的X项目<a href="http://ruby-china.org">新微博</a> Rails 示例教学
</p>
app/views/static_pages/help.html.erb
<% provide(:title, 'Help') %>
<h1>帮助</h1>
<p>
更多相关 Ruby on Rails 帮助,请莅临
<a href="http://ruby-china.org">Ruby-china</a>.
本示例教程教学文章:
<a href="http://ruby-china.org/topics/3239">1000 小时学会 Rails 系列</a>.
</p>
app/views/static_pages/about.html.erb
<% provide(:title, 'About') %>
<h1>关于新微博</h1>
<p>
新微博是使用 <a href="http://rubyonrails.org">Ruby on Rails</a> 技术所开发的微博,网络新纪元,微博新时代,你今天微勃了吗?
</p>
运行测试依旧是青山绿水一片:
......
Finished in 0.52661 seconds
6 examples, 0 failures
好了,这样子我们的静态页面就做好了,有三个页面:Home, Help, About、并有不同的标题。。。
先存个档,存档之前记得先运行所有的测试确保无误:
git add .
git commit -m "Finish static pages"
git checkout master
git merge static_pages
喔耶!我们首先 commit, 切回主分支 (master),并把劳动成果都合并过来。
接下来 push 到 Github 上:
git push
这个示例项目可以在 Github 上找到:神秘的 X 项目 Github
演示页面:神秘的 X 项目 Heroku (拜托不要给太多人知道,流量暴了会收钱的)
存档完毕。
不过现在还是弱暴了,但是慢慢来,不著急,还有 920 个小时。。。
让我们继续看看如何实现........
等等,五十一区的暴乳摔角格斗开始了,我要去观赛啦,今天就到这儿啦。。。
待续。。。
习题:
依照刚刚的思路写一个 contact 页面,先写个测试、创建 contact.html.erb、根据测试的报错慢慢调试、并加入适当的 title: Contact | X Weibo 。
我们的 static_pages_spec.rb 有著重复的基本标题用例:| X Weibo,试著去查询 RSpec 的 let 方法,看要怎么样 DRY。
(选择性)参考 004 文章,将你的应用布署至 Heroku,你可能得用 PostgreSQL 才行,并在回应晒出你的 URL。
相关推荐
在IT行业中,项目静态页面通常指的是那些不涉及服务器端动态处理的网页,它们主要由HTML、CSS和JavaScript等前端技术构建。这些文件直接在客户端浏览器中解析和执行,为用户提供直观的交互体验。下面我们将详细探讨...
【标题】"购物车项目静态页面"涉及到的是一个基于Web的电子商务系统中至关重要的组成部分——购物车功能的前端实现。这个项目旨在创建一个用户可以浏览商品、选择并添加到购物车的静态页面。通过这个页面,用户能够...
综上所述,"物流管理项目静态页面和需求文档"是构建高效、智能的物流管理系统的基础。静态页面设计需兼顾美观和实用性,而需求文档则为系统开发提供了明确的方向。理解并掌握这些知识点,有助于打造一个满足业务需求...
5. **目录结构**:一个标准的SSM项目静态页面的目录结构可能包括`/static`或`/public`目录,用于存放所有的静态资源,如`/static/css`、`/static/js`和`/static/images`等子目录。 6. **视图解析器**:在Spring MVC...
【标题】"商城项目静态页面"所指的是一款在线商城系统的前端部分,主要包含用于展示商品、实现用户交互以及提供美观界面的HTML、CSS和JavaScript等静态资源。这些页面是不涉及服务器端处理的,主要任务是将商城的...
【北大青鸟S2结业项目静态页面】是北大青鸟教育机构ACCP6.0课程体系中的一个重要学习阶段——S2阶段的成果展示。这个项目主要是为了让学生们在掌握前端开发基础知识后,通过实际操作来提升自己的技能,将理论与实践...
【标题】"网上商城-静态页面模版"指的是一个用于构建在线购物平台的网页设计模板。这个模版专为初级开发者设计,旨在帮助他们快速搭建一个功能基础的网上商城网站,无需从零开始编写所有HTML、CSS和JavaScript代码。...
基于HTML+CSS的静态网页设计仿网易云音乐静态页面项目源码.zip 亲测95分以上高分必过项目,下载即用无需修改。 基于HTML+CSS的静态网页设计仿网易云音乐静态页面项目源码.zip 亲测95分以上高分必过项目,下载即用...
《品优购项目静态页面开发》 在网页开发领域,静态页面是一种常见的设计方式,它主要由HTML、CSS以及可能的JavaScript组成,不涉及服务器端动态处理。本资源"品优购项目静态页面开发.rar"显然是一个专注于电商网站...
这个项目旨在教授学员如何构建一个完整的OA系统,涵盖前端静态页面设计、后端程序开发以及相关的学习资料,帮助学员提升在实际工作中的应用能力。 在该项目中,【静态页面】是用户界面的基础部分,通常由HTML、CSS...
【标题】"传智播客oa项目静态页面12年12月"涉及的是一个针对OA(Office Automation,办公自动化)系统的前端开发实践,时间点回溯至2012年12月。这个项目主要关注的是网页界面的构建,也就是所谓的静态页面设计。 ...
本项目“JavaWeb技术及应用—教材贯穿项目静态页面”旨在通过实际操作,让学生深入理解和掌握JavaWeb的基本概念和实践技能。 首先,我们来了解一下静态页面。静态页面是指HTML、CSS和JavaScript等前端技术编写的...
HTML + CSS 实现淘宝页面首屏静态网页项目练习 HTML + CSS 实现淘宝页面首屏静态网页项目练习 HTML + CSS 实现淘宝页面首屏静态网页项目练习 HTML + CSS 实现淘宝页面首屏静态网页项目练习 HTML + CSS 实现淘宝页面...
这个静态页面项目是CRM系统的一个演示版本,主要用于展示和理解CRM系统的基础功能和界面设计。下面我们将深入探讨这个静态页面所涉及的几个关键知识点。 1. **HTML**:HTML(HyperText Markup Language)是构建网页...
在构建大型项目时,后台静态页面的开发是一个至关重要的环节,它涉及到用户界面的设计、用户体验的优化以及数据的展示和交互。"大项目后台静态页面"这个标题和描述暗示了我们要探讨的是关于大规模应用程序中非动态...
基于HTML+CSS的静态网页设计仿网易云音乐静态页面95分以上项目源码+项目说明.zip基于HTML+CSS的静态网页设计仿网易云音乐静态页面95分以上项目源码+项目说明.zip基于HTML+CSS的静态网页设计仿网易云音乐静态页面95分...
"DaNei云端笔记项目静态资源"是一个专为初学者设计的实践项目,旨在帮助他们了解和掌握云笔记应用的开发。这个项目包含了所有必要的前期准备,因此开发者无需从零开始,可以直接进入环境搭建和编码阶段。对于想要...
《网上书城项目的静态页面》 在Web开发领域,静态页面是构成网站基础的重要部分,它们不依赖服务器端的脚本或数据库交互,而是由HTML、CSS和JavaScript等前端技术直接构建而成。网上书城项目的静态页面设计是用户...
小兔鲜项目是一个在线蔬菜...以上是小兔鲜项目前端静态页面的基本功能,通过这些页面可以让用户方便地浏览和购买蔬菜水果。在开发过程中,我们需要注意页面的设计美观、用户体验友好,确保用户能够顺利完成购物流程。
静态网页设计大作业。 静态网页设计期末作业二十四节气HTML静态网页源码。期末作业高分项目、95分项目。静态网页设计大作业。静态网页设计期末作业二十四节气HTML静态网页源码。期末作业高分项目、95分项目。静态...