More at rubyonrails.org: Overview | Download | Deploy | Code | Screencasts | Documentation | Ecosystem | Community | Blog

Rails 初上手指南

這份文件涵蓋了如何上手使用 Ruby on Rails。閱讀之後您應該可以熟悉:

這份文件基於 Rails 3.0。某些程式碼無法運行於舊版 Rails。

1 前提條件

這份指南的目標是為了幫助初學者從頭開始學習 Rails 應用程式,而不需要有任何 Rails 經驗。不過要能夠讀的懂,還是需要一些前提:

Ruby 1.8.7 p248 和 p249 已知有 marshaling 臭虫會搞爛 Rails 3.0。而 Ruby Enterprise Edition 需要 1.8.7-2010.02 之後的版本。1.9.1 也不適用有 segfaults,所以如果你要用 1.9 系列請從 1.9.2 開始。

Rails 是一套使用 Ruby 的 Web 框架。如果您對 Ruby 一無所知就一頭栽進 Rails,您的學習曲線會非常陡峭。以下是一些網路上的免費 Ruby 學習資源:

2 什麼是 Rails?

Rails 是個使用 Ruby 程式語言開發的網站開發架構。它的是設計目標是只要開發者熟悉它的慣例,它就可以讓網站開發變的非常容易。而相對於其他程式語言和框架,Rails 可以讓你用更少的程式碼達成更多的功能。經驗豐富的 Rails 開發者也表示它讓網站開發更有趣了。

Rails 也是個很有主見(opinionated)的軟體。意思是說它假定事情有"最佳解",而且它也被設計成鼓勵那麼做 – 而不鼓勵其他作法。如果你學會所謂的 “The Rails Way” 的話,你的生產力非常可能獲得極大的增長。但如果你硬套用其他語言的習慣或模式來使用 Rails,你可能會有不愉快的使用經驗。

Rails 的哲學包括以下指導原則:

  • DRY – “不要重複自己(Don’t Repeat Yourself)” – 撰寫出重複的程式碼是件壞事
  • 慣例勝於設計(Convention Over Configuration) – Rails 會假設什麼是你要做的事情跟如何去做,而不是要求你設定每一個細節到設定檔中。
  • REST 是 Web 應用程式的最佳模式 – 使用 Resources 和標準的 HTTP verbs(動詞)來組織你的應用程式是最快的方式

2.1 MVC 架構

Rails 的核心是 Model, View 和 Controller 的架構,通常稱作 MVC。MVC 的好處包括:

  • 從使用者介面中把商業邏輯隔離出來
  • 更容易使程式保持 DRY
  • 容易維護,讓不同的程式碼乾淨地放在屬於它的地方
2.1.1 Models

Model 代表了應用程式的資料和操作資料的邏輯。在 Rails 中,Models 主要的功能是負責操作資料庫資料表。在大多數的情況,一個資料表就對應了一個 Model。你的應用程式商業邏輯也會放在 Models 中。

2.1.2 Views

Views 代表了應用程式的使用者介面。在 Rails 中,Views 通常就是有內嵌 Ruby 程式(可以操縱如何顯示資料)的 HTML 檔案。Views 負責提供資料給瀏覽器或其他發 HTTP 請求的軟體。

2.1.3 Controllers

Controllers 是 Models 和 Views 之間的黏著劑。在 Rails 中,Controllers 負責處理從瀏覽器進來的 HTTP 請求,並對 Models 詢問資料,然後將資料傳進 Views 中顯示出來。

2.2 Rails 元件

Rails 包含許多個別的元件:

  • Action Pack
    • Action Controller
    • Action Dispatch
    • Action View
  • Action Mailer
  • Active Model
  • Active Record
  • Active Resource
  • Active Support
  • Railties
2.2.1 Action Pack

Action Pack 是個包含 Action Controller、Action View 和 Action Dispatch 的 gem。也就是 “MVC” 中的 “VC” 部分。

2.2.2 Action Controller

Action Controller 是 Rails 應用程式中,管理 Controllers 的元件。Action Controller 框架處理傳給 Rails 的 HTTP 請求,萃取出參數,然後分派給所屬的 Action。Action Controller 還提供了 session 管理、樣板演算顯示(template rendering) 和 redirect 功能。

2.2.3 Action View

Action View 負責 Rails 應用程式中的 Views。它預設可以產生 HTMLXML 輸出。Action View 負責樣板的演算顯示(template rendering),包括嵌套(nesting)或局部(partial)樣板,甚至也內建支援一些 Ajax。

2.2.4 Action Dispatch

Action Dispatch 處理 HTTP 請求的路由(routing),它把 HTTP 請求發派(dispatch)到它該去的地方,也許是你的應用程式或其他 Rack 程式。

2.2.5 Action Mailer

Action Mailer 是個建構 E-mail 功能的框架。你可以使用 Action Mailer 來接收來信,或是使用樣板來寄出純文字或複雜的 multipart 信件。

2.2.6 Active Model

Active Model 在 Action Pack gem 和 ORM gem (例如 Active Record) 之間定義了一組介面。Active Model 允許 Rails 可以依你的需求把 Active Record 換成其他 ORM 框架。

2.2.7 Active Record

Active Record 是 Rails 應用程式中的 Models 基礎。它不依存特定的資料庫系統,提供了 CRUD 功能、先進的查詢能力以及可以跟其他 Models 關聯的本事。

2.2.8 Active Resource

Active Resource 提供了與其他商業物件和 RESTful 網路服務的連結框架。它實作了一種可以對應以 Web 為基礎的 Resources 成為本地端支援 CRUD 的物件。

2.2.9 Active Support

Active Support 是 Rails 裡的工具函式庫,它也擴充了一些 Ruby 標準函式庫。除了被用在 Rails 核心程式中,你也可以在你的程式中使用。

2.2.10 Railties

Railties 是 Rails 的核心程式碼,用來把以上各種的框架函式庫以及 Plugin 全部組合在一起。

2.3 REST

REST 代表了 “Representational State Transfer” (表象化狀態轉變),它也是 RESTful 架構的基礎概念。它被認為出自於 Roy Fielding 的博士論文 Architectural Styles and the Design of Network-based Software Architectures 。當你閱讀這篇論文的時候,REST 被 Rails 濃縮成兩個主要定理:

  • 使用 Resource 來當做識別資源,也就是使用 URLs 來代表 Resources
  • Transferring representations of the state of that resource between system components (譯註:????)

例如,對 Rails 應用程式來說,這樣的 HTTP 請求:

DELETE /photos/17

被解讀為指向 photo resource 的 ID 17,並帶著一個動作 – 刪除這個 resource。REST 對 Web 應用程式來說是一種天生的設計風格,而 Rails 幫你把這個概念包裝實作出來,並且免於眾多繁雜 RESTful 理論及瀏覽器怪癖之苦。

如果你想知道更多關於 REST 架構風格,以下資源比起 Fielding 的論文更容易親近:

3 建立新的 Rails 專案

