Instant Gratification

让我们编写一个简单的应用验证我们已经在自己的机器上正确安装了 Rails。通过这种方式,我们可以了解 Rails 应用运作的方式。

创建新应用

当你安装了 Rails 框架,你还会获得一个新的命令行工具—— rails,可以通过这个命令构建新的 Rails 应用。

为什么你需要这个一个工具呢?为什么我们就不能通过自己最爱的编辑器,并且从头开始创建我们应用的源代码?其实我们可以做到。毕竟 Rails 应用只是 Ruby 代码。但是 Rails 也在后面做了许多工作,使我们可以通过最少量的配置使应用运行。为了使魔法运转,Rails 需要查找所有你应用中需要的所有组件。就如同后面我们会学习到的,这意味着我们需要创建特别的文件夹结构,并在合适的地方插入我们编写的代码。rails 命令简单地创建了文件夹结构,并填充了一些标准 Rails 代码。

创建你的第一个 Rails 应用,通过一个 shell 窗口,并且导航至你希望创建应用的项目结构的文件系统的地方。在我们的例子中,我们会在被称做 work 的路径中创建我们的项目。在这个路径中,通过 rails 命令创建一个被叫做的 demo 的路径。这里需要小心,如果你已经有一个已经存在的路径叫做 demo,你将会被询问是否需要覆写已经存在的文件。(注意:如果你需要特定的 Rails 版本,可以按照第 8 页的 1.4 节 Choosing a Rails Version 做,现在你还有时间做到这些)。

rubys> cd work
work> rails new demo
create
create README.rdoc
In this chapter, we’ll see
creating a new application,
starting the server,
accessing the server from a browser,
producing dynamic content,
adding hypertext links, and
passing data from the controller to the view.
report erratum • discuss
create Rakefile
create config.ru
: : :
create vendor/assets/stylesheets
create vendor/assets/stylesheets/.keep
run bundle install
Fetching gem metadata from https://rubygems.org/...........
: : :
Your bundle is complete!
Use `bundle show [gemname]` to see where a bundled gem is installed.
work>

上面的命令已经创建了一个叫做 demo 的路径。你可以进入此路径查看项目中的内容。你也会看到一堆文件和子路径。

一开始看到这么多文件路径确实让人恐惧,但现在先忽略它们。在这章,我们直接使用项目编写我们的应用就好。

你可以使用下面的命令检验你的应用。

rake about

这个命令将将探寻出常见的安装问题。例如,如果你不能查到 JavaScript 运行时环境,它将会提供一个可用的运行时环境链接。

如果你看见一堆关于已经初始化常量的信息,或者一些其他的冲突,请考虑将 demo 路径删除,并创建一个隔离的 RVM gemset 再开始。如果还是不能正常运行,可以使用 bundle exec 运行 rake 命令。

一旦 rake about 正常运行,你就拥有了将当前创建的 Rails 应用作为单体网站应用运行的所有必备的事物。因此,闲话少说,让我们开始我们的演示应用。

rails server

=> Booting WEBrick
=> Rails 4.0.0 application starting in development on http://0.0.0.0:3000
=> Run rails server -h for more startup options
=> Ctrl-C to shutdown server
[2013-04-18 20:22:16] INFO WEBrick 1.3.1
[2013-04-18 20:22:16] INFO ruby 2.0.0 (2013-02-24) [x86_64-linux]
[2013-04-18 20:22:16] INFO WEBrick::HTTPServer#start: pid=25170 port=3000

网站服务器的运行依赖于你安装的服务器是什么。WEBrick 是一个与 Ruby 同时发布的纯 Ruby web 服务器,因此它能够保证一直可用。然而,如果你在系统中安装了其他 web 服务器(并且 Rails 能够查找到它),rails server 会优先使用 WEBrick。你可以强制通过 rails 命令的参数使 Rails 使用 WEBrick。

rails server webrick

