22
CHAPTER ` 立竿見影 現在,我們來編寫一個簡單的應用程式,以驗證 Rails 已經成功地在 安裝在我們的機器上了。在此過程中,我們會順便瞧瞧 Rails 應用程式的 運作方式。 4.1 建立一個新的應用程式 安裝 Rails 框架的時候,我們還會得到一個新的命令列工具——rails 這個工具用來建構我們編寫的每一個新的 Rails 應用程式。 為什麼需要一個工具來做這件事情?——也就是說,為什麼不開啟最 鍾愛的編輯器,從頭開始為我們的應用程式建立原始程式碼呢?沒錯,我 們確實可以這樣做。畢竟, Rails 應用程式只是 Ruby 的原始程式碼。但 Rails 還可以在幕後變很多戲法,讓我們只需做最少量的顯式配置即可執行應用 程式。為了讓這些戲法能夠生效,Rails 需要找到應用程式中各種各樣的全 部元件。正如我們在後面將會看到的(第 14.2 節「目錄結構」),這就意 味著我們需要建立一種特定的目錄結構,以便將我們編寫的程式碼放在合 適的地方。rails 命令就可以為我們建立這一目錄結構,並配好一些標準的 Rails 程式碼。 為了建立第一個 Rails 應用程式,請打開 shell 視窗,瀏覽到檔案系統 中的某個地方,也就是您想在其中建立應用程式目錄結構的那個地方。在 本書的例子裡,我們將把項目建立在一個名為 work 的目錄中。在該目錄

CHAPTERepaper.gotop.com.tw/pdf/ACL022900.pdf · 為了建立第一個Rails應用程式,請打開shell視窗,瀏覽到檔案系統 中的某個地方,也就是您想在其中建立應用程式目錄結構的那個地方。在

  • Upload
    others

  • View
    2

  • Download
    0

Embed Size (px)

Citation preview

Page 1: CHAPTERepaper.gotop.com.tw/pdf/ACL022900.pdf · 為了建立第一個Rails應用程式,請打開shell視窗,瀏覽到檔案系統 中的某個地方,也就是您想在其中建立應用程式目錄結構的那個地方。在

CHAPTER

立竿見影

現在,我們來編寫一個簡單的應用程式,以驗證 Rails 已經成功地在

安裝在我們的機器上了。在此過程中,我們會順便瞧瞧 Rails 應用程式的

運作方式。

4.1 建立一個新的應用程式 安裝 Rails 框架的時候,我們還會得到一個新的命令列工具——rails。

這個工具用來建構我們編寫的每一個新的 Rails 應用程式。

為什麼需要一個工具來做這件事情?——也就是說,為什麼不開啟最

鍾愛的編輯器,從頭開始為我們的應用程式建立原始程式碼呢?沒錯,我

們確實可以這樣做。畢竟,Rails 應用程式只是 Ruby 的原始程式碼。但 Rails還可以在幕後變很多戲法,讓我們只需做最少量的顯式配置即可執行應用

程式。為了讓這些戲法能夠生效,Rails 需要找到應用程式中各種各樣的全

部元件。正如我們在後面將會看到的(第 14.2 節「目錄結構」),這就意

味著我們需要建立一種特定的目錄結構,以便將我們編寫的程式碼放在合

適的地方。rails 命令就可以為我們建立這一目錄結構,並配好一些標準的

Rails 程式碼。

為了建立第一個 Rails 應用程式,請打開 shell 視窗,瀏覽到檔案系統

中的某個地方,也就是您想在其中建立應用程式目錄結構的那個地方。在

本書的例子裡,我們將把項目建立在一個名為 work 的目錄中。在該目錄

Page 2: CHAPTERepaper.gotop.com.tw/pdf/ACL022900.pdf · 為了建立第一個Rails應用程式,請打開shell視窗,瀏覽到檔案系統 中的某個地方,也就是您想在其中建立應用程式目錄結構的那個地方。在

Part 1 起步

34

裡,使用 rails 命令建立一個名為 demo 的應用程式。此處要稍加小心:如

果已經存在一個名叫 demo 的目錄,rails 就會詢問是否覆蓋已有的檔案。 dave> cd work work> rails demo create create app/controllers create app/helpers create app/models : : : create log/development.log create log/test.log work>

上述命令建立了一個名為 demo 的目錄。進入這個目錄,(在 Unix 中

使用 ls 命令,在 Windows 中使用 dir 命令)列出全部內容。此時應該會看

到一堆檔案和子目錄: work> cd demo demo> ls –p README components/ doc/ public/ tmp/ Rakefile config/ lib/ script/ vendor/ app/ db/ log/ test/

以這麼多目錄(以及它們包含的檔案)開頭,可能會有點兒嚇人,不

過我們一開始可以忽視其中的大部分內容。在這一章,我們只會直接用到

其中的兩個目錄:一個是 app 目錄,我們將在這裡編寫應用程式;另一個

是 script 目錄,其中包含一些有用的工具腳本。

我們先從 script 子目錄開始。其內有一個名為 server 的腳本。該腳本

會啟動一個獨立運作的 web 伺服器,它能夠在 WEBrick 之下執行我們新

建立的 Rails 應用程式。1那麼,不多說了,我們這就開始啟動 demo 應用

程式吧。

1 WEBrick是一個純 Ruby的 web伺服器,隨 Ruby 1.8.1和更高版本發佈。因為它保證能用,所以 Rails 使用它作為開發用的 web 伺服器。不過,如果系統上安裝了名為 Mongrel 或Lighttpd web的伺服器(Rails可以找到其中之一),script/server命令就會優先使用它們,而不是WEBrick。我們可以在命令中使用下列選項來強制 Rails使用WEBrick:

demo>ruby script/server webrick

Page 3: CHAPTERepaper.gotop.com.tw/pdf/ACL022900.pdf · 為了建立第一個Rails應用程式,請打開shell視窗,瀏覽到檔案系統 中的某個地方,也就是您想在其中建立應用程式目錄結構的那個地方。在

Chapter 4 立竿見影

35

demo> ruby script/server => Booting WEBrick... => Rails application started on http://0.0.0.0:3000 => Ctrl-C to shutdown server; call with --help for options [2006-01-08 21:44:10] INFO WEBrick 1.3.1 [2006-01-08 21:44:10] INFO ruby 1.8.2 (2004-12-30) [powerpc-darwin8.2.0] [2006-01-08 21:44:11] INFO WEBrick::HTTPServer#start: pid=10138 port=3000

從啟動追蹤資訊的最後一行可以看出,我們剛剛在埠 3000 上啟動了一

個 web 伺服器。2 打開瀏覽器,存取 URL http://localhost:3000,就可以看

到這個應用程式,如圖 4.1 所示(版本編號可能會有所差別)。

如果看一下啟動 WEBrick 的視窗,就會發現追蹤資訊顯示出我們正在

存取該應用程式。我們要讓 WEBrick 一直在這個命令列視窗中運作。稍

後,在編寫應用程式碼並透過瀏覽器執行它的時候,我們就能夠使用這個

命令列視窗來追蹤進來的請求。要關閉應用程式的時候,在這個視窗中按

control+C 鍵即可停止 WEBrick。(現在先不要關閉,下面我們還會用到

這個特定的應用程式。)

圖 4.1 新建的 Rails應用程式

2 位址中的“0.0.0.0”代表 WEBrick會接收來自所有介面的連結。在 Dave的 OS X系統上,這就意味著本地介面(127.0.0.1和::1)和 LAN連結都包含在內。

Page 4: CHAPTERepaper.gotop.com.tw/pdf/ACL022900.pdf · 為了建立第一個Rails應用程式,請打開shell視窗,瀏覽到檔案系統 中的某個地方,也就是您想在其中建立應用程式目錄結構的那個地方。在

Part 1 起步

36

現在,我們已經啟動了新的應用程式,但其中還沒有我們自己編寫的

程式碼。我們這就開始動手吧!

4.2 Hello, Rails 沒辦法——每次要試用一個新系統時,我都得寫一個“Hello, World!”

程式。在 Rails 中,這個程式會把我們親切的問候發送到瀏覽器上。

正如我們在第 2 章「Rails 應用的架構」中看到的,Rails 是一個

Model-View-Controller 框架。Rails 會接收來自瀏覽器的請求,解讀請求

以找到合適的控制器,並呼叫該控制器中的一個 action 方法。然後,控制

器會呼叫一個特定的視圖(view),將結果顯示給使用者。好在 Rails 已

經幫我們搞定了絕大部分的內部管道,這些管道把所有這些 action 連結了

起來。為了寫出這個簡單的“Hello, World!”應用程式,我們需要編寫一

個控制器和一個視圖。我們不需要編寫模型,因為我們不用處理任何資料。

讓我們從控制器開始吧。

就像用 rails 命令新建一個 Rails 應用程式那樣,我們也可以使用一個

產生器腳本來為我們的項目新建一個控制器。這個命令叫做 generate,就

在我們建立的 demo 項目的 script 子目錄中。所以,為了建立一個名為 Say的控制器,我們就要確保當前在 demo 目錄中,然後執行該腳本,把想要

建立的控制器的名稱傳遞過去。3

demo> ruby script/generate controller Say exists app/controllers/ exists app/helpers/ create app/views/say exists test/functional/ create app/controllers/say_controller.rb create test/functional/say_controller_test.rb create app/helpers/say_helper.rb

3 「控制器名稱」這個概念實際上要比我們想像的更複雜,我們會在第 14.4 節「命名慣例」中詳細講解。現在,我們就假定該控制器叫做 Say好了。

Page 5: CHAPTERepaper.gotop.com.tw/pdf/ACL022900.pdf · 為了建立第一個Rails應用程式,請打開shell視窗,瀏覽到檔案系統 中的某個地方,也就是您想在其中建立應用程式目錄結構的那個地方。在

Chapter 4 立竿見影

37

該腳本會為它檢查的檔案和目錄產生日誌,記錄它向應用程式添加新

的 Ruby 腳本或目錄的時間。現在,我們感興趣的是其中的一個腳本,以

及新增的目錄。

我們馬上要看的是控制器的原始程式碼。在文件 app/controllers/say_ controller.rb 中可以找到它。讓我們看看這個檔。 work/demo1/app/controllers/say_controller.rb class SayController < ApplicationController end

小得很,是嗎?因為 SayController 是一個從 ApplicationController 繼承而來的空白類別,所以它會自動獲得所有預設的控制器行為。讓我們來

給它添加一點佐料。我們需要加入一些程式碼,讓控制器處理進入的請求。

這些程式碼必須做些什麼?現在,它什麼都不用做——我們只需要一個空

的 action 方法。所以,下一個問題是:這個方法應該叫什麼名字?為了回

答這個問題,我們需要先來看看 Rails 處理請求的方式。

Rails和 URL請求

就像其他 web 應用程式一樣,Rails 應用程式在其使用者看來是與一個

URL 相關聯的。把瀏覽器指向那個 URL 時,就開始了與應用程式碼的對

話,程式碼會為我們產生回應。

不過,真實的情況要比這更加複雜。試想我們的應用程式可透過下列

位址存取:http://pragprog.com/。存放應用程式的 web 伺服器在路徑方面

相當聰明。它知道對這個 URL 的請求必須與應用程式對話。URL 中在此

之後的路徑內容不會改變這一點——同樣的應用程式仍然會被呼叫。後續

的路徑資訊會傳遞給應用程式,應用程式可以針對自身內部的用途來使

用它。

Page 6: CHAPTERepaper.gotop.com.tw/pdf/ACL022900.pdf · 為了建立第一個Rails應用程式,請打開shell視窗,瀏覽到檔案系統 中的某個地方,也就是您想在其中建立應用程式目錄結構的那個地方。在

Part 1 起步

38

Rails 會根據路徑來判斷要使用的控制器的名稱,以及要在該控制器上

呼叫的 action 的名稱,4如圖 4.2 所示。路徑中緊跟在應用程式名稱之後的

第一部分是控制器名稱,第二部分是 action 名稱,如圖 4.3 所示。

圖 4.2 URL被對應到控制器和 action上

圖 4.3 Rails將請求導向控制器和 action

第一個 action

讓我們給 say 控制器加上一個名為 hello 的 action。從上一節的講解可

以得知,加上一個名為 hello 的 action,就意味著在 SayController 類別中

建立一個名為 hello 的方法。但這個方法應該做些什麼呢?現在,它什麼

4 Rails在解析 URL的時候相當靈活。本章描述的是預設的 URL解析機制。在第 20.2節「請求的路由」中,我們將展示改變這一機制的方法。

1. 應用程式 URL位址的第一部份

2. 然後是控制器(say)

3. 以及 action(hello)

建立一個 SayController 的實體

並且觸發 action方法 hello

Page 7: CHAPTERepaper.gotop.com.tw/pdf/ACL022900.pdf · 為了建立第一個Rails應用程式,請打開shell視窗,瀏覽到檔案系統 中的某個地方,也就是您想在其中建立應用程式目錄結構的那個地方。在

Chapter 4 立竿見影

39

都不用做。要記住,控制器的職責就是提供資訊,以便讓視圖知道該顯示

什麼。在我們的第一個應用程式中,沒有任何資訊需要控制器提供,所以

一個空的 action 方法就可以了。使用鍾愛的編輯器修改 app/controllers 目錄下的 say_controller.rb 檔案,在其中加上 hello 方法: work/demo1/app/controllers/say_controller.rb class SayController < ApplicationController def hello end end

現在讓我們試著呼叫它。在瀏覽器視窗中瀏覽到下列 URL :

http://localhost:3000/say/hello。(請注意:在開發環境下,路徑中沒有包

含應用程式名稱——我們直接導向控制器。)我們會看到類似下面的效果:

也許有些惱人,但這個錯誤是絕對合理的(除了錯誤提示中那個古怪

的路徑之外)。我們建立了控制器類別和 action 方法,但沒有告訴 Rails該顯示什麼東西。這就要用到視圖了。還記得我們執行腳本、建立新控制

器時的情景嗎?那個腳本為應用程式添加了三個檔案和一個新目錄。這個

目錄就是用來存放控制器視圖的樣板檔的。在這裡,我們建立了一個名為

say 的控制器,所以視圖就應該位於 app/views/say 目錄中。

為了完成這個“Hello, World!”應用程式,我們來建立一個樣板。預

設情況下,Rails 會在與當前處理的 action 同名的檔案中尋找樣板。在這個

例子中,就意味著我們需要在 app/views/say 目錄中建立一個名為

hello.rhtml 的文件。(為什麼是.rhtml?我們稍後就會解釋。)現在,我們

只在其中放入一些基本的 HTML 程式碼。

Page 8: CHAPTERepaper.gotop.com.tw/pdf/ACL022900.pdf · 為了建立第一個Rails應用程式,請打開shell視窗,瀏覽到檔案系統 中的某個地方,也就是您想在其中建立應用程式目錄結構的那個地方。在

Part 1 起步

40

work/demo1/app/views/say/hello.rhtml <html> <head> <title>Hello, Rails!</title> </head> <body> <h1>Hello from Rails!</h1> </body> </html>

保存 hello.rhtml 檔,並刷新瀏覽器視窗。此時應該看到一句友好的問

候。請注意,我們不需要重新開機應用程式就可以看到更新後的效果。在

開發的過程中,每次存檔時,Rails 就會自動將修改結果整合到正在運作的

應用程式中。

到目前為止,我們已經在 Rails 應用程式的兩個檔案中加入程式碼。

我們在控制器中添加了一個 action,又建立了一個樣板以便在瀏覽器中顯

示頁面。這些檔案都位於 Rails 層級的標準位置中:控制器在 app/controllers目錄下,視圖在 app/views 中各自的子目錄下,如圖 4.4 所示。

圖 4.4 控制器和視圖的標準位置

Page 9: CHAPTERepaper.gotop.com.tw/pdf/ACL022900.pdf · 為了建立第一個Rails應用程式,請打開shell視窗,瀏覽到檔案系統 中的某個地方,也就是您想在其中建立應用程式目錄結構的那個地方。在

Chapter 4 立竿見影

41

讓它動起來

到目前為止,我們的 Rails 應用程式還相當老土——它只能顯示一個

靜態頁面。為了使它更具動感,我們讓它在每次顯示頁面時順便顯示出當

前的時間。

為實現這一效果,我們需要對視圖中的樣板檔稍加修改——現在它需

要以字串的形式把「時間」這項資訊包含進來。這就會引發兩個問題。首

先,如何在樣板中添加動態內容?其次,要顯示的「時間」資訊從哪裡來?

動態內容

在 Rails 中,建立動態樣板有兩種方式。5其一是使用一項名為“Builder

(構建器)”的技術,我們將在第 22.1 節「Builder 樣板」中介紹這種方式。

第二種方式也就是我們要在這裡使用的:將 Ruby 程式碼嵌入到樣板中。

這也就是我們要把樣板檔命名為 hello.rhtml 的原因:.rhtml 尾碼會告訴

Rails,應該使用一個名為 Erb(即 Embedded Ruby,嵌入式 Ruby)的系

統對檔案的內容進行擴展。

ERb 是一個篩檢程式:進來的是.rhtml 檔案,出去的是經過轉換的內

容。在 Rails 中,輸出的檔案通常是 HTML 格式,但也可以是其他任何格

式。普通的內容會直進直出,沒有任何變化。但<%=和%>符號之間的內容

則會被看做 Ruby 程式碼加以執行。執行的結果將被轉換成字串,並替換

到檔案中<%...%>序列所在的位置。例如,我們在 hello.rhtml 中加入下列

內容: erb/ex1.rhtml <ul> <li>Addition: <%= 1+2 %> </li> <li>Concatenation: <%= "cow" + "boy" %> </li> <li>Time in one hour: <%= 1.hour.from_now %> </li> </ul>

5 實際上有三種方式,但是第三種(rjs)僅適用於向已顯示的頁面中施加 AJAX魔法的情況。我們將在第 668頁討論 rjs。

Page 10: CHAPTERepaper.gotop.com.tw/pdf/ACL022900.pdf · 為了建立第一個Rails應用程式,請打開shell視窗,瀏覽到檔案系統 中的某個地方,也就是您想在其中建立應用程式目錄結構的那個地方。在

Part 1 起步

42

更新瀏覽器畫面,樣板就會產生下列 HTML:

<ul> <li>Addition: 3 </li> <li>Concatenation: cowboy </li> <li>Time in one hour: Tue May 16 08:55:14 CDT 2006 </li> </ul>

在瀏覽器視窗中,會看到下面的內容:

Addition: 3

Concatenation: cowboy

Time in one hour: Sun May 07 16:06:43 CDT 2006

另外,在.rhtml 檔案中,<%與%>符號(前者沒有等號)之間的內容

會被看做 Ruby 程式碼執行,但執行的結果不會替換到輸出畫面。有趣的

是,這種程式處理可以與非 Ruby 程式碼混合使用。例如,我們可以編寫

一個節慶版本的 hello.rhtml。 <% 3.times do %> Ho!<br /> <% end %> Merry Christmas!

這會產生以下 HTML 程式碼: Ho!<br /> Ho!<br /> Ho!<br /> Merry Christmas!

注意:每當 Ruby 迴圈執行一次,其檔案中的文字就會被發送到輸出流。

但這裡也有一些奇怪的地方:所有空行都來自何處?它們皆來自輸入

文件。如果留意一下,就會發現原文件第一行和第三行的%>之後緊跟著一

個或多個行尾字元。所以,<% 3.times do %>雖已從檔案中剝離,但新行

卻留了下來。每次執行迴圈時,新行就會連同“Ho!”行的所有文字添加

Page 11: CHAPTERepaper.gotop.com.tw/pdf/ACL022900.pdf · 為了建立第一個Rails應用程式,請打開shell視窗,瀏覽到檔案系統 中的某個地方,也就是您想在其中建立應用程式目錄結構的那個地方。在

Chapter 4 立竿見影

43

到輸出檔案中。這就產生了輸出中每個“Ho!”行之前的空行。類似的道

理,<% end %>之後的新行就促成了“%last Ho!”和“Merry Christmas!”行之間的空行。

一般情況下,這無關緊要,因為 HTML 並不怎麼關心空白區域。不過,

如果是使用此樣板機制建立電子郵件或<pre>區塊內的 HTML,那就要刪

除這些空行。為此,將 ERb 序列末尾的%>改為-%>即可。這個減號會告訴

Rails:應該刪除輸出中帶有的所有新行。如果我們在“3.times”行加上一

個減號: <% 3.times do -%> Ho!<br /> <% end %> Merry Christmas!

讓開發過程更簡單

大家應該已經注意到我們目前所做的開發工作。在應用程式中添加程式

碼之後,我們無須重新開機正在運作的應用程式。新的內容已經在伺服

器端快樂地運轉了。而且當我們透過瀏覽器存取應用程式的時候,所做

的每一項修改就會體現出來。為什麼會這樣?

這說明基於 WEBrick的 Rails分發器是相當聰明的。在開發模式下(另

外的兩種模式是測試模式和生產模式),每當有新的請求進來,它都會

自動重新載入應用程式原始檔案。這樣一來,當我們編輯應用程式的時

候,分發器就會確保現正執行的是最近的修改結果。這對於開發來說是

件好事。

然而這種靈活性也是有代價的:它會在「用戶輸入 URL」與「應用程式

做出回應」之間造成一個短暫的間隔。這段間隔就是由分發器重新載入

檔案造成的。在開發階段,這是值得付出的代價;但在投入真實運作之

後,這就是不能接受的。因此,這項特性在生產模式下是被禁用的(詳

見第 27章「部署與生產」)。

Page 12: CHAPTERepaper.gotop.com.tw/pdf/ACL022900.pdf · 為了建立第一個Rails應用程式,請打開shell視窗,瀏覽到檔案系統 中的某個地方,也就是您想在其中建立應用程式目錄結構的那個地方。在

Part 1 起步

44

將會得到下列輸出: Ho!<br /> Ho!<br /> Ho!<br /> Merry Christmas!

在包含行尾字元的行中添加一個減號: <% 3.times do -%> Ho!<br /> <% end -%> Merry Christmas!

去掉 Merry Christmas 前面的空行: Ho!<br /> Ho!<br /> Ho!<br /> Merry Christmas!

一般來說,去掉這些新行只是一種個人習慣,並不是必需的。但是,

我們會看到使用減號的 Rails 程式碼無處不在,所以最好知道它是怎麼回事。

在下面的例子中,迴圈會設定一個變數值,該變數值會在迴圈每次執

行的時候插入到文字中: erb/ex3.rhtml <% 3.downto(1) do |count| -%> <%= count %>...<br /> <% end -%> Lift off!

這個樣板會把下列內容發送給瀏覽器: 3...<br /> 2...<br /> 1...<br /> Lift off!

關於 ERb 功能,還有最後一點需要說明。很多時候,用<%=...%>產生

的替代值會包含“<”和“&”這兩個對 HTML 很有意義的符號。為了防

Page 13: CHAPTERepaper.gotop.com.tw/pdf/ACL022900.pdf · 為了建立第一個Rails應用程式,請打開shell視窗,瀏覽到檔案系統 中的某個地方,也就是您想在其中建立應用程式目錄結構的那個地方。在

Chapter 4 立竿見影

45

止這些符號把頁面搞亂(以及避免潛在的安全性問題,詳見第 26 章「保護

Rails 應用程式的安全」),我們應該對這些字元進行轉碼。Rails 有一個

輔助的 h 方法可以做這件事。大多數時候,我們會在把值替換到 HTML 頁

面中時用到這個方法。 erb/ex4.rhtml Email: <%= h("Ann & Bill <[email protected]>" ) %>

在這個例子中,h 方法保證了郵寄地址中的特殊字元不會擾亂瀏覽器

的顯示結果——它們會被轉碼為 HTML 實體。用戶在瀏覽器中會看到

“Email: Ann &amp; Bill &lt;[email protected]&gt;”字樣,特殊字元也

會正確地顯示出來。

添加時間顯示

我們的初衷是向使用者顯示當前的時間。現在我們已經知道如何在應

用程式中顯示動態資料。第二個必須解決的問題就是:從哪裡獲取時間?

有一種方法是在 hello.rhtml 樣板中嵌入對 Ruby 的 Time.now 方法的

呼叫。 <html> <head> <title>Hello, Rails!</title> </head> <body> <h1>Hello from Rails!</h1> <p> It is now <%= Time.now %> </p> </body> </html>

這個辦法行得通。只要存取這個頁面,使用者就會看到當前的時間。

對於我們這個小例子,此方法可能已經夠好了。但是,通常情況下,我們

可能要採用一種略微不同的做法。我們將把確定所顯示時間的工作移到控

制器中,讓視圖只承擔顯示時間的簡單職責。因此,我們要更改控制器中

的 action 方法,將時間值放在名為@time 的執行區域變數中。

Page 14: CHAPTERepaper.gotop.com.tw/pdf/ACL022900.pdf · 為了建立第一個Rails應用程式,請打開shell視窗,瀏覽到檔案系統 中的某個地方,也就是您想在其中建立應用程式目錄結構的那個地方。在

Part 1 起步

46

work/demo2/app/controllers/say_controller.rb class SayController < ApplicationController def hello @time = Time.now end end

在.rhtml 樣板中,我們將使用這個執行區域變數把時間替換到輸出結

果裡。 work/demo2/app/views/say/hello.rhtml <html> <head> <title>Hello, Rails!</title> </head> <body> <h1>Hello from Rails!</h1> <p> It is now <%= @time %> </p> </body> </html>

更新瀏覽器視窗的時候,我們會看到時間以 Ruby 的標準格式顯示出來:

注意:如果按一下瀏覽器的「重新整理」按鈕,時間會在每次顯示頁

面的時候更新。看起來,我們確實已經製造出了動態的內容。

為什麼要在控制器中獲取要顯示的時間,然後在視圖中使用它呢?這

不是自找麻煩嗎?問得好。在這個應用程式中,我們本可以簡單地在樣板

中嵌入對 Time.now 方法的呼叫,但是把這一呼叫放進控制器會帶來一些

好處。例如,也許我們將來會想對應用程式進行擴展,使其支援多國用戶。

在這種情況下,我們就要對時間的顯示加以本地語系化:不僅要選擇適合

使用者當地的顯示格式,還要提供與他們所在時區相應的時間。這些邏輯

Page 15: CHAPTERepaper.gotop.com.tw/pdf/ACL022900.pdf · 為了建立第一個Rails應用程式,請打開shell視窗,瀏覽到檔案系統 中的某個地方,也就是您想在其中建立應用程式目錄結構的那個地方。在

Chapter 4 立竿見影

47

應該屬於應用級程式碼,可能並不適合嵌在視圖中。透過在控制器中設置

要顯示的時間,就可以使應用程式更加靈活:我們可以在控制器中修改顯

示格式和時區設置,而不必更新使用該時間物件的視圖。時間資訊是一種

資料,應該由控制器提供給視圖。當我們在等式中引入模型時,會看到更

多這樣的資料。

視圖如何獲取時間?

在講解視圖和控制器的時候,我們展示了那個把要顯示的時間放進一個

執行區域變數的控制器。.rhtml 檔案使用這個執行區域變數取代了當前

的時間。但是,控制器物件中的執行區域變數是 private 的。那麼 ERb

又是如何得到這個 private的資料,並在樣板中使用的呢?

答案既簡單又有些微妙。Rails施了一些 Ruby魔法,使得控制器物件中

的執行區域變數被注射到了樣板物件中。其結果就是:視圖樣板可以存

取控制器中的任何執行區域變數,就好像是存取它們自己的執行區域變

數一樣。

有些人會抓住這一點:「我只想知道這些變數的“get, set”方法是怎麼

操作的?」這些人顯然並不相信魔法,還是別和他們一起過耶誕節了。

重點複習

讓我們簡單回顧一下當前的應用程式的運作方式。

1. 使用者透過瀏覽器瀏覽到我們的應用程式。在這裡,我們使用的是一個本

地 URL,如 http://localhost:3000/say/hello。

2. Rails對 URL進行分析。say這一部分被視為控制器的名稱,所以 Rails會

為(在 app/controllers/say_controller.rb 檔案中找到的)SayController

這個 Ruby類別新建一個實體。

3. URL路徑的下一部分(hello)被視為 action的名稱。Rails會呼叫控制器

中一個名稱為 hello 的方法。這個 action 方法會新建一個承載當前時間的

Time物件,並將其放進@time執行區域變數中。

Page 16: CHAPTERepaper.gotop.com.tw/pdf/ACL022900.pdf · 為了建立第一個Rails應用程式,請打開shell視窗,瀏覽到檔案系統 中的某個地方,也就是您想在其中建立應用程式目錄結構的那個地方。在

Part 1 起步

48

4. Rails會尋找一個樣板來顯示結果。它會到 app/views目錄中尋找與控制器

(say)同名的子目錄,然後在該子目錄中尋找與 action名稱(hello.rhtml)

相符的檔案。

5. Rails會通過 ERb對這個樣板進行處理,執行其中嵌套的 Ruby程式碼,並

把由控制器提供的值替換進去。

6. 處理的結果被傳回給瀏覽器,且 Rails結束對這一請求的處理。

這並不是故事的全部——Rails 給了我們很多機會,可以對基本流程進

行調整(我們很快就會用到這些機會)。我們這個故事的意義在於:它體

現了慣例重於配置(convention over configuration)的原則,這是 Rails的基本思想之一。透過提供便利的預設配置和應用某些慣例,Rails 應用程

式通常只需要很少或者不使用外部配置——應用程式的各個部分以一種很

自然的方式就自行組合了起來。

4.3 把頁面連起來 很少有 web 應用只有一個頁面。讓我們看看如何能替“Hello,

World!”應用程式再加一個漂亮的 web 設計實例。

通常,應用程式中的每一頁面會對應一個單獨的視圖。在這個例子中,

我們還要使用一個新的 action 方法來處理頁面(儘管情況並非總是如此,

正如我們將在本書後面的部分所看到的)。我們將會為兩個 action 方法使

用相同的控制器。同樣,不一定非要這樣,但目前我們並沒有特別的理由

去使用一個新的控制器。

我們已經知道如何替 Rails 應用程式添加新的視圖和 action。若要添加

action,我們應在控制器中定義一個新方法。假設這個 action 叫做

goodbye。現在,我們的控制器看起來就像這樣: work/demo3/app/controllers/say_controller.rb class SayController < ApplicationController def hello @time = Time.now end

Page 17: CHAPTERepaper.gotop.com.tw/pdf/ACL022900.pdf · 為了建立第一個Rails應用程式,請打開shell視窗,瀏覽到檔案系統 中的某個地方,也就是您想在其中建立應用程式目錄結構的那個地方。在

Chapter 4 立竿見影

49

def goodbye end end

接下來,我們必須在 app/views/say 目錄中建立一個新的樣板。這一

次,它的名字叫做 goodbye.rhtml,因為在預設情況下,樣板是根據相關聯

的 action 命名的。 work/demo3/app/views/say/goodbye.rhtml <html> <head> <title>See You Later!</title> </head> <body> <h1>Goodbye!</h1> <p> It was nice having you here. </p> </body> </html>

再次開啟瀏覽器,但這一次要使用如下 URL 指向新的視圖:

http://localhost:3000/say/goodbye。此時應該看到下列內容:

現在,我們需要把這兩個頁面連結起來。我們要在 hello 頁面上放一

個連結,讓它把我們帶到 goodbye 頁面;反過來,後者也應該有一個指向

前者的連結。在真實的應用程式中,我們可能要把這些連結做成合適的按

鈕,但現在只要使用超連結就可以了。

我們已經知道,Rails 會按照命名慣例將 URL 解析為「目標控制器」

和「該控制器內的一個 action」兩部分。所以,我們的連結也應該採納這

一 URL 慣例。在文件 hello.rhtml 中加入下列內容:

Page 18: CHAPTERepaper.gotop.com.tw/pdf/ACL022900.pdf · 為了建立第一個Rails應用程式,請打開shell視窗,瀏覽到檔案系統 中的某個地方,也就是您想在其中建立應用程式目錄結構的那個地方。在

Part 1 起步

50

<html> ... <p> Say <a href="/say/goodbye" >Goodbye</a>! </p> ...

goodbye.rhtml 檔案則指向另一個地方: <html> ... <p> Say <a href="/say/hello" >Hello</a>! </p> ...

這種辦法當然管用,但有點脆弱:如果我們把應用程式搬到 web 伺服

器的另一個地方,這些 URL 就會失效。而且,這還把 Rails 對 URL 格式

的解讀直接寫進了程式碼中,而 Rails 將來的版本有可能會改變這一解讀

方式。

好在,我們不必非冒這個險。Rails 提供了一大堆可以在視圖樣板中使

用的輔助方法。這裡,我們將使用 link_to 輔助方法,該方法會建立一個指

向某個 action 的超連結。6用上 link_to 方法之後,hello.rhtml 就變成了:

work/demo4/app/views/say/hello.rhtml <html> <head> <title>Hello, Rails!</title> </head> <body> <h1>Hello from Rails!</h1> <p> It is now <%= @time %>. </p> <p> Time to say <%= link_to "Goodbye!" , :action => "goodbye" %> </p> </body> </html>

6 方法可以做的還遠不止這些,不過別著急,讓我們慢慢來……

Page 19: CHAPTERepaper.gotop.com.tw/pdf/ACL022900.pdf · 為了建立第一個Rails應用程式,請打開shell視窗,瀏覽到檔案系統 中的某個地方,也就是您想在其中建立應用程式目錄結構的那個地方。在

Chapter 4 立竿見影

51

有一個<%=...%>ERb 序列嵌入了對 link_to 的呼叫。這會建立一個指

向呼叫 goodbye 這個 action 的 URL 的連結。在 link_to 呼叫中,第一個參

數是超連結中顯示的文字,第二個參數則是讓 Rails 產生到 goodbye 這個

action 的連結。由於我們沒有指定控制器,所以 Rails 會使用當前的控制器。

我們不妨停下幾分鐘,考慮一下這個連結是如何產生的。我們剛才寫下了:

link_to "Goodbye!" , :action => "goodbye"

首先,link_to 是一個方法呼叫。(在 Rails 中,我們會呼叫方法以使

得樣板輔助方法的編寫更加容易。)如果原來使用的是諸如 Java 之類的語

言,可能會感覺驚訝,因為 Ruby 不必非在方法參數兩邊放上括弧。我們

總是可以根據自己的喜好選擇加或不加。

:action 是一個 Ruby 符號。我們可以把這裡的冒號看做「名叫……的

東西」,所以:action 就表示「名叫 action 的東西」。7後面的=>"goodbye"

則是將字串 goodbye 與名稱 action 關聯起來。從效果上來說,這就使我們

在呼叫方法時可以使用一些關鍵字參數。Rails 大量地利用了這一便利

性——只要一個方法接收多個參數,並且其中一些參數是選擇性的,我們

就可以透過關鍵字參數來傳遞這些參數值。

好了,言歸正傳。現在,如果用瀏覽器查看 hello 頁面,其中就會有

一個指向 goodbye 頁面的連結,如下圖所示。

我們可以在 goodbye.rhtml 中做相應的更改,將其連回到開始的 hello頁面。

7 與其他語言的特性不同,第一次使用 Ruby的時候,「符號」這個詞可能會造成一些混淆。我們試過很多不同的解釋,但沒有一種解釋能夠對所有人適用。現在,我們把 Ruby符號看做是一個不帶任何字串方法的常數字串就可以了。它是名稱標籤,而不是人。

Page 20: CHAPTERepaper.gotop.com.tw/pdf/ACL022900.pdf · 為了建立第一個Rails應用程式,請打開shell視窗,瀏覽到檔案系統 中的某個地方,也就是您想在其中建立應用程式目錄結構的那個地方。在

Part 1 起步

52

work/demo4/app/views/say/goodbye.rhtml <html> <head> <title>See You Later!</title> </head> <body> <h1>Goodbye!</h1> <p> It was nice having you here. </p> <p> Say <%= link_to "Hello" , :action => "hello" %> again. </p> </body> </html>

4.4 本章回顧 本章,我們建構了一個小不點兒應用程式。在此過程中,我們學會了:

如何新建一個 Rails應用程式,以及如何在其中新建控制器,

Rails如何將用戶請求對應到對程式碼的呼叫,

如何在控制器中建立動態內容,以及如何透過視圖樣板顯示動態內容,

如何把頁面連結起來。

這是一個很好的開始。下面,讓我們開始建造一個真實的應用程式吧。

遊戲時間

試著親自動手做一些東西吧。

為 say應用程式寫一個頁面,表現出在 ERb中可以執行的迴圈。

嘗試添加和刪除<%= %> ERb 序列末尾的減號(也就是說,將%>改為

-%>,反之亦然)。用瀏覽器的「檢視→檢視原始檔」選項查看不同之處。

呼叫下列 Ruby方法會傳回一個當前目錄中所有檔案的列表。

@files = Dir.glob('*' )

Page 21: CHAPTERepaper.gotop.com.tw/pdf/ACL022900.pdf · 為了建立第一個Rails應用程式,請打開shell視窗,瀏覽到檔案系統 中的某個地方,也就是您想在其中建立應用程式目錄結構的那個地方。在

Chapter 4 立竿見影

53

用它在控制器 action中設置一個執行區域變數,然後寫一個對應的樣板,

在瀏覽器中顯示出清單中的檔名。

提示:在 Erb範例中,我們看到了反覆運算 n次的方法。可以使用下列程

式碼來反覆運算某個集合:

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

我們可能要對列表使用<ul>。

(有關提示的詳情,請參閱

http://wiki.pragprog.com/cgi-bin/wiki.cgi/RailsPlayTime。)

結尾

讀者可能一直跟著我們的講解,寫出了本章中的程式碼。如果是這樣,

那麼這個應用程式應該仍然在電腦上運作著。我們很快就要開始編寫下一

個應用程式了,在第一次運作該程式的時候會出現衝突,因為它也會設法

使用埠 3000 與瀏覽器對話。因此,現在就可以在啟動當前應用程式的視窗

中按 control+C 鍵停止該應用程式了。

Page 22: CHAPTERepaper.gotop.com.tw/pdf/ACL022900.pdf · 為了建立第一個Rails應用程式,請打開shell視窗,瀏覽到檔案系統 中的某個地方,也就是您想在其中建立應用程式目錄結構的那個地方。在

Part 1 起步

54