接下來的範例,你將建立一個叫做 blog 的 Rails 專案,是個非常簡單的部落格系統。在你開始建構這個應用之前,需要確認你的 Rails 已經安裝妥當。

3.1 安裝 Rails

大多數的情況,最簡單的安裝方式是透過 Rubygems:

通常會用 root user 來執行: $ gem install rails

目前還是 Rails 3.0.0-beta 尚未正式發行 Rails 3.0,所以你必須執行 gem install rails —pre

如果你使用 Windows,你可以安裝看看 Instant Rails ,不過要注意它的 Rails 版本比較舊不相容。另外你也會發現 Rails 跑在 Windows 很慢。所以可能的話,我們建議你裝在 Linux 虛擬機器上跑 Rails,而不是 Windows。(譯註:建議使用 RubyInstall 安裝 Ruby 1.8.7 或是用 VirtualBoxUbuntu Desktop Edition )

3.2 建立部落格應用程式

本指南的最佳學習方式就是緊跟著接下來的每個步驟。沒有任何步驟或程式會被省略,所以你可以一步步跟著。如果你需要下載完整的程式,可以從這裡下載 Getting Started Code

要開始了,首先打開指令列視窗(terminal),然後找個目錄適合放你的程式,接著輸入:

$ rails new blog

這會建立一個叫做 Blog 的 Rails 應用程式在 blog 目錄下。

你可以透過 rails -h 的指令看到所有可用的指令

完成之後,進到這個目錄下繼續:

$ cd blog

總之,Rails 會建立一個工作目錄叫做 blog。請打開這個目錄看看它的內容。本指南的大部分工作都會發生在 app 目錄下,這裡來簡單走訪一下各個目錄的功能吧:

檔案/目錄 目錄
Gemfile 設定你的 Rails 應用程式會使用哪些 Gems
README.rdoc 你的應用程式使用手冊。你可以用來告訴其他人你的應用程式是做什麼用的,如何使用等等。
Rakefile 用來載入可以被命令列執行的一些任務
app/ 包含了 Controllers、Models 和 Views,接下來的指南內容主要都在這個目錄。
config/ 應用程式設定檔、路由規則、資料庫設定等等
config.ru 用來啟動應用程式的 Rack 設定檔
db/ 目前資料庫的 Schema(綱要) 和資料庫 Migrations,我們很快就會學到什麼是 Migrations
doc/ 用來放你的文件
lib/ 擴充用的 Modules 檔案 (不在本指南範圍)
log/ 應用程式的 log 檔案
public/ 唯一可以在網路上看到的目錄,這是你的圖檔、javascript、stylesheets (CSS) 和其他靜態檔案擺放的地方
script/ 包括了讓你開始 Rails 專案的 script 以及其他 script
test/ 單元測試、fixtures 及其他測試程式,我們在 Testing Rails Applications 一文中會介紹
tmp/ 暫時性的檔案
vendor/ 用來放第三方程式碼的地方。例如 Ruby Gems、Rails 原始碼 (如果你要裝在你的專案裡面) 和可以增加功能的 Plugin(外掛)

3.3 安裝必要的 Gems

Rails 使用 Bundler gem 來管理所有你應用程式會依存的 gems 到 vendor 目錄。到目前為止,我們根據預設不需要特殊的 gem,我們只需要執行以下指令就可以準備好了:

$ bundle install

3.4 設定資料庫

幾乎每一個 Rails 應用程式都會與資料庫互動。而資料庫需要一個設定檔是 config/database.yml。如果你打開這個檔案,你會發現預設設定是 SQLite3。這個檔案包含三個不同的部分,對應到三個 Rails 預設環境:

  • development environment 開發模式,用在你的開發的時候
  • test environment 測試模式,用在自動測試時
  • production environment 正式上線模式,用在實際的上線運作環境
3.4.1 設定 SQLite3 資料庫

Rails 預設內建支援 SQLite3 這是一套非常輕量的非伺服器型資料庫程式。雖然繁重的上線環境可能超過 SQLite 的負擔,但是它卻非常適合開發和測試時使用。Rails 預設使用 SQLite 資料庫來建立新的專案,當然你也可以換別套。

這裡是一段有連線資料的開發用預設設定檔(config/database.yml):

development: adapter: sqlite3 database: db/development.sqlite3 pool: 5 timeout: 5000

本指南使用 SQLite3 資料庫,因為它完全不需要什麼設定就可以用了。Rails 當然也支援 MySQL 跟 PostgreSQL,也有其他資料庫系統的 plugins。如果是正式的上線環境就會需要了。

3.4.2 設定 MySQL 資料庫

如果你選擇使用 MySQL 取代預設的 Sqlite3 資料庫,你的 config/database.yml 會有點不同,以下是一個開發用的設定檔:

development: adapter: mysql2 encoding: utf8 database: blog_development pool: 5 username: root password: socket: /tmp/mysql.sock

如果在你的開發用電腦 MySQL 有使用者 root 和空白密碼,那這個設定就可以直接用了。不然,請修改 username 和 password。

3.4.3 設定 PostgreSQL 資料庫

最後,如果你選擇使用 PostgreSQL,你的 config/database.yml 可以設定成:

development: adapter: postgresql encoding: unicode database: blog_development pool: 5 username: blog password:

變更 username 和 password 以符合你所需。

3.5 建立資料庫

現在你的資料庫設定妥當,是時候讓 Rails 建立空的資料庫了。輸入以下的 rake 指令:

$ rake db:create

這會在 db/ 目錄下建立 development 和 test 的 SQLite3 資料庫。

Rake 是個在 Rails 中廣泛運用的通用型 command 命令列工具,你可以輸入 rake -T 列出所有可用的指令。

4 哈囉,Rails!

每學習一個新的程式語言,一開始都會有個輸出 Hello, World! 的最簡單練習。為了辦到這件事情,你需要啟動 Rails 應用程式的伺服器。

4.1 啟動 Web 伺服器

其實你已經有了可以運作的 Rails 應用程式了。要在你的開發機器上啟動 Web 伺服器,請輸入:

$ rails server

這會啟動一個 Mongrel (譯註:或是 WEBrick) 伺服器(Rails 也可以用其他的伺服器)。要看到結果,請打開瀏覽器前往 http://localhost:3000 。你應該就會看到 Rails 的預設首頁。

Welcome Aboard screenshot

要關閉伺服器的話,請輸入 Ctrl+C。在 development mode 開發模式的話,Rails 通常是不需要重新啟動的,修改的檔案會自動載入。(譯註:如果是 production mode 的話,修改任何檔案都必須重新啟動伺服器才會有效果)

這個 “Welcome Aboard” 的畫面是 Rails 應用程式的 煙霧測試(smoke test): 它確認了你的軟體設定正確。你可以點擊 About your application’s environment 的超連結看到應用程式的環境資訊摘要。

4.2 說 "Hello",Rails

要讓 Rails 說 "Hello",你必須至少建立一個 Controller 跟 View。而我們用一個指令就可以辦到了。在命令列視窗輸入:

$ rails generate controller home index

