这份文件基于 Rails 3.0。某些代码无法运行于旧版 Rails。
1 前提条件
这份指南的目标是为了帮助初学者从头开始学习 Rails 应用程序,而不需要有任何 Rails 经验。不过要能够读的懂,还是需要一些前提:
- Ruby 程序语言 版本 1.8.7 或 1.9.2 之后
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 开始。
- RubyGems Ruby 的套件管理系统
- SQLite3 数据库
Rails 是一套使用 Ruby 的 Web 框架。如果您对 Ruby 一无所知就一头栽进 Rails,您的学习曲线会非常陡峭。以下是一些网路上的免费 Ruby 学习资源:
- Mr. Neighborly’s Humble Little Ruby Book
- Programming Ruby
- Why’s (Poignant) Guide to Ruby
- 译注: 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。它预设可以产生 HTML 或 XML 输出。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 的论文更容易亲近:
- A Brief Introduction to REST by Stefan Tilkov
- An Introduction to REST (video tutorial) by Joe Gregorio
- Representational State Transfer article in Wikipedia
- How to GET a Cup of Coffee by Jim Webber, Savas Parastatidis & Ian Robinson
- 译注: 什么是REST跟RESTful? (了解 REST 理论并不是在 Rails 中使用 RESTful 技术的前提,所以大可以跳过不甚理解没关係。)
3 建立新的 Rails 项目
接下来的范例,你将建立一个叫做 blog 的 Rails 项目,是个非常简单的blog系统。在你开始建构这个应用之前,需要确认你的 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 或是用 VirtualBox 跑 Ubuntu Desktop Edition )
3.2 建立blog应用程序
本指南的最佳学习方式就是紧跟着接下来的每个步骤。没有任何步骤或程序会被省略,所以你可以一步步跟着。如果你需要下载完整的程序,可以从这里下载 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 Hello,Rails!
每学习一个新的程序语言,一开始都会有个输出 Hello, World! 的最简单练习。为了办到这件事情,你需要启动 Rails 应用程序的服务器。
4.1 启动 Web 服务器
其实你已经有了可以运作的 Rails 应用程序了。要在你的开发机器上启动 Web 服务器,请输入:
$ rails server
这会启动一个 Mongrel (译注:或是 WEBrick) 服务器(Rails 也可以用其他的服务器)。要看到结果,请打开浏览器前往 http://localhost:3000 。你应该就会看到 Rails 的预设首页。

要关闭服务器的话,请输入 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:这将完成blog文章管理功能。要办到这件事情,在命令行视窗输入:
$ 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” 连接:

这就是 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 (代码区块)同时处理了 HTML 和 XML 请求。如果浏览器浏览 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_path 和 new_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 有的属性(在这个例子是 name、title跟content)。Rails 偏好使用 form_for 而不是让你手写表单 HTML,这是因为代码可以更加简洁,而且可以明确地绑在一个 model 实例上。
form_for block 也非常聪明,不同的 New Post 跟 Edit 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,然后传进 1 到 id 参数。以下是 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 是blog文章的留言。
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 里建立一个 comments 的 nested 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 文件所在目录
就像任何blog,我们的读者可以在看完文章之后留言,然后回到文章页面看到刚刚的留言。所以,我们的 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 页面新增了一个表单可以建立新留言,这个表单送出后会呼叫 CommentsController 的 create 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 来把使用者重新导向到本来的文章页面。这我们之前看过了,会呼叫 PostsController 的 show 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 %> |
现在我们可以在你的blog上新增文章跟留言了。
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 删除留言
另一个blog的重要功能是可以删除垃圾留言。要办到这件事,我们需要在 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/:id 到 CommentsController,我们接下来要找到要删除的留言,让我们在 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 安全性
如果你打算发佈这个blog,任何人都可以新增、修改、删除文章或删除留言。
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。在这个例子中,我们希望使用者验证除了 index 跟 show 之外的所有 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 认证。

11 建立一个有多个 Model 的表单
另一个blog常见的功能是可以为文章下标签(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 应用,请随意修改实验你的程序。不过请不要埋头苦干,当你需要协助的时候,请问问看以下资源:
- Ruby On Rails guides
- The Ruby on Rails Tutorial
- Ruby on Rails mailing list
- #rubyonrails channel on irc.freenode.net
- Rails Wiki
- 译注: Ruby Wednesday 定期聚会
- 译注: ruby-tw #ruby-tw channel on irc.freenode.net
- 译注: ppt.cc 的 Ruby 版
- 译注: RailsFun!
你也可以透过 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 文件修改记录
- Oct 17,2010:翻译完成by david
- 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 关于译者
david (RubyEye.Net) ,翻译的原始码位于 http://guides.ruby.tw/rails3/
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 | 代码区块 |