启动的追踪信息最后一行表明我们刚才开启的 web 服务器端口是 3000。地址中的 0.0.0.0 部分意味着 WEBrick 将可以通过所有接口连接访问。在 Dave 的 OS X 系统中,之前的地址意味着所有的本地接口(127.0.0.1 和 ::1) 以及他的 LAN 链接。我们可以在浏览器中通过 http://localhost:3000 访问。

如果你看着启动服务器的窗口,你会看到启动应用的追踪信息。我们将脱离使用控制台窗口运行服务器。后面,我们编写应用代码和通过浏览器运行它,我们可以通过控制台窗口跟踪输入的请求。当你想将应用停止时,你可以在窗口中按下 Ctrl-C 将 WEBrick 停止。(但别这样做,我们后面会用特别的应用进行操作。)

在这节,我们运行了一个新应用,但我们没有编写任何代码。让我们修正这种情况。

你好,Rails!

我们不能帮助它,我们必须写 "Hello, World!" 程序尝试创建一个新系统。让我们开始创建一个应用向浏览器发送我们的美好问候。在我们编写的程序正常运作后,我们会通过当前时间和链接建立它。

如同我们将在 Chapter 3, The Architecture of Rails Applications 介绍,Rails 是一个 Model-View-Controller 框架。Rails 从浏览器获取发起的请求,通过解码请求查找到 controller,并调用 controller 中的一个 action 方法。controller 接着调用指定的 view 向用户展示结果。好消息是 Rails 负责大部分内部协作的垂直通道。编写基础的 "Hello, World!" 应用,我们需要编码一个 controller 和一个 view,并且我们需要将链接路由至它们两个。我们不需要编写 model,因为我们不需要处理任何数据。让我们从 controller 开始。

通过相同的方法我们使用 rails 命令创建一个新的 Rails 应用,我们也可以通过生成脚本为项目创建一个新的 controller。这些命令叫做 rails generate。因此,创建一个叫做 say 的 controller,我们需要确认是在 demo 路径中运行命令,并且传递我们希望创建的 controller 名字和 action 的名称希望 controller 支持它们。

rails generate controller Say hello goodbye

create app/controllers/say_controller.rb
route get "say/goodbye"
route get "say/hello"
invoke erb
create app/views/say
create app/views/say/hello.html.erb
create app/views/say/goodbye.html.erb
invoke test_unit
create test/controllers/say_controller_test.rb
invoke helper
create app/helpers/say_helper.rb
invoke test_unit
create test/helpers/say_helper_test.rb
invoke assets
invoke coffee
create app/assets/javascripts/say.js.coffee
invoke scss
create app/assets/stylesheets/say.css.scss

rails generate 命令记录了它验证过的文件和路径,除了添加新的 Ruby 脚本或者路径给应用之外就没有其他操作了。现在,我们主要关注脚本中的一个和(稍后) .html.erb 文件。

我们在 controller 中看见的第一个文件是 controller。你会在 app/controller/say_controller.rb 中找到。让我来看看。

class SayController < ApplicationController
    def hello
    end
    def goodbye
    end
end

内容很少,不是吗?SayController 是继承于 ApplicationController 的一个类,因此它自动拥有了所有默认 Controller 的行为。那么代码不需要做什么?现在什么都需要做,我们就拥有最基础的空 action 方法 hello()goodbye()。要理解为什么方法按照这种方式命名,我们需要看看 Rails 怎么处理请求。

Rails 和请求 URL

如同其他 web 应用一样,Rails 应用通过 URL 与用户联系。当你在浏览器中输入 URL 后,你就在与应用的代码交流,它会向你返回响应信息。

让我们现在试一试。在浏览器中输入 http://localhost:3000/say/hello,你将看见如下的内容。

我们的第一个 Action