如果你在 Windows 上,或你的 Ruby 不像常見的設定,你可能需要改成輸入 ruby \path\to\rails controller home index

Rails 會新增幾個檔案,包括 app/views/home/index.html.erb。這個樣板(template)會被 home controller 裡的 index action (即 index method 函式) 拿來顯示給瀏覽器。用編輯器打開這個檔案,加入以下程式碼:

<h1>Hello, Rails!</h1>

4.3 設定首頁

那現在我們有了 Controller 跟 View,我們需要告訴 Rails 什麼時候 “Hello Rails” 要出現。在這個例子裡,我們希望把剛剛首頁的 http://localhost:3000 的 “Welcome Aboard” 換掉,改成 “Hello Rails”

第一步是刪除預設的首頁檔案:

$ rm public/index.html

這是因為 Rails 會優先回傳任何 public 下有的靜態檔案,而不是 Controllers 裡面建立的動態內容。

接著,你必須要告訴 Rails 你真正的首頁在哪裡。用編輯器打開 config/routes.rb 這個檔案。這是你的應用程式的 路由檔案 (routing file),它是個特殊的 DSL (domain-specific language 專屬領域語言) 告訴 Rails 如何將進來的 HTTP 請求派送到 Controllers 跟 Actions。這個檔案包含許多註解起來的範例,其中一行開頭是 :root to 請把註解移掉如下:

Blog::Application.routes.draw do # You can have the root of your site routed with "root" # just remember to delete public/index.html. root :to => "home#index"

root :to => "home#index" 這一行告訴 Rails 將 root 網址對應到 home controller 的 index action。

接下來用瀏覽器打開 http://localhost:3000 ,你就會看到 Hello, Rails! 了。

關於更多路由的資訊,請參考 Rails Routing from the Outside In.

5 使用鷹架 (scaffolding) 快速上手

Rails 的 鷹架 (scaffolding) 功能可以用一行指令就快速為 Resource 建立一組 Model, Views 跟 Controller 程式碼。

6 建立 Resource

在這個 blog 的例子,你可以用鷹架建立 Post resource:這將完成部落格文章管理功能。要辦到這件事情,在命令列視窗輸入:

$ rails generate scaffold Post name:string title:string content:text

雖然鷹架(scaffolding)可以幫助你快速上手,但是可沒辦法產生出完美符合需求的程式碼。因此許多有經驗的 Rails 開發者根本不用鷹架(scaffolding)功能,而偏好從頭打造起 Models, Controllers 和 Views。

鷹架(scaffold)產生器(generator)會建立出 15 個檔案在不同目錄,以下是個簡單的說明:

檔案 目的
db/migrate/20100207214725_create_posts.rb.rb 用來建立 posts 資料庫資料表的 Migration (你的檔案開頭名稱會有不同的 timestamp)
app/models/post.rb Post model
test/fixtures/posts.yml 用來測試的假文章資料
app/controllers/posts_controller.rb Posts controller
app/views/posts/index.html.erb 用來顯示所有文章的 index 頁面
app/views/posts/edit.html.erb 用來編輯文章的頁面
app/views/posts/show.html.erb 用來顯示特定一篇文章的頁面
app/views/posts/new.html.erb 用來新增文章的頁面
app/views/posts/_form.html.erb 用來顯示編輯和新增文章的表單 partial
app/helpers/posts_helper.rb 可在文章 views 中使用的 Helper 函式
test/unit/post_test.rb posts model 的單元測試
test/functional/posts_controller_test.rb posts controller 的功能測試
test/unit/helpers/posts_helper_test.rb posts helper 的單元測試
config/routes.rb 設定 URL 路由規則的檔案
public/stylesheets/scaffold.css CSS 樣式檔案

6.1 執行 Migration

rails generate scaffold 產生出來的程式中,有一項是 資料庫遷移(database migration)。Migration 是種 Ruby 類別用來方便建立和修改資料庫資料表。Rails 使用 rake 指令來執行 migrations,而且它也支援可以逆推 migration 步驟。Migration 的檔名包含了 timestamp (時間戳章),用來確保它們可以依照建立時間依序執行。

如果你仔細看看 db/migrate/20100207214725_create_posts.rb 這個檔案(記住,你的檔名開頭會有點不一樣),你會看到:

class CreatePosts < ActiveRecord::Migration def self.up create_table :posts do |t| t.string :name t.string :title t.text :content t.timestamps end end def self.down drop_table :posts end end

以上的 Migration 有兩個函式, up 會在 migration 進資料庫時執行,而 down 則會在之後需要逆推的時候執行。在這個例子中 up 會建立 posts 資料表,包含兩個 string 欄位和一個 text 欄位。它也會建立兩個 timestamp 欄位(譯註: t.timestamps 該行等同於 t.datetime :created_at 和 t.datetime :updated_at)用來追蹤建立和最後修改時間。更多的 Rails migrations 資訊請參考 Rails Database Migrations

這時你可以用以下的 rake 指令執行 Migration:

$ rake db:migrate

Rails 就會執行這個 migration 命令,然後告訴你它建立了 Posts 資料表。

== CreatePosts: migrating ==================================================== -- create_table(:posts) -> 0.0019s == CreatePosts: migrated (0.0020s) ===========================================

因為預設是跑在 development 模式,這個指令會用 config/database.yml 設定裡的 development 那段所指定的資料庫。

6.2 增加超連結

為了能把文章列表加到我們已經建好的首頁,你可以放個超連結在首頁上。打開 app/views/home/index.html.erb 修改成:

<h1>Hello, Rails!</h1> <%= link_to "My Blog", posts_path %>

這個 link_to 函式是 Rails 內建的 view helpers (View 的輔助函式)。它會建立一個文字超連結,連到文章列表。

6.3 在瀏覽器中操作文章

好,你已經準備好可以進入文章列表了,請瀏覽 http://localhost:3000 然後點擊 “My Blog” 連結:

Posts Index screenshot

這就是 Rails 執行 index view 文章頁面的結果。目前資料庫裡面還沒有任何文章,如果你點選 New Post 超連結,就可以新增一篇文章。有了文章之後,你就可以編輯、詳細瀏覽或刪除。所有的邏輯和 HTML 都被內建的 rails generate scaffold 指令搞定了。

在 development 模式中(也就是目前的預設環境),Rails 每次瀏覽器來 HTTP 請求都會重新載入程式,所以不需要重新啟動伺服器。

恭喜啦,你正在駕馭 Rails! 現在讓我們看看到底它是如何運作的。

6.4 Model

app/models/post.rb 就是 Model 檔案,它非常簡單:

class Post < ActiveRecord::Base end

程式碼不多,但是注意 Post 類別繼承了 ActiveRecord::Base。Active Record 讓你的 Model 有非常多功能,包括基本的資料庫 CRUD 操作(Create, Read, Update, Destroy,新增、瀏覽、更新、刪除)、資料驗證(data validation)、厲害的搜尋以及可以和其他 Models 關聯在一起。

6.5 新增一些 Validation (驗證)

Rails 提供一些函式幫助你驗證資料的正確性,編輯 app/models/post.rb 這個檔案:

