更多 RubyEye.Net: 概述 | 下载 | 新闻 | 论坛| 查看翻译说明

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 项目,是个非常简单的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 或是用 VirtualBoxUbuntu 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 的预设首页。

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:这将完成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” 连接:

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 是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 里建立一个 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 文件所在目录

就像任何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 页面新增了一个表单可以建立新留言,这个表单送出后会呼叫 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 %> |

现在我们可以在你的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/: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 安全性

如果你打算发佈这个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。在这个例子中,我们希望使用者验证除了 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 的表单

另一个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 应用,请随意修改实验你的程序。不过请不要埋头苦干,当你需要协助的时候,请问问看以下资源:

你也可以透过 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

  • 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 代码区块