此时,可以看到我们不止通过 URL 链接至 controller,Rails 也向我们表明了接下来要如何做,以及告诉 Rails 要展示什么。这也是 view 位于的地方。还记得我们运行脚本创建新的 controller 吗?命令添加了几个文件和新的路径到应用中。路径包括了 controller 的 view 的模板文件。在我们的例子中,我们创建了一个叫做 say 的 controller,所以 view 将出现在 app/views/say 路径中。

默认情况下,Rails 在与处理请求的同名 action 中寻找模板文件。在我们的例子中,意味着我们需要替换 app/views/say 中的 hello.html.erb 文件。(为什么是 .html.erb?我们稍后会解释。)现在让我们在这里编写一些基本的 HTML 代码。

保存 hello.html.erb 文件然后刷新浏览器窗口。你应该看到它展现友好的问候。

总的来说,我们在 Rails 应用树上看见了两个文件。我们找到了 controller,并且修改了浏览器中展示的界面模板。这些文件都位于 Rails 体系的标准路径,controller 在 app/controllers 中,views 在 app/views 的子路径中。

让它动态起来

说了那么多,我们的 Rails 应用还是很无聊,它只是展示了一个静态界面。为了让它有更多动态效果,让我们使它能够显示每次展示页面的时间。

要做到这些,我们需要修改 view 中的模板文件,它现在需要包含时间的字符串。这就抛出了两个问题。首先,我们如何向模板添加动态内容?第二,我们从哪里获得时间?

添加时间

其实这有很多方式都可以在 Rails 中创建动态模板。我们最常用的方式是在模板中嵌入 Ruby 代码。这也是我们将模板文件命名为 hello.html.erb 的原因,.html.erb 的后缀是在告诉 Rails 文件的内容需要使用 ERB 系统进行解释。

ERB 是一个作为 Rails 组件同时安装的操作 .erb 文件的过滤器,并且会转出翻译的版本。在 Rails 通常输出 HTML,但也可以是其他的任何内容。一般的内容转换时不会做任何改变。但是,在 <%=%> 之间的内容会被作为 Ruby 代码解释和执行。执行结果会被转换为字符串,并且转换结果会将文件中的 <%=...%> 替换。例如,修改 hello.html.erb 用于显示当前时间。

Hello from Rails!

It is now <%= Time.now %>

当我们刷新浏览器窗口时,我们会看见通过 Ruby 的标准格式显示时间。

需要注意,如果你在浏览器中点击刷新,每次页面显示的时间都会更新。看起来就像我们已经真正地创建了动态内容一样。

添加时间

我们最开始的想法是向我们应用的用户展示时间。现在,我们知道如何在应用中使用动态数据。第二个问题是我们要时间是从哪里来。

我们已经展示了向模板文件 hello.html.erb 嵌入 Ruby 的 Time.now() 方法的方式。每次我们访问页面时,用户将会看到当前时间替换响应体内容。对我们这个不重要的应用这样可能已经够好了。也许,我们还是希望能够做一些不同的事情。我们将确定时间的事情移动至 controller 中进行,而 view 只是单纯地显示时间即可。我们将修改 controller 中的 action 方法,将时间值设置为叫做 @time 的实例变量。

class SayController < ApplicationController
    def hello
        @time = Time.now
    end
    def goodbye
    end
end

你可能已经注意到关于我们进行开发的这些事情。当我们向应用中添加代码时,我们不是必须重启正在运行的程序。它在幕后愉快地进行着变化。当我们通过浏览器访问我们修改的应用程序时,我们的修改是会生效的。这是怎么做到的呢?

那是因为 Rails 的分发器非常聪明。在开发模式中时(在测试和生产模式中不需要),当新请求进入时 Rails 自动重新加载应用资源文件。当我们编辑应用时,分发器会确认是否运行了最新的文件。这对于开发时是非常友好的。

然而,这个灵活性也会带来性能的损耗,在你向浏览器输入 URL 后得到相应响应前会出现短暂的暂停。那里因为分发器需要重载资源。当处于开发模式时这种资源损耗是值得的,但在生产环境是不可接受的。因为这个原因,这个特性需要在部署生产时关闭(可以看 Chapter 16, Task K: Deployment and Production 章节)。