class Post < ActiveRecord::Base validates :name, :presence => true validates :title, :presence => true, :length => { :minimum => 5 } end

這幾行程式會確保所有儲存的文章一定會有 name 和 title 的資料,而且 title 至少有五個字元長度。Rails 提供各種驗證的方法,包括必填、唯一性、格式或是需要有關聯物件。

6.6 使用 Console 主控台

要看到 validations 的作用,你可以使用 console。console 是一種命令列工具可以讓你在 Rails 中的環境中執行 Ruby 程式:

$ rails console

在 console 載入之後,你就可以在裡面使用 Models:

>> p = Post.new(:content => "A new post") => #<Post id: nil, name: nil, title: nil, content: "A new post", created_at: nil, updated_at: nil> >> p.save => false >> p.errors => #<OrderedHash { :title=>["can't be blank", "is too short (minimum is 5 characters)"], :name=>["can't be blank"] }>

這段程式先建立了一個 Post 實例,試圖要儲存進資料庫,但是卻回傳 false (表示儲存失敗),然後觀察文章的 errors

當你完成之後,輸入 exit 按下 enter 來離開主控台(Console)。

不像在 development 模式,console 不會自動載入剛修改的程式。如果你在 console 開啟之後才修改程式,請輸入 reload! 重新載入。

6.7 列出所有文章

最容易開始上手的地方就是列出文章的程式碼了。請打開 app/controllers/posts_controller.rb 這個檔案,然後看看 index+ 這個 action:

def index @posts = Post.all respond_to do |format| format.html # index.html.erb format.xml { render :xml => @posts } end end

Post.all 會呼叫 Post model 回傳資料庫裡所有的文章,結果會是一個包含文章的 @posts 陣列。

關於更多 Active Reocrd 資料查詢的功能,請查閱 Active Record Query Interface.

這個 respond_to block (程式碼區塊)同時處理了 HTMLXML 請求。如果瀏覽器瀏覽 http://localhost:3000/posts.xml 你就會看到 XML 格式。HTML 格式則會去找 app/views/posts/ 下符合 action 名稱的檔案。Rails 會讓所有 action 裡的實例變數(instance variables)(譯註: 也就是有 @ 開頭的變數) 通通傳到 View 裡面可以使用。以下是 app/views/posts/index.html.erb:

<h1>Listing posts</h1> <table> <tr> <th>Name</th> <th>Title</th> <th>Content</th> <th></th> <th></th> <th></th> </tr> <% @posts.each do |post| %> <tr> <td><%= post.name %></td> <td><%= post.title %></td> <td><%= post.content %></td> <td><%= link_to 'Show', post %></td> <td><%= link_to 'Edit', edit_post_path(post) %></td> <td><%= link_to 'Destroy', post, :confirm => 'Are you sure?', :method => :delete %></td> </tr> <% end %> </table> <br /> <%= link_to 'New post', new_post_path %>

這個 view 迭代了 @posts 陣列並顯示內容跟超連結,有幾件值得注意的事情:

  • link_to 會建立超連結到特定的位置
  • edit_post_pathnew_post_path 都是 Rails RESTful 路由提供的 helpers。你也會在 controller 的不同 actions 中看到這些 helpers。

在之前的 Rails 版本,你必須使用 <%=h post.name %> 如此 HTML 才會被逸出(譯註:可以防止 XSS 網路攻擊)。在 Raisl 3.0 中預設就會逸出。如果不要逸出,請使用 <%= raw post.name %>

關於更多 rendering 的處理,請參閱 Layouts and Rendering in Rails.

6.8 客製化 Layout 版型

View 只是 Rails 處理 HTML 的一個環節,還有一項概念叫做 layouts,可以用來包裹 views。當 Rails 要顯示一個 view 給瀏覽器時,它會將 view 的 HTML 放到 layout 的 HTML 裡面去。在之前的 Rails 版本,rails generate scaffold 指令會自動為每個 controller 建立一個 layout,例如 app/views/layouts/posts.html.erb 就是給 posts controller 的。但是在 Rails 3.0 的 scaffold 改了,所有的 controllers 共用一個 layout 檔案叫做 app/views/layouts/application.html.erb 。打開這個檔案然後修改 它的 body 標籤:

<!DOCTYPE html> <html> <head> <title>Blog</title> <%= stylesheet_link_tag :all %> <%= javascript_include_tag :defaults %> <%= csrf_meta_tag %> </head> <body style="background: #EEEEEE;"> <%= yield %> </body> </html>

瀏覽器重新整理 /posts 頁面,你會看到灰色的背景。同樣的背景也會出現在所有的文章 views。

6.9 建立新文章

建立一篇新的文章需要兩個 actions。第一個是 new action,它用來實例化一個空的 Post 物件:

def new @post = Post.new respond_to do |format| format.html # new.html.erb format.xml { render :xml => @post } end end

這個 new.html.erb view 會顯示空的 Post 給使用者:

<h1>New post</h1> <%= render 'form' %> <%= link_to 'Back', posts_path %>

其中 <%= render 'form' %> 是你第一次遇到 partials 。partial 是一個包含 HTML 和 Ruby 程式的片段,可以在其他地方重複使用。在這個例子中,表單被用在新增文章,基本上跟編輯文章的表單相同,兩者都有相同的 name 跟 title 文字欄位跟 content 文字區塊欄位,以及送出按鈕。

如果看清楚 views/posts/_form.html.erb 這個檔案,內容如下:

<%= form_for(@post) do |f| %> <% if @post.errors.any? %> <div id="errorExplanation"> <h2><%= pluralize(@post.errors.count, "error") %> prohibited this post from being saved:</h2> <ul> <% @post.errors.full_messages.each do |msg| %> <li><%= msg %></li> <% end %> </ul> </div> <% end %> <div class="field"> <%= f.label :name %><br /> <%= f.text_field :name %> </div> <div class="field"> <%= f.label :title %><br /> <%= f.text_field :title %> </div> <div class="field"> <%= f.label :content %><br /> <%= f.text_area :content %> </div> <div class="actions"> <%= f.submit %> </div> <% end %>

這個 partial 接收了來自 view 的所有的實例變數(instance variables)。在這個例子中,controller 中設定了 @post 是新的 Post 物件,所以在 view 跟這個 partial 中也都有這個 @post 物件。

想知道更多 partials 的資訊,請參閱 Layouts and Rendering in Rails

這個 form_for block (程式碼區塊)被用來建立 HTML 表單。在 block 之中,你可以使用各種函式來建構表單。例如 f.text_field :name 建立出一個文字輸入框,並填入 @post 的 name 屬性資料。但這個表單只能基於這個 model 有的屬性(在這個例子是 nametitlecontent)。Rails 偏好使用 form_for 而不是讓你手寫表單 HTML,這是因為程式碼可以更加簡潔,而且可以明確地綁在一個 model 實例上。

form_for block 也非常聰明,不同的 New PostEdit Post 表單 action 屬性跟送出按鈕的文字也會跟著不同 (譯註: 根據 @post 的不同,前者是全新的,後者是已經建立過的)。

如果你需要建立任意欄位的 HTML 表單,而不綁在某一個 model 上,你可以使用 form_tag 函式。它也提供了建構表單的函式而不需要綁在 model 實例上。

當使用者點擊表單的 Create Post 按鈕時,瀏覽器就會送出資料到 controller 的 create 函式(Rails 會知道要呼叫 create 函式,這是因為表單是用 HTTP POST 請求的,這是個稍早提過的 RESTful 慣例):

def create @post = Post.new(params[:post]) respond_to do |format| if @post.save format.html { redirect_to(@post, :notice => 'Post was successfully created.') } format.xml { render :xml => @post, :status => :created, :location => @post } else format.html { render :action => "new" } format.xml { render :xml => @post.errors, :status => :unprocessable_entity } end end end

create action 會透過從表單傳進來的資料,也就是 Rails 提供的 params hash 雜湊,來實例化一個新的 Post 物件。成功儲存之後, create 會根據使用者的請求回傳適當的格式(在這個例子是 HTML)。這裡它是把使用者導向(redirect)到 show action 顯示文章內容,並設定 notice 提醒使用者 Post 已經成功被建立。

如果文章因為 validation 錯誤而儲存失敗,這裡會回傳給使用者帶有錯誤訊息的 new action,好讓使用者可以修正問題再試一次。(譯註:render :action => "new" 會回傳 new action 使用的樣板,而不是執行 new action 這個函式。如果改成使用 redirect_to new_post_path 則會讓瀏覽器重新發送請求到 new action,但是如此一來 @post 就被重新建立而失去使用者剛輸入的資料)

“Post was successfully created” 的訊息會被儲存在 Rails 的 flash hash 裡 (通常就稱作 Flash) 好讓訊息可以被帶到另一個 action,它可以提供使用者一些有用的資訊。在這個 create 的 action 中,使用者並沒有真的看到任何頁面,因為它馬上就被導向到新的文章頁面。而這個 Flash 就帶著訊息到下一個 action,好讓使用者在 show action 頁面看到 “Post was successfully created.” 這個訊息。

6.10 顯示個別文章

當你在 index 頁面點擊 show 的文章連結,就會前往如 http://localhost:3000/posts/1 的網址。 Rails 會針對這個 resource 去呼叫 show action,然後傳進 1id 參數。以下是 show action。

def show @post = Post.find(params[:id]) respond_to do |format| format.html # show.html.erb format.xml { render :xml => @post } end end

這個 show action 根據 id 值使用 Post.find 從資料庫中找出該篇文章。找到資料之後,Rails 用 show.html.erb 顯示出來:

<p class="notice"><%= notice %></p> <p> <b>Name:</b> <%= @post.name %> </p> <p> <b>Title:</b> <%= @post.title %> </p> <p> <b>Content:</b> <%= @post.content %> </p> <%= link_to 'Edit', edit_post_path(@post) %> | <%= link_to 'Back', posts_path %>

6.11 編輯文章

如同建立新文章,編輯文章也有兩個步驟。第一個是請求特定一篇文章的 edit_post_path(@post) 頁面。這會呼叫 controller 的 edit+ action:

def edit @post = Post.find(params[:id]) end

找到要編輯的文章之後,Rails 顯示 edit.html.erb 頁面:

<h1>Editing post</h1> <%= render 'form' %> <%= link_to 'Show', @post %> | <%= link_to 'Back', posts_path %> <% end %>

這裡也像 new action,edit action 使用 form partial,只是這一次表單會用 HTTP PUT 動作給 PostsController,而且送出按鈕的字樣變成 “Update Post”。

送出表單後,會呼叫 controller 的 update action:

def update @post = Post.find(params[:id]) respond_to do |format| if @post.update_attributes(params[:post]) format.html { redirect_to(@post, :notice => 'Post was successfully updated.') } format.xml { head :ok } else format.html { render :action => "edit" } format.xml { render :xml => @post.errors, :status => :unprocessable_entity } end end end

update action 裡,Rails 透過 :id 參數找到要編輯的資料。接著 update_attributes 會根據表單傳進來的參數修改到資料上。如果一切正常,使用者會被導向到文章的 show 頁面。如果驗證有任何問題,它會顯示 edit 頁面好讓使用者可以修正資料。

6.12 刪除文章

最後,點擊 destroy 超連結會呼叫 destroy action:

def destroy @post = Post.find(params[:id]) @post.destroy respond_to do |format| format.html { redirect_to(posts_url) } format.xml { head :ok } end end

Active Record model 的 destroy 函式會刪除對應的資料庫資料。完成之後,就沒辦法顯示囉,所以 Rails 將使用者導向這個 model 的 index 頁面。

7 新增第二個 Model

你已經完成用 scaffolding 功能建立一個 model 了,接下來讓我們再新增第二個 model。第二個 model 是部落格文章的留言。

7.1 產生 Model

Rails 的 Models 名稱都是單數名詞,而它們對應的資料庫資料表是複數名詞,這個慣例也適用在新的 model 名字:Comment。即使你完全不用 scaffolding,大部分的 Rails 開發者也都會用產生器(generators)來產生 models 及 controllers 檔案。要建立一個新的 model,請在命令列視窗中輸入:

$ rails generate model Comment commenter:string body:text post:references

這個指令會產生以下檔案:

  • app/models/comment.rb – Model 檔案
  • db/migrate/20100207235629_create_comments.rb – Migration 檔案
  • test/unit/comment_test.rb and test/fixtures/comments.yml – 測試檔案

首先,讓我們看一下 comment.rb

class Comment < ActiveRecord::Base belongs_to :post end

這看起來跟先前的 post.rb model 非常像。差別是多了一行 belongs_to :post ,這會設定 Active Record 的 association(關聯) 。你將會在下一節學到更多 associations 的知識。

除了 model,Rails 也會建立對應的資料庫資料表 migration:

class CreateComments < ActiveRecord::Migration def self.up create_table :comments do |t| t.string :commenter t.text :body t.references :post t.timestamps end end def self.down drop_table :comments end end

注意到 t.references 這一行會幫關聯的 models 建立 foreign key (外部鍵) 欄位(譯註:等同於 t.integer :post_id )。接著讓我們執行 Migration:

$ rake db:migrate

Rails 很聰明只會執行還沒有執行過的 Migrations,所以在這個例子中,我們只會看到:

== CreateComments: migrating ================================================= -- create_table(:comments) -> 0.0017s == CreateComments: migrated (0.0018s) ========================================

7.2 把 Models 關聯起來

Active Record associations 讓你可以輕易宣告兩個 Models 之間的關係。在這個文章跟留言的例子,你可以寫出以下的關係:

  • 每篇留言(comment)屬於一篇文章(post)
  • 一篇文章(post)有許多留言(comments)

事實上,這就非常接近 Rails 用來宣告關係的語法了。你已經見到 Comment model 裡面的程式碼,宣告了每篇留言屬於一篇文章:

class Comment < ActiveRecord::Base belongs_to :post end

你會需要編輯 post.rb 檔案加上另一頭的關聯宣告:

class Post < ActiveRecord::Base validates :name, :presence => true validates :title, :presence => true, :length => { :minimum => 5 } has_many :comments end

這兩行宣告語法產生了一些神奇的行為。例如,如果你有一篇文章的實例變數 @post,你就可以透過 @post.comments 拿到所有的留言陣列了。

關於更多 Active Record associations 的資訊,請參閱 Active Record Associations.

7.3 為留言新增 URL 路由

如同 home controller,我們也需要新增路由告訴 Rails 如何瀏覽 comments。再次打開 config/routes.rb ,你會看到一段之前由 scaffold 產生器為 posts 產生的 resources :posts 程式碼,請修改成:

resources :posts do resources :comments end

這會在 posts 裡建立一個 commentsnested resource (嵌套 resource) 。這也描述了文章和留言有著階層關係。

關於路由的更多資訊,請參閱 Rails Routing from the Outside In

7.4 產生 Controller

有了 Model,我們來把注意力放到如何建立對應的 controller。再一次使用產生器:

$ rails generate controller Comments

這會建立四個檔案和一個空目錄:

  • app/controllers/comments_controller.rb – Controller 檔案
  • app/helpers/comments_helper.rb – View helper 檔案
  • test/functional/comments_controller_test.rb – Controller 的功能測試
  • test/unit/helpers/comments_helper_test.rb – Helper 的單元測試
  • app/views/comments/ – Controller 的 Views 檔案所在目錄

就像任何部落格,我們的讀者可以在看完文章之後留言,然後回到文章頁面看到剛剛的留言。所以,我們的 CommentsController 會提供函式可以建立留言跟刪除垃圾留言。

首先,讓我們修改 Post 的 show 樣板 (/app/views/posts/show.html.erb) 好讓我們可以新增留言:

<p class="notice"><%= notice %></p> <p> <b>Name:</b> <%= @post.name %> </p> <p> <b>Title:</b> <%= @post.title %> </p> <p> <b>Content:</b> <%= @post.content %> </p> <h2>Add a comment:</h2> <%= form_for([@post, @post.comments.build]) do |f| %> <%= f.error_messages %> <div class="field"> <%= f.label :commenter %><br /> <%= f.text_field :commenter %> </div> <div class="field"> <%= f.label :body %><br /> <%= f.text_area :body %> </div> <div class="actions"> <%= f.submit %> </div> <% end %> <%= link_to 'Edit Post', edit_post_path(@post) %> | <%= link_to 'Back to Posts', posts_path %> |

我們在 Post show 頁面新增了一個表單可以建立新留言,這個表單送出後會呼叫 CommentsControllercreate action。讓我們繼續:

class CommentsController < ApplicationController def create @post = Post.find(params[:post_id]) @comment = @post.comments.create(params[:comment]) redirect_to post_path(@post) end end

看起來比之前的 posts controller 複雜一點。這是因為有了階層關係。每一篇留言必須追蹤它是屬於哪一篇文章,因此需要一開始就得用 find 找到所屬的 Post model。

此外,這裡也用到一些 association 所提供的函式。我們在 @post.comments 上使用 create 函式來新增並儲存。這會自動關聯起該留言屬於該特定文章。

一旦我們完成新增留言,我們使用 post_path(@post) helper 來把使用者重新導向到本來的文章頁面。這我們之前看過了,會呼叫 PostsControllershow action 顯示 show.html.erb 樣板。這個頁面也將用來顯示留言,讓我們在 app/views/posts/show.html.erb 新增以下程式碼:

<p class="notice"><%= notice %></p> <p> <b>Name:</b> <%= @post.name %> </p> <p> <b>Title:</b> <%= @post.title %> </p> <p> <b>Content:</b> <%= @post.content %> </p> <h2>Comments</h2> <% @post.comments.each do |comment| %> <p> <b>Commenter:</b> <%= comment.commenter %> </p> <p> <b>Comment:</b> <%= comment.body %> </p> <% end %> <h2>Add a comment:</h2> <%= form_for([@post, @post.comments.build]) do |f| %> <%= f.error_messages %> <div class="field"> <%= f.label :commenter %><br /> <%= f.text_field :commenter %> </div> <div class="field"> <%= f.label :body %><br /> <%= f.text_area :body %> </div> <div class="actions"> <%= f.submit %> </div> <% end %> <br /> <%= link_to 'Edit Post', edit_post_path(@post) %> | <%= link_to 'Back to Posts', posts_path %> |

現在我們可以在你的部落格上新增文章跟留言了。

8 重構

文章跟留言都可以運作了,但是如果我們看看 app/views/posts/show.html.erb 樣板,實在有點又臭又長。我們可以利用 partials 來加以改善。

8.1 顯示 Partial Collections (集合)

首先,我們來建立一個 partial 來顯示文章的所有留言。新增 app/views/comments/_comment.html.erb 檔案加入以下程式:

<p> <b>Commenter:</b> <%= comment.commenter %> </p> <p> <b>Comment:</b> <%= comment.body %> </p>

然後修改 app/views/posts/show.html.erb 如下:

<p class="notice"><%= notice %></p> <p> <b>Name:</b> <%= @post.name %> </p> <p> <b>Title:</b> <%= @post.title %> </p> <p> <b>Content:</b> <%= @post.content %> </p> <h2>Comments</h2> <%= render @post.comments %> <h2>Add a comment:</h2> <%= form_for([@post, @post.comments.build]) do |f| %> <%= f.error_messages %> <div class="field"> <%= f.label :commenter %><br /> <%= f.text_field :commenter %> </div> <div class="field"> <%= f.label :body %><br /> <%= f.text_area :body %> </div> <div class="actions"> <%= f.submit %> </div> <% end %> <br /> <%= link_to 'Edit Post', edit_post_path(@post) %> | <%= link_to 'Back to Posts', posts_path %> |

這將為 post.comments<notextile><tt> 中的每篇留言都套用 </tt></notextile>app/views/comments/_comment.html.erb<notextile><tt> 這個 partial。每次 render 函式迭代 </tt></notextile>post.comments ,它會把每一篇留言指定到一個與 partial 同名的區域變數(local variable),在這個例子中,就可以在 partial 裡面使用。(譯註:也就是在 _comment.html.erb+ 這個 partial 裡面的 comment 變數就是一篇篇的留言)

8.2 顯示 Partial 表單

讓我們也把新增留言的部分移到 partial 去吧。同樣地,我們新增 app/views/comments/_form.html.erb 內容是:

<%= form_for([@post, @post.comments.build]) do |f| %> <%= f.error_messages %> <div class="field"> <%= f.label :commenter %><br /> <%= f.text_field :commenter %> </div> <div class="field"> <%= f.label :body %><br /> <%= f.text_area :body %> </div> <div class="actions"> <%= f.submit %> </div> <% end %>

然後編輯 app/views/posts/show.html.erb 如下:

<p class="notice"><%= notice %></p> <p> <b>Name:</b> <%= @post.name %> </p> <p> <b>Title:</b> <%= @post.title %> </p> <p> <b>Content:</b> <%= @post.content %> </p> <h2>Comments</h2> <%= render @post.comments %> <h2>Add a comment:</h2> <%= render "comments/form" %> <br /> <%= link_to 'Edit Post', edit_post_path(@post) %> | <%= link_to 'Back to Posts', posts_path %> |

其中第二個 render 定義了要顯示 comments/form 這個樣板,Rails 會根據其中的斜線去找 app/views/comments 目錄下的 _form.html.erb 檔案。

因為 @posts 被定義成實例變數(instance variable),所以可以在所有的 partials 中讀取到。

9 刪除留言

另一個部落格的重要功能是可以刪除垃圾留言。要辦到這件事,我們需要在 view 中有個超連結,以及在 controller 中實作 DELETE 動作。

首先,讓我們在 app/views/comments/_comment.html.erb partial 加上刪除的超連結:

<p> <b>Commenter:</b> <%= comment.commenter %> </p> <p> <b>Comment:</b> <%= comment.body %> </p> <p> <%= link_to 'Destroy Comment', [comment.post, comment], :confirm => 'Are you sure?', :method => :delete %> </p>

點擊 “Destroy Comment” 連結會送出 DELETE /posts/:id/comments/:idCommentsController,我們接下來要找到要刪除的留言,讓我們在 controller 裡加入 destroy action:

class CommentsController < ApplicationController def create @post = Post.find(params[:post_id]) @comment = @post.comments.create(params[:comment]) redirect_to post_path(@post) end def destroy @post = Post.find(params[:post_id]) @comment = @post.comments.find(params[:id]) @comment.destroy redirect_to post_path(@post) end end

這個 destroy action 會先找到所屬的文章,然後透過這篇文章的 @post.comments 集合找到該留言,接著從資料庫中移除,最後把使用者導向 show action。

9.1 刪除關聯的物件

如果你要刪除一篇文章,那麼其關聯的留言也需要被一起刪除。不然的話這些留言只會白白佔據你的資料庫。Rails 支援在 association 關聯上使用 dependent 選項來解決這件事情。修改 Post model,即 app/models/post.rb 如下:

class Post < ActiveRecord::Base validates :name, :presence => true validates :title, :presence => true, :length => { :minimum => 5 } has_many :comments, :dependent => :destroy end

10 安全性

如果你打算發佈這個部落格,任何人都可以新增、修改、刪除文章或刪除留言。

Rails 內建了一個非常簡單的 HTTP 認證系統可以處理這種情形。首先,我們在 app/controllers/application_controller.rb 啟用 simple HTTP based authentication:

class ApplicationController < ActionController::Base protect_from_forgery private def authenticate authenticate_or_request_with_http_basic do |user_name, password| user_name == 'admin' && password == 'password' end end end

當然你可以修改成你想要的使用者名稱和密碼。我們把這個函式放進 ApplicationController 裡,如此所有 controller 都可以使用 (譯註:因為所有的 controller 都繼承自 ApplicationController)。

接著在 PostsController 裡,我們要對需要認證的 actions 加上權限檢查,這裡我們使用 Rails 的 before_filter 函式,它允許我們在執行特定的 actions 前先執行指定的函式,而我們在這個函式中檢查使用者是否有權限。

我們在 PostsController 的上方來加入 before filter。在這個例子中,我們希望使用者驗證除了 indexshow 之外的所有 action,請這麼寫:

class PostsController < ApplicationController before_filter :authenticate, :except => [:index, :show] # GET /posts # GET /posts.xml def index @posts = Post.all respond_to do |format| # snipped for brevity

我們也希望有權限的使用者才可以刪除留言,所以在 CommentsController 加上:

class CommentsController < ApplicationController before_filter :authenticate, :only => :destroy def create @post = Post.find(params[:post_id]) # snipped for brevity

這樣當你試著建立一篇新文章,你會需要先經過 basic HTTP Authentication 認證。

Basic HTTP Authentication Challenge

11 建立一個有多個 Model 的表單

另一個部落格常見的功能是可以為文章下標籤(tag)。要實作這個功能,你的應用程式必須在一個表單中操作不只一個 model。Rails 提供了 nested forms (內嵌的表單)。

要示範這項功能,我們將在你新增文章的地方,也可以順便下標籤。首先,建立一個新的標籤 Model:

$ rails generate model tag name:string post:references

同樣的,執行 migration 來建立資料表:

$ rake db:migrate

接著,編輯 post.rb 檔案來建立關聯。接著告訴 Rails (透過 accepts_nested_attributes marco 巨集) 你希望透過文章來設定標籤:

class Post < ActiveRecord::Base validates :name, :presence => true validates :title, :presence => true, :length => { :minimum => 5 } has_many :comments, :dependent => :destroy has_many :tags accepts_nested_attributes_for :tags, :allow_destroy => :true, :reject_if => proc { |attrs| attrs.all? { |k, v| v.blank? } } end

其中的 :allow_destroy 選項告訴 Rails 在稍後的 view 中會顯示 “remove” checkbox。而 :reject_if 選項會阻止儲存空的標籤。

修改 views/posts/_form.html.erb 來顯示標籤的 partial:

<% @post.tags.build %> <%= form_for(@post) do |post_form| %> <% if @post.errors.any? %> <div id="errorExplanation"> <h2><%= pluralize(@post.errors.count, "error") %> prohibited this post from being saved:</h2> <ul> <% @post.errors.full_messages.each do |msg| %> <li><%= msg %></li> <% end %> </ul> </div> <% end %> <div class="field"> <%= post_form.label :name %><br /> <%= post_form.text_field :name %> </div> <div class="field"> <%= post_form.label :title %><br /> <%= post_form.text_field :title %> </div> <div class="field"> <%= post_form.label :content %><br /> <%= post_form.text_area :content %> </div> <h2>Tags</h2> <%= render :partial => 'tags/form', :locals => {:form => post_form} %> <div class="actions"> <%= post_form.submit %> </div> <% end %>

注意到為了接下來程式碼的可讀性,我們修改了 form_for(@post) do |f|f 變成 post_form

這個範例也展示了 render helper 可以接受 locals 參數來傳遞區域變數。在這個例子中,partial 裡面的區域變數 form 指的就是 post_form 物件。

我們也在表單上方新增一行 @post.tags.build,這會確保有空的標籤物件可以被使用者編輯,不然的話標籤表單沒辦法顯示。

建立 app/views/tags 目錄,以及 _form.html.erb 檔案,其內容是標籤的表單:

<%= form.fields_for :tags do |tag_form| %> <div class="field"> <%= tag_form.label :name, 'Tag:' %> <%= tag_form.text_field :name %> </div> <% unless tag_form.object.nil? || tag_form.object.new_record? %> <div class="field"> <%= tag_form.label :_destroy, 'Remove:' %> <%= tag_form.check_box :_destroy %> </div> <% end %> <% end %>

最後,我們編輯 app/views/posts/show.html.erb 樣板來顯示標籤。

<p class="notice"><%= notice %></p> <p> <b>Name:</b> <%= @post.name %> </p> <p> <b>Title:</b> <%= @post.title %> </p> <p> <b>Content:</b> <%= @post.content %> </p> <p> <b>Tags:</b> <%= @post.tags.map { |t| t.name }.join(", ") %> </p> <h2>Comments</h2> <%= render @post.comments %> <h2>Add a comment:</h2> <%= render "comments/form" %> <%= link_to 'Edit Post', edit_post_path(@post) %> | <%= link_to 'Back to Posts', posts_path %> |

透過這些修改,你就可以在同一個 view 中同時編輯文章跟標籤了。

不過呢,那個 @post.tags.map { |t| t.name }.join(", ") 實在有點醜,我們可以把它變成 helper 函式。

12 View Helpers

View Helpers (輔助函式)放在 app/helpers 目錄下,提供一些可以被重複使用的 Views 函式。在這個例子,我們希望有個字串函式可以把一群物件中的 name 屬性用逗號串接在一起。因為這用在 Post show 樣板,所以我們把它放在 PostsHelper 裡。

打開 app/helpers/posts_helper.rb 加入以下程式:

module PostsHelper def join_tags(post) post.tags.map { |t| t.name }.join(", ") end end

編輯 app/views/posts/show.html.erb view 如下:

<p class="notice"><%= notice %></p> <p> <b>Name:</b> <%= @post.name %> </p> <p> <b>Title:</b> <%= @post.title %> </p> <p> <b>Content:</b> <%= @post.content %> </p> <p> <b>Tags:</b> <%= join_tags(@post) %> </p> <h2>Comments</h2> <%= render @post.comments %> <h2>Add a comment:</h2> <%= render "comments/form" %> <%= link_to 'Edit Post', edit_post_path(@post) %> | <%= link_to 'Back to Posts', posts_path %> |

13 接下來?

到目前為止,你已經建立了你的第一個 Rails 應用,請隨意修改實驗你的程式。不過請不要埋頭苦幹,當你需要協助的時候,請問問看以下資源:

你也可以透過 Rails 內建的工具來產生文件:

  • 執行 rake doc:guides 會產生一份完整的 Rails 指南在你的應用程式 doc/guides 目錄下。用瀏覽器打開 doc/guides/index.html 就可以了。
  • 執行 rake doc:rails 會產生一份 API documentation 文件在 doc/api 目錄下。請打開 doc/api/index.html

14 一些設定上的訣竅

最簡單的方式就是把所有外部資料都當做 UTF-8。如果不是的話,函式庫跟 Rails 會需要轉換你的資料變成 UTF-8,這可能會發生問題。所以最好的方式還是讓所有的外部資料都是 UTF-8。

常見的癥兆是在你的瀏覽器中出現了帶有問號的小黑鑽石,或是 “ü” 變成 "ü"。Rails 內部可以自動偵測然後修正。但是,如果你有外部資料不是 UTF-8,它還是可能無法自動幫你偵測和修正。

兩種常見的非 UTF-8 原因:

  • 你的文字編輯器: 大部分的文字編輯器(例如Textmate)預設會存成 UTF-8。如果你的不是,這會導致你在樣板中輸入的文字(例如é),在瀏覽器中會變成帶有問號的小黑鑽石。同樣地,在你的 I18N 翻譯檔案也可能發生。大部分預設不是 UTF-8 的編輯器(例如某些版本的 Dreamweaver) 可以修改預設值,請改成 UTF-8。
  • 你的資料庫。Rails 預設會從資料庫出來的資料轉成 UTF-8。但是,如果你的資料庫內部不是 UTF-8,那麼可能沒辦法存進所有使用者輸入的字元。例如,你的使用者輸入俄文、希伯來文或是日文字元,而你的資料庫內部使用 Latin-1,那輸入的資料就會在進資料庫時不見。所以可能的話,讓資料庫也使用 UTF-8。

15 文件修改記錄

Lighthouse ticket

  • July 15, 2010: 翻譯完成 by ihower
  • July 12, 2010: Fixes, editing and updating of code samples by Jaime Iniesta
  • May 16, 2010: Added a section on configuration gotchas to address common encoding problems that people might have by Yehuda Katz
  • April 30, 2010: Fixes, editing and updating of code samples by Rohit Arondekar
  • April 25, 2010: Couple of more minor fixups Mikel Lindsaar
  • April 1, 2010: Fixed document to validate XHTML 1.0 Strict. Jaime Iniesta
  • February 8, 2010: Full re-write for Rails 3.0-beta, added helpers and before_filters, refactored code by Mikel Lindsaar
  • January 24, 2010: Re-write for Rails 3.0 by Mikel Lindsaar
  • July 18, 2009: Minor cleanup in anticipation of Rails 2.3.3 by Mike Gunderloy
  • February 1, 2009: Updated for Rails 2.3 by Mike Gunderloy
  • November 3, 2008: Formatting patch from Dave Rothlisberger
  • November 1, 2008: First approved version by Mike Gunderloy
  • October 16, 2008: Revised based on feedback from Pratik Naik by Mike Gunderloy (not yet approved for publication)
  • October 13, 2008: First complete draft by Mike Gunderloy (not yet approved for publication)
  • October 12, 2008: More detail, rearrangement, editing by Mike Gunderloy (not yet approved for publication)
  • September 8, 2008: initial version by James Miller (not yet approved for publication)

16 關於譯者

張文鈿 (a.k.a. ihower) ,翻譯的原始碼位於 http://github.com/ihower/docrails

17 翻譯詞彙

本文翻譯自 http://guides.rails.info/getting_started.html 。以下是英文與繁體中文的對照詞彙:

原文 中文
class 類別
object 物件
instance 實例
instantiate 實例化
instance variable 實例變數
local variable 區域變數
inherit 繼承
interface 介面
library 函式庫
server 伺服器
database 資料庫
(database) table 資料表
code 程式碼
command-line 命令列
terminal 命令列視窗
method 函式
application 應用程式, 應用
framework 框架
template 樣板
layout 版型
template rendering 樣板演算顯示
request HTTP 請求
timestamp 時間戳章
form 表單
array 陣列
iterate 迭代
escaped 逸出
tag 標籤
attribute 屬性
routing 路由
collection 集合
macro 巨集

以下包留原名詞不譯,必要時加上翻譯註解:

原文 說明
model 模型
controller 控制器
view 視圖
resource 資源
partial 指片段的 view
schema 資料庫綱要
migration 指資料庫遷移
RESTful REST 的形容詞
action 指 controller 的 action 時不譯
view helper View 輔助函式
development, test, production mode 指 Rails 運作的環境
HTTP verbs HTTP 協定中的動詞
template rendering 樣板演算顯示/呈現
scaffolding, scaffold 鷹架
timestamp 時間戳章
validation 驗證
callback 回呼
console 主控台
hash 雜湊
generator 產生器
association 關聯
foreign key 外部鍵
nested 嵌套的
checkbox 核對盒
Plugin 外掛
block 程式碼區塊