在过去的两年中,Ruby on Rails应用程序框架已经具备了一个由托管和服务提供商组成的一体式行业、一套功能广泛且令人印象深刻的开发工具,还有各种在Ruby 用语里称为gems和plug-ins的补充库 — 可增强软件的功能。
自 2007年以来,Rails 社区也已不断壮大。全球有众多的Rails开发人员充满活力、团结互助,并且渴望不断地改进该软件。可以毫不夸张地说,Rails 的改进应归功于社区,因为是程序员之间不断的相互超越使得构建出的软件越来越完善。如此不断地循环,各个功能才得以从初期阶段快速发展,逐渐变的实用、功能不断强大并完善,最终成为不可或缺的工具。
在很多情况下,社区认为最基本的 gems 和 plug-ins 都会保留到 Rails 核心中。Rails 的 named scopes(一个查询快捷方式),可实现与 nested forms 相同的功能。这是一个新增的功能,可取代以前的尝试,并在相同的 HTML 表单中创建和编辑多个模型。实际上,对于 Rails 开发人员来说最困难的任务或许就是跟上变化的节奏。
Rails下一个主要的发布是Rails版本3,该版本继续保持工具包的快速改进。与以往相同,该软件仍然非常 “固执”,即仍然偏向于约定优于配置。Rails 的核心组件始终存在,即 RESTful 路径、关系、验证、模板和数据库抽象化。不过,这些组件的许多内部内容已经被重写或者进行了改进。最明显的并且很大程度上借用了 Merb 的理念的就是很多 Rails 的基本功能不再密切结合。
例如,以前只对 Rails 应用程序可用的数据验证便捷功能现在成为独立的组件,并且可以包含在 Vanilla Ruby 代码中。如呈现部件和模板等控制器功能,现在也是相互独立的,并且可以嵌入到任一库中。
大改动、小变化
Rails 3中变动的数量太多,无法在此全部列出。此处,仅介绍一些很可能会影响到开发人员的一些变动:
Ruby On Rails 3发布说明:http://edgeguides.rubyonrails.org/3_0_release_notes.html
◆一条命令可以控制所有事件。有了 Rails 3,无需在每一个应用程序中使用整套脚本(script/server、script/generate 以及其他),使用一条命令即可取代其功能,该命令恰如其分地被命名为 rails。例如,在以前需要键入 ./script/console 的地方,您现在只需键入 rails console。rails 命令还可以像以前一样生成新的应用程序。其运行方式依据其是否在现有的 Rails 应用程序中启动而有所不同。
◆可为依赖性提供具体的解决方案。协调和解决 gem 依赖性是个棘手的问题。与可用 gems 的集合一样,gem 的修订也是随系统的不同而有所变化。因为具有这样的多样化,所以很难广泛地部署或共享一个 Rails 应用程序。Rails 3 引入了 Bundler,这是一个专门用于管理依赖性的实用程序(因此无需再使用 config.gem)。您可以在应用程序根目录内一个名为 Gemfile 的目录中声明依赖性。Bundler 将下载和存储所有指定的 gem。您甚至可以在应用程序中 “打包” gem ,以便阻止从外部存储库下载。
◆不带查询语句的查询功能。一直以来,Rails 已经可以充分运用特定于领域的语言 (DSL) — 考虑一下 has_one 或 validates_numericality_of — 有一个明显的例外:数据库查询。可以确定地说,Rails 的动态搜寻器便捷、易用,但混合使用选项哈希值如 :conditions、:order 和 :limit 非常常见,因为都是 find_by_sql 语句。Rails 3 合并了 relational algebra,这是专门设计用于表示查询的 DSL。基本命令包括 project(用于选择列)、where(用于表示条件)、join(用于指定关系)、take 和 skip(分别用于限定和抵消),以及 group(用于聚集)等其他属性。
用于模糊样板代码的控制器。Rails控制器的核心操作—new、create、edit和update—通常不变,尤其是当控制器大部分用于CRUD操作时。事实上,控制器生成器的输出 ./script/generate controller一般不需要进一步的修改就可以满足需要。考虑到这些相似性,Rails 3引入了Responder来进一步简化代码。例如下面是create操作全部所需的几行代码:
- class PostsController
- respond_to :html, :xml
- def create
- @post = Post.create(params[:post])
- respond_with(@post)
- end
- end
在该代码片段中,如果@post保存成功,respond_with(@post) 将发送到show以显示新的记录,而假设对象的验证失败,则发送到new。这仅仅是一个小样本。您可以在下一章节找到这些新功能的示例以及更多内容,例如从头构建Rails 3应用程序。
#p#
***构建 Rails 3应用程序
要运行 Rails 3,您的系统必须安装有Ruby 1.8.7版或 Ruby 1.9.2 版,或者该编程语言的较新版本及其附加库和解释程序。您的机器上***同时安装有 Git 软件版本控制系统,因为 Rails 3 和许多其他重要的 Rails 项目都是在 Git 中进行维护的。您的系统还需要数据库引擎,例如 SQLite(版本 3)、MySQL 或者 PostgreSQL。开发 Rails 应用程序时,Web 服务器不是必须的,但它通常是生产部署的一部分。
要创建 Rails 3 应用程序,您必须拥有Rails 3预发布gem和所有其相关产品。这时,您只需通过运行几条命令(请参阅 清单 1)即可安装所需的组件。(在您继续进行之前请查看 Rails 3 文档,因为根据版本的不同具体的操作会有所不同。)
- 清单 1. Rails 3 预发布 gem 和相关产品
- $ gem install rails3b
- Due to a rubygems bug, you must uninstall all older versions of bundler for 0.9 to work
- Successfully installed mime-types-1.16
- Successfully installed mail-2.1.2
- Successfully installed text-hyphen-1.0.0
- Successfully installed text-format-1.0.0
- Successfully installed memcache-client-1.7.8
- Successfully installed rack-1.1.0
- Successfully installed rack-mount-0.4.7
- Successfully installed abstract-1.0.0
- Successfully installed erubis-2.6.5
- Successfully installed i18n-0.3.3
- Successfully installed tzinfo-0.3.16
- Successfully installed bundler-0.9.5
- Successfully installed thor-0.13.1
- Successfully installed rails3b-3.0.1
- 14 gems installed
- $ gem install arel --pre
- Successfully installed activesupport-3.0.0.beta
- Successfully installed arel-0.2.pre
- 2 gems installed
- $ gem install rails --pre
- Successfully installed activemodel-3.0.0.beta
- Successfully installed actionpack-3.0.0.beta
- Successfully installed activerecord-3.0.0.beta
- Successfully installed activeresource-3.0.0.beta
- Successfully installed actionmailer-3.0.0.beta
- Successfully installed railties-3.0.0.beta
- Successfully installed rails-3.0.0.beta
- 7 gems installed
下一步是生成应用程序 — 在 清单 2 中显示了一个小 wiki。该应用程序创建并管理文章。每一篇文章都有一个标题和一些散文,通过从现有页面的正文创建一个指向新文章的引用,您即可创建一篇新的文章。引用可以是任一驼峰式大小写单词,例如 TheSolarSystem 或者 TheOscars。
注意:可通过下面的 下载 表格获取该 wiki 应用程序的源代码。
- 清单 2. Wiki Rails 应用程序
- $ rails wiki
如果您运行了 ls -lR 来查看应用程序的内容,将会显示一些新文件:
◆Gemfile,即前面曾提到的 gem 清单。该文件必须至少包含两行:一行指向 Rails 3 beta gem 的源,另一行则绑定 Rails 3 beta gem 本身。您或许还需要第三行(至少)以连接数据库:
- source 'http://gemcutter.org'
- gem "rails", "3.0.0.beta"
- gem "sqlite3-ruby", :require => "sqlite3"
◆config/application.rb,它包含 config/environment.rb 中以前提供的很多选项。虽然后者仍然保留,但很大程度上已不再使用该文件。config/application.rb 的一个显著的附加功能是 generators block:
- config.generators do |g|
- g.orm :active_record
- g.template_engine :erb
- g.test_framework :test_unit, :fixture => true
- end
您的 Rails 3 应用程序可以使用一些兼容的对象关系映射器 (ORM)、模板引擎和测试框架。生成器块会指定应用程序的***项,并根据您的模型、视图等调用适当的生成器。
◆db/seeds.rb,该文件对于 Rails 3 来说并不是新增的,但却有必要着重介绍一下,因为它是最近不久刚增加的功能(在 Rails 2.3.4 版引入的)。如果您的应用程序需要初始数据以正常运行,例如一个管理用户、价格代码或静态页面,那么您可以在 db/seeds.rb 中创建这些数据并运行任务 rake db:seed。在 Seed 文件之前,不存在初始化的惯例,许多开发人员把代码放入迁移中,这样容易混淆创建数据库和填充数据库之间的不同之处。
◆config.ru,存在于每个 Rails 3 应用程序的根目录下,即所谓的 rackup 文件,也就是基于 Rack 的应用程序的配置文件。Rails 3 是一个 Rack 应用程序,并且与任一支持 Rack 的 Web 服务器相兼容。总的来说,除非您想要添加其他 Rack 组件,否则请不要更改 config.ru 文件。
还有一些其他新文件;不过大多数看上去与 Rails 版本 2.3 相似。config/routes.rb 文件的功能与以往相同,只不过更加简化、更具有 Ruby 的特色。您将很快会看到一个示例。
生成应用程序并编辑 Gemfile 以声明依赖性之后,下一步就是收集应用程序所需的 gem。这是由新的实用程序 bundle(请参阅 清单 3)来完成的工作。
- 清单 3. 收集所需的gem
- $ bundle
- installFetching source index from http://gemcutter.org
- Resolving dependencies
- Installing abstract (1.0.0) from system gems
- Installing actionmailer (3.0.0.beta) from system gems
- Installing actionpack (3.0.0.beta) from system gems
- Installing activemodel (3.0.0.beta) from system gems
- Installing activerecord (3.0.0.beta) from system gems
- Installing activeresource (3.0.0.beta) from system gems
- Installing activesupport (3.0.0.beta) from system gems
- Installing arel (0.2.1) from rubygems repository at http://gemcutter.org
- Installing builder (2.1.2) from system gems
- Installing bundler (0.9.7) from rubygems repository at http://gemcutter.org
- Installing erubis (2.6.5) from system gems
- Installing i18n (0.3.3) from system gems
- Installing mail (2.1.2) from system gems
- Installing memcache-client (1.7.8) from system gems
- Installing mime-types (1.16) from system gems
- Installing rack (1.1.0) from system gems
- Installing rack-mount (0.4.7) from system gems
- Installing rack-test (0.5.3) from system gems
- Installing rails (3.0.0.beta) from system gems
- Installing railties (3.0.0.beta) from system gems
- Installing rake (0.8.7) from system gems
- Installing sqlite3-ruby (1.2.5) from rubygems repository at
- http://gemcutter.org with native extensions
- Installing text-format (1.0.0) from system gems
- Installing text-hyphen (1.0.0) from system gems
- Installing thor (0.13.3) from rubygems repository at http://gemcutter.org
- Installing tzinfo (0.3.16) from system gems
- Your bundle is complete!
该bundle实用程序,简称 Bundler,可用于下载和安装所有在 Gemfile 中指定的 gem 以及任何这些 gems 的依赖项(请参阅 清单 4)。该 bundle 实用程序还可以将所有依赖项复制到您的应用程序中,使得您的代码库自给自足。具体来说,如果您运行 bundle pack,Bundler 会将所有 gem 的资料复制到 vendor/cache。
- 清单 4. 运行 bundle 实用程序
- $ bundle pack
- Copying .gem files into vendor/cache
- * bundler-0.9.7.gem
- * thor-0.13.3.gem
- * abstract-1.0.0.gem
- * mime-types-1.16.gem
- * text-hyphen-1.0.0.gem
- * rack-mount-0.4.7.gem
- * rake-0.8.7.gem
- * text-format-1.0.0.gem
- * tzinfo-0.3.16.gem
- * rack-test-0.5.3.gem
- * builder-2.1.2.gem
- * erubis-2.6.5.gem
- * memcache-client-1.7.8.gem
- * rack-1.1.0.gem
- * sqlite3-ruby-1.2.5.gem
- * i18n-0.3.3.gem
- * activesupport-3.0.0.beta.gem
- * arel-0.2.1.gem
- * mail-2.1.2.gem
- * activemodel-3.0.0.beta.gem
- * activerecord-3.0.0.beta.gem
- * actionpack-3.0.0.beta.gem
- * railties-3.0.0.beta.gem
- * actionmailer-3.0.0.beta.gem
- * activeresource-3.0.0.beta.gem
- * rails-3.0.0.beta.gem
- $ ls vendor/cache
- abstract-1.0.0.gem memcache-client-1.7.8.gem
- actionmailer-3.0.0.beta.gem mime-types-1.16.gem
- actionpack-3.0.0.beta.gem rack-1.1.0.gem
- activemodel-3.0.0.beta.gem rack-mount-0.4.7.gem
- activerecord-3.0.0.beta.gem rack-test-0.5.3.gem
- activeresource-3.0.0.beta.gem rails-3.0.0.beta.gem
- activesupport-3.0.0.beta.gem railties-3.0.0.beta.gem
- arel-0.2.1.gem rake-0.8.7.gem
- builder-2.1.2.gem sqlite3-ruby-1.2.5.gem
- bundler-0.9.7.gem text-format-1.0.0.gem
- erubis-2.6.5.gem text-hyphen-1.0.0.gem
- i18n-0.3.3.gem thor-0.13.3.gem
- mail-2.1.2.gem tzinfo-0.3.16.gem
将vendor/cache视为应用程序自己的gem存储库。您可以将代码库移动到任何地方,并可以获得您所需的gem软件和版本 — 无需远程存储器即可实现。例如,如果您在 bundle pack之后运行bundle install,gem会从您的应用程序存储库安装到您的系统中(请参阅 清单 5)。
- 清单 5. 安装 gem
- Fetching source index from http://gemcutter.org
- Resolving dependencies
- Installing abstract (1.0.0) from .gem files at
- /Users/strike/projects/rails3/wiki/vendor/cache
- Installing actionmailer (3.0.0.beta) from .gem files at
- /Users/strike/projects/rails3/wiki/vendor/cache
- Installing actionpack (3.0.0.beta) from .gem files at
- /Users/strike/projects/rails3/wiki/vendor/cache
- ...
- Installing thor (0.13.3) from .gem files at
- /Users/strike/projects/rails3/wiki/vendor/cache
- Installing tzinfo (0.3.16) from .gem files at
- /Users/strike/projects/rails3/wiki/vendor/cache
- Your bundle is complete!
#p#
使用wiki
要创建应用程序,则需要为页面生成一个工作框架(scaffold)、创建数据库、将初始页面放到数据库并且设定所需的路径(请参阅 清单 6)。为了简单化,仅限在某些字段使用 wiki 页面记录:标题、标头(标题的缩略语)、正文和时间截(以用于记录页面的创建时间和***修改时间)。标题和标头是字符串字段;散文是文本字段;时间截是日期和时间字段。(当然,一个真正的 wiki 还会有其他字段,如最近的作者以及页面的修订历史记录。为了尽量简洁,该例子还省略了用户和会话、格式以及各种身份验证和授权。)您可以使用 rails generate scaffold 命令生成一个初始模型、一系列视图以及一个控制器。
- 清单 6. 完整的 wiki 应用程序
- $ rails generate scaffold page title:string slug:string body:text --timestamps
- invoke active_record
- create db/migrate/20100221115613_create_pages.rb
- create app/models/page.rb
- invoke test_unit
- create test/unit/page_test.rb
- create test/fixtures/pages.yml
- route resources :pages
- invoke scaffold_controller
- create app/controllers/pages_controller.rb
- invoke erb
- create app/views/pages
- create app/views/pages/index.html.erb
- create app/views/pages/edit.html.erb
- create app/views/pages/show.html.erb
- create app/views/pages/new.html.erb
- create app/views/pages/_form.html.erb
- create app/views/layouts/pages.html.erb
- invoke test_unit
- create test/functional/pages_controller_test.rb
- invoke helper
- create app/helpers/pages_helper.rb
- invoke test_unit
- create test/unit/helpers/pages_helper_test.rb
- invoke stylesheets
- create public/stylesheets/scaffold.css
如果您想知道 ./script/generate 命令有何变化,回忆一下,该命令已经被全能的 rails 命令包含了。运行rake db:create db:migrate 以创建数据库:
- $ rake db:create db:migrate
- == CreatePages: migrating ====================================================
- -- create_table(:pages)
- -> 0.0010s
- == CreatePages: migrated (0.0011s) ===========================================
该Wiki现已存在,但却是空的。添加一个初始页面作为所有其他页面的基准。编辑文件 db/seeds.rb,并编写代码以创建一个新的页面,如 清单 7 中所示:
- 清单 7. wiki 基准页面
- Page.create(
- :title => 'The Marx Brothers Wiki',
- :slug => 'Home',
- :body => 'An encyclopedic guide to the Marx Brothers.')
运行 rake db:seed 以执行代码。您可以通过使用 rails console 快速浏览以验证页面,如 清单 8 中所示。
- 清单 8. 验证基准页面
- $ rake db:seed
- (in /Users/strike/projects/rails3/wiki)
- $ rails console
- Loading development environment (Rails 3.0.0.beta)
- irb(main):001:0> Page.all
- => [#<Page id: 1, title: "The Marx Brothers Wiki", slug: "Home",
- body: "An encyclopedic guide to the Marx Brothers.",
- created_at: "2010-02-21 12:24:43", updated_at: "2010-02-21 12:24:43">]
在继续运行编码之前,请先设定路径。需要两条路径:一条默认的路径用来查找主页面,而另外一条路径则通过标头来查找页面。清单 9 显示了最终版的 config/routes.rb 文件。
- 清单 9. config/routes.rb(最终版)
- Wiki::Application.routes.draw do |map|
- resources :pages
- root :to => "pages#show"
- end
在清单 6中,rails generate scaffold page 这一行命令可自动在第二行创建路径,这是 REST 式的。您必须在第三行手动添加路径。用于指定站点路径的默认 “根目录” 的语法是 Rails 3 中的新增功能。第三行定义的是,“将路径 ‘/’ 映射到页面控制器的 ‘show’ 方法”。show 方法的代码将在数据库中查找主页面并显示出来。添加新的根目录路径后,需要删除 public/index.html 文件以避免产生冲突:
- $ rm public/index.html
现在,让我们来关注页面控制器。Rails 3 中的控制器代码可以极其简单。清单 10 通过单一的 show 方法,显示了控制器的初始实现。
- 清单 10. Rails 3 控制器
- class PagesController < ApplicationController
- respond_to :html
- def show
- @page = Page.where( :slug => ( params[:id] || 'Home' ) ).first
- respond_with( @page )
- end
- end
正如您所看到的,通常在 Rails 2 控制器中提供的所有模板都不见了。respond_to 列出了控制器所支持的格式;此处,它仅会对 HTML 的请求做出反应。respond_with 是逻辑快捷方式,用于决定控制器应如何继续处理。
查询的语法也是大有不同。查询是 Rails 3 关系代数的一个示例。您可能会想知道为什么需要有 first 后缀。where 和其他表达查询的操作数并不会真正引起查询语句被执行。相反地,查询站点一直闲置,直到真正需要数据时才启动。这就是延迟加载,即尽可能长的延迟查询语句的执行。first 命令将触发数据库中的实际查询。
如果您现在运行应用程序,您会看到与 图 1 相似的情况,现在,您可以向控制器中添加更多的代码。清单 11 显示了完整的控制器。
- 清单 11. 完整的 Rails 3 控制器
- class PagesController < ApplicationController
- respond_to :html
- before_filter :get_page, :except => [ :create ]
- def create
- respond_with( @page = Page.create( params[ :page ] ) )
- end
- def edit
- end
- def index
- render :action => :show
- end
- def show
- @page ||= Page.new( :slug => params[ :id ] )
- if @page.new_record?
- render :action => :new
- else
- respond_with( @page )
- end
- end
- def update
- @page.update_attributes( params[ :page ] )
- respond_with( @page )
- end
- private
- def get_page
- @page = Page.where( :slug => ( params[:id] || 'Home' ) ).first ||
- Page.where( :id => params[:id] ).first
- end
- end
在该控制器中,index 方法仅仅反映没有页面标示符的 show 操作,从而呈现主页面。show 会显示一个页面,并提供一个 ID 或标头(所有操作的查询都集中在 get_page 中,从而进一步减少了代码的数量);如果某个页面不存在,则会准备一个新的页面以供进行编辑。Page模型仅仅可以验证所有显示的字段:
- class Page > ActiveRecord::Base
- validates_presence_of :body, :slug, :title
- end
将驼峰式大小写引用转换为指向其他页面的链接,这一工作是在 Page 模型的视图中进行的。由 app/helpers/pages_helper.rb 中的 helper 函数来完成这一工作,从而保持视图的最小化(请参阅 清单 12)。
- 清单 12. 驼峰式大小写转换 helper 函数
- module PagesHelper
- def wikify( page )
- return '' if page.body.blank?
- page.body.gsub( /^([A-Z][[:alnum:]]*([A-Z][[:alnum:]]*)+)/ ) do |match|
- link_to( $1, :action => :show, :id => $1 )
- end
- end
- end
该视图是典型的视图,如清单 13中所示。
- 清单 13. 典型视图
- <p>
- <b>Title:b>
- <%= @page.title %>
- p>
- <p>
- <b>Body:b>
- <%= raw wikify( @page ) %>
- p>
- <%= link_to 'Edit', edit_page_path(@page) %> |
- <%= link_to 'Back', pages_path %>
raw操作数是Rails 3中新增的功能。与以前版本的Rails不同,默认情况下所有的字符串都可以(去掉了HTML)安全发送。如果要通过HTML发送一个字符串,则必须使用 raw。
切换Rails
除了此处所介绍的功能改进和便捷性,Rails 3还提供了比以前版本更佳的性能,尤其是在呈现部件方面。您还可以创建您专有的验证器类,并充分利用更为流畅的标准验证。例如,由 Jeremy McAnally 编写以下验证,一次需要四行单独的代码:
- validates :login, :presence => true, :length => {:minimum => 4},
- :uniqueness => true, :format => { :with => /[A-Za-z0-9]+/ }
【编辑推荐】