在 .html.erb 模板中,我们会用实例变量替换输出的时间。

Hello from Rails!

It is now <%= @time %>

当我们刷新浏览器窗口时,我们会再次看见当前时间,这表示 controller 和 view 是正常交流的。

为什么我们还要额外将时间设置在 controller 中,再在 view 中使用?这是个好问题。在应用中,前一种方式和后一种方式并没有太多不同,但将逻辑放入 controller 中我们会得到一些好处。例如,我们可能希望未来扩展应用能够支持不同国家的人使用。如果要做类似的扩展,我们就希望根据合适的时区显示本地时间。这可能会需要大量的应用级代码,在 view 中将这些代码嵌入就不那么合适。通过设置在 controller 中的时间,我们让应用更加灵活,我们可以只修改 controller 中的时区而不修改 view 中的时间对象。时间也是一种数据,它应该由 controller 供应给 view。当我们将 model 引入时还会看见许多类似情况。

当前的故事

让我们简短地回顾我们当前的应用是怎样运作的。

  1. 用户导航进入我们的应用。在我们的例子中,我们通过本地 URL 实现,例如 http://localhost:3000/say/hello。

  2. 然后 Rails 匹配路由模式,它分离出两个部分并分析。

    say 部分是由 controller 名字组成,因此 Rails 创建新的接口也就是 Ruby 类 SayController(位于 app/controllers/say_controller.rb中)。

  3. 下一部分匹配,hello 指向同名的 action。Rails 调用 controller 中同名的方法。action 方法持有当前时间的 Time 对象,并把它保存在 @time 实例变量中。

  4. Rails 查找显示结果的模板方法。它通过 controller 的名字 say 在 app/views 查找子路径,并根据 action 名称定位文件 hello.html.erb。

  5. Rails 通过 ERB 模板系统处理文件,执行嵌入的 Ruby 代码和用 controller 中设置的值和执行结果将其替换。

  6. 浏览器返回结果,Rails 也结束请求流程。

这并不是故事的全部,Rails 会给你许多机会重写基本的工作流程(我们会对其进行简短的介绍)。如同之前表达的一样,我们的故事阐述了编写大于配置这一 Rails 中的基本哲学。通过提供方便的默认配置和应用确定的约定,我们通过 URL 就可以构造 controller 的定义和位置,Rails 应用是典型的很少写甚至是没有外部配置的应用,它只是将资源通过自然的方式纺织到一起。

将页面链接起来

那仅仅只是拥有一个页面的 web 应用。让我们看看我们可以如何添加一些有趣的东西,对 "Hello, World!" 应用增加设计。

一般情况下,应用中的每个页面都同样是分离的 view。在我们的例子中,还是通过 action 方法操作页面(其实也不完全是这样,我们会在后面的内容介绍到)。当然不要为这些 action 使用 controller。需要再次说明,这不需要在例子中展现,尽管我们没有说明当前不增加新 controller 的原因。

我们已经在 controller 中定义了 goodbye action,所以也需要在 app/view/say 路径下创建新模板。按规则它应用叫做 goodbye.html.erb,因为默认情况下模板名称与 action 名称是相关联的。

Goodbye!

It was nice having you here.

再次启动浏览器,可以通过 http://localhost:3000/say/goodbye 访问新的 view。

现在我们需要将两个场景链接起来。我们需要将一个链接放置在 hello 场景中,hello 场景将带我们跳转到 goodbye 场景,反之亦然。在真实的应用中,我们可能需要制作一些简单的按钮,但现在我们直接使用超链接。

我们已经了解 Rails 是通过约定将 URL 转换为目标 controller 及其中的 action。所以,最简单的方法就是采用这种约定作为我们的链接。

hello.html.erb 包含如下内容:

...

Say Goodbye!

...

goodbye.html.erb 也可以指向其他界面。

...

Say Hello!

...

这种方法也许能正常运作,但它比较脆弱。如果我们将应用在 web 服务器上进行了移动,URL 就不会一直有效。也可以将 Rails URL 的假设转码到代码中,也许 Rails 未来的版本会修改这个特性。

幸运的是,这并不需要我们亲自运作。Rails 提供了一堆能够在 view 模板中使用的 helper method。这里我们要使用 link_to() 方法,它将会为一个 action 创建超链接(link_to() 方法能做到的不止这些,但现在我们先只介绍这个功能)。使用 link_to() 后 hello.html.erb 将会像下面一样:

Hello from Rails!

It is now <%= @time %>

Time to say <%= link_to "Goodbye", say_goodbye_path %>!

这里的 link_to() 方法在 ERB 序列中调用。它创建一个调用 goodbye() action 的 URL 链接。调用 link_to() 的第一个参数是超链接显示的文本,下一个参数是告诉 Rails 生成 goodbye() action 的链接。

让我们思考一下,我们是如何生成链接的。我们编写了如下代码:

link_to "Goodbye", say_goodbye_path

首先,link_to() 是一个方法调用。(在 Rails 中,我们可以调用方法使在模板中编写更加容易)。如果你是从 Java 等语言转换而来,你会惊讶于 Ruby 在方法参数周围居然没有小括号。如果你喜欢,你也可以把小括号加上。

say_goodbye_path 是一个预先计算好在 Rails 的应用 view 中可用的值。它估算了 /say/goodbye 路径。随着时间的推移,你还会 Rails 提供了一个功能,你可以对自己将在应用中使用的路由进行命名。

好的,让我们回到应用。如果我们在浏览器中键入 hello 页面,它现在会包含 goodbye 页面的链接。

我们也可以对 goodbye.html.erb 进行一致的修改,将它链接回开始的 hello 页面。

Goodbye!

It was nice having you here.

Say <%= link_to "Hello", say_hello_path %> again.

这样我们也就完成了这个玩具应用,并且也通过了 Rails 可用的验证。在简单的了解后,是时候去构建一个真正的应用了。

我们完成的事

我们构造了一个玩具应用,它向我们展示了如下几点:

  • 怎样创建一个新的 Rails 应用,以及怎样在应用中创建新的 controller

  • 在 controller 中怎样创建动态内容并通过 view 模板展示

  • 怎样将页面链接起来

这是一个良好的基础学习,它并不需要花费太多时间和精力。这份经验将持续至下一章构建更大的应用时。

自习时间

还有些东西需要你自己尝试:

  • 尝试一下下面的表达式:

    • 加法: <%= 1 + 2 %>
    • 拼接: <%= "cow" + "boy" %>
    • 一个小时后的时间: <%= 1.hour.from_now.localtime %>
  • 调用下面的 Ruby 方法,返回当前路径下所有文件列表

    @file = Dir.glob('*')

    将它设置为一个 controller 中 action 的实例变量,然后通过相应的模板在浏览器中显示列表中的文件名。

    提示:你可以用类似下面的方式遍历集合:

    <% for file in @files %>
      file name is: <%= file %>
    <% end %>
    

    你可以需要用

      显示列表。

    梳理

    也许你已经跟随这章学习并编写了代码。如果是这样,应用已经在你的电脑上运行。当我们开始在第 61 页的 Chapter 6, Task A: Creating the Application 编写下一个应用时,我们运行它时会出现一个冲突,因为它也需要通过 3000 端口与浏览器通讯。现在是时候在你开启应用的窗口中按下 Ctrl-C 将应用停止。Windows 用户可能需要按下 Ctrl-Pause/Break。

    下面让我们去纵览一下 Rails。


    本文翻译自《Agile Web Development with Rails 4》,目的为学习所用,如有转载请注明出处。

你可能感兴趣的:(Instant Gratification)