Agile Web Development with Rails 翻译(六)
2006年4月16日更新
到现在为止,我们已向我们的Rails应用程序树内添加了两个文件。我们添加了一个用于“控制器”的“动作”和用于在浏览器内显示的“模板”。这些文件中的“控制器”存在app/controllers标准目录中,“视图”则在app/views中。这显示在图4.4中。
让它动态化
现在,我们的Rails应用程序不是很好—它只显示一个静止页面。要让它更动态些,让我们在每次显示这个页时加上当前时间。
要做到这一点,我们需要对“视图”内的“模板”做些变动—它现在需要包含表示时间的字符串。这会带来两个问题。一首先是我们如何向模板添加动态内容?其次,我们从哪儿得到时间?
动态的内容
在Rails内有两个途径可创建动态模板。一是使用Builder技术,我们在17.2节讨论它。第二种方法,是我们在这儿使用的,它在模板文件自身植入Ruby代码。这就为什么我们命名模板文件为hello.rhtml:.rhtml前缀告诉Rails要使用ERb系统来扩展文件的内容。
ERb是个过滤器,它接受一个.rhtml文件并输入一个翻译后的版本。在Rails中输出文件通常是HTML,也可以是其它什么文件。普通的内容不会被修改。但是,在<%=和%>之间内容会解释成Ruby代码,并进行计算。计算的结果被转换成字符串,然后这个值被替换掉<%=…%>序列。例如,修改hello.rhtml包含下面内容。
<ul>
<li>Addition: <%= 1+2 %> </li>
<li>Concatenation: <%= "cow" + "boy" %> </li>
<li>Time in one hour: <%= 1.hour.from_now %> </li>
</ul>
当你刷新浏览器时,“模板”将生成下面HTML。
<ul>
<li>Addition: 3 </li>
<li>Concatenation: cowboy </li>
<li>Time in one hour: Sat Feb 26 18:33:15 CST 2005 </li>
</ul>
----------------------------------------------------------------------------------------
让开发更容易些
现在为止从我们开始中你可能已经注意到了什么。因为我们已经给们的应用程序添加了代码,我们不必接触运行中应用程序。它很乐意使用这种后台方式。无论何时们访问浏览器时,每次修改都会生效。谁做的?它明显地关闭了基于WEBrick的Rails分派。在开发模式中(对应的是测试模式和产品模式),当有一个新请求时,它自动地重新加载应用程序源文件。当我们编辑我们应用程序时,“分派器”会确保它运行大多数最近的修改。这对开发来说很好。但是,这很复杂—在你输入URL之后,应用程序响应之前,它会出现暂停现象。这是由分派器重新加载文件引起的。对于开发来说,这还是值得的,但在发行的产品中,却是不合适的。因为这些,这个特性在产品模式中被禁止(查阅440页第二十二章。)
------------------------------------------------------------------------------------------
在浏览器窗口,你会看到些东西:
• Addition: 3
• Concatenation: cowboy
• Time in one hour: Sat Feb 26 18:33:15 CST 2005
此外,在<%和%>之间东西(没有等于符号)被解释成没有输出的Ruby代码。有趣的它处理的东西,尽管,它不能混杂有非Ruby代码。例如,我们可这样写:
<% 3.times do %>
Ho!<br />
<% end %>
Merry Christmas!
再次刷新浏览器,你会看到这些。
Ho!
Ho!
Ho!
Merry Christmas!
注意文件内的Ruby循环中的文本,在每次循环迭代时是如何被发送到输出流。
我们可以混合这两种形式。在这个例子中,循环设置个变量,以在每次循环执行时插入到文本中。
<% 3.downto(1) do |count| %>
<%= count %>...<br />
<% end %>
Lift off!
下面东西会被发送给浏览器。
3...<br />
2...<br />
1...<br />
Lift off!
最后是ERb,通常你想使用值来替换<%=…%>的内容,而&字符对HTML来说有重要的意义。为了避免这些弄乱你的页面 (像我们在427页的第二十一章看到的,避免潜在的安全问题),你要转义些字符。Rails有个帮助方法,h(),它用来做这件事。大多数时候,你在向HTML页插入值使用它们。
Email: <%= h("Ann & Bill <frazers@isp.email>") %>
这个例子中,h()方法用于防止e-mail地址内特殊字符与浏览器显示混淆—它会转义HTML条目。浏览器看到Email:Ann & Bill <frazers@isp.email>--会以适当的方式显示特殊字符。
添加时间
我们原先的问题是给使用我们应用程序的用户显示时间。现在我们知道如何让我们的应用程序动态地显示时间。其次是找到显示时间的地方。
一种途径是在say.rhtml“模板”内插入Ruby的Time.now()调用 。
<html>
<head>
<title>Hello, Rails!</title>
</head>
<body>
<h1>Hello from Rails!</h1>
<p>
The time is <%= Time.now %>
</p>
</body>
</html>
它工作了。每次我们访问这个页面,用户将看到当前时间。这对于我们这个小程序来说,这就足够了。虽然,通常我们或许想做些不的事。我们会决定从“视图”移出时间,并放到“控制器”中来完成简单的显示工作。我们修改“控制器”内的“动作”方法来设置时间的值到一个实例变量@time中。
class SayController < ApplicationController
def hello
@time = Time.now
end
end
在.rhtml模板中,我们将使用实例变量来替换输出的时间。
<html>
<head>
<title>Hello, Rails!</title>
</head>
<body>
<h1>Hello from Rails!</h1>
<p>
It is now <%= @time %>.
</p>
</body>
</html>
当刷新浏览器时,我们看到了显示的时间,如图4.5。注意如果你偶然地刷新了浏览器,则每次显示时都会更新时间。看看我们真正地生成了动态内容。
为什么我们会有要在“控制器”内设置显示的时间,然后在“视图”内使用它这么麻烦?问的很好。在这个应用程序中,你不应只在“模板”中插入对Time.now()的调用,还要把它放到“控制器”中,这样你会得到一些好处。例如,我们可能想在将来扩展我们应用程序,让它支持多个国家用户。在这种情况下,我们想按地区显示时间,选择适当的格式化用户时区和它们时区的时间。这需要些应用级别的代码,它或许不适合于被插入到“视图”级别中。通过在“控制器”内设置要显示的时间,我们可增强我们程序的灵活性—我们可以在“控制器”内修改显示格式和时区,而不必修改使用这个时间对象的“视图”。
------------------------------------------------------------------------------
Joe 问. . .
“视图”是如何得到时间的?
在“视图”和“控制器”的描述中,我们显示了“控制器”设置要显示的时间到一个实例变量中。.rhtml文件使用这个实例变量来替换当前时间。但是“控制器”对象的实例变量对那个对象说是私有的。ERb是如何持有这个私有数据并在模板内使用的呢?
回答是即简单又微妙。Rails做了些Ruby魔术,以便于“控制器”对象的实例变量能被注入到“模板”对象中。结果就是,“视图”模板可以访问“控制器”内设置的任何实例变量,就像是它自己的一样。
保存hello.rhtml文件,然后刷新浏览器。你应该看到我们朋友问候的显示。注意我们不必须重启动应用程序来查看更新。在开发期间,Rails自动地使用你修改的文件来运行应用程序。