1 基础设施
Rails 2.2 是一个重要的版本,它为 Rails 的持续运行和与外部世界的连接提供了基础设施。
1.1 国际化
Rails 2.2 提供了一个方便的国际化系统(或 i18n,对于那些厌倦打字的人来说)。
- 主要贡献者:Rails i18 团队
- 更多信息
1.2 与 Ruby 1.9 和 JRuby 的兼容性
除了线程安全性之外,还进行了大量工作来使 Rails 与 JRuby 和即将推出的 Ruby 1.9 良好配合。由于 Ruby 1.9 是一个不断变化的目标,在边缘 Ruby 上运行边缘 Rails 仍然是一个不确定的命题,但 Rails 准备在 Ruby 1.9 发布后进行过渡。
2 文档
Rails 的内部文档(以代码注释的形式)在许多地方都得到了改进。此外,Ruby on Rails 指南 项目是有关主要 Rails 组件信息的权威来源。在其第一个正式版本中,指南页面包含
- Rails 入门
- Rails 数据库迁移
- Active Record 关联
- Active Record 查询接口
- Rails 中的布局和渲染
- Action View 表单助手
- Rails 路由从外到内
- Action Controller 概述
- Rails 缓存
- 测试 Rails 应用程序指南
- 保护 Rails 应用程序
- 调试 Rails 应用程序
- 创建 Rails 插件的基础知识
总而言之,指南为初级和中级 Rails 开发人员提供了数万字的指导。
如果您想在本地(在您的应用程序中)生成这些指南
$ rake doc:guides
这将把指南放在 Rails.root/doc/guides
中,您可以通过在您喜欢的浏览器中打开 Rails.root/doc/guides/index.html
来开始浏览。
- 主要贡献来自 Xavier Noria 和 Hongli Lai。
- 更多信息
3 与 HTTP 的更好集成:开箱即用的 ETag 支持
支持 HTTP 标头中的 ETag 和上次修改时间戳意味着 Rails 现在可以在获取最近未修改的资源的请求时发回空响应。这允许您检查是否需要发送响应。
class ArticlesController < ApplicationController
def show_with_respond_to_block
@article = Article.find(params[:id])
# If the request sends headers that differs from the options provided to stale?, then
# the request is indeed stale and the respond_to block is triggered (and the options
# to the stale? call is set on the response).
#
# If the request headers match, then the request is fresh and the respond_to block is
# not triggered. Instead, the default render will occur, which will check the last-modified
# and etag headers and conclude that it only needs to send a "304 Not Modified" instead
# of rendering the template.
if stale?(:last_modified => @article.published_at.utc, :etag => @article)
respond_to do |wants|
# normal response processing
end
end
end
def show_with_implied_render
@article = Article.find(params[:id])
# Sets the response headers and checks them against the request, if the request is stale
# (i.e. no match of either etag or last-modified), then the default render of the template happens.
# If the request is fresh, then the default render will return a "304 Not Modified"
# instead of rendering the template.
fresh_when(:last_modified => @article.published_at.utc, :etag => @article)
end
end
4 线程安全性
为使 Rails 线程安全而进行的工作正在 Rails 2.2 中推出。根据您的 Web 服务器基础设施,这意味着您可以使用更少的内存中的 Rails 副本来处理更多请求,从而实现更好的服务器性能和更高效地利用多个核心。
要在应用程序的生产模式中启用多线程调度,请在您的 config/environments/production.rb
中添加以下行
config.threadsafe!
5 Active Record
这里有两个主要的新增功能:事务迁移和数据库事务池。还有一种新的(更简洁)的联接表条件语法,以及一些小的改进。
5.1 事务迁移
历史上,多步骤的 Rails 迁移一直是麻烦的根源。如果在迁移过程中出现错误,则错误之前的任何更改都会更改数据库,而错误之后的任何更改都不会应用。此外,迁移版本被存储为已执行,这意味着在您修复问题后,无法简单地通过 rake db:migrate:redo
重新运行它。事务迁移通过将迁移步骤包装在 DDL 事务中来改变这一点,因此如果其中任何一个步骤失败,整个迁移将被撤销。在 Rails 2.2 中,事务迁移开箱即用地支持 PostgreSQL。该代码将来可以扩展到其他数据库类型,IBM 已经扩展了它以支持 DB2 适配器。
- 主要贡献者:Adam Wiggins
- 更多信息
5.2 连接池
连接池允许 Rails 在一组数据库连接中分配数据库请求,这些连接将增长到最大大小(默认值为 5,但您可以在 database.yml
中添加一个 pool
键来调整它)。这有助于消除支持许多并发用户的应用程序中的瓶颈。还存在一个 wait_timeout
,它默认在放弃之前等待 5 秒。ActiveRecord::Base.connection_pool
使您可以直接访问池,如果您需要它。
development:
adapter: mysql
username: root
database: sample_development
pool: 10
wait_timeout: 10
- 主要贡献者:Nick Sieger
- 更多信息
5.3 用于联接表条件的哈希
您现在可以使用哈希来指定联接表上的条件。如果您需要跨复杂联接进行查询,这将是一个很大的帮助。
class Photo < ActiveRecord::Base
belongs_to :product
end
class Product < ActiveRecord::Base
has_many :photos
end
# Get all products with copyright-free photos:
Product.all(:joins => :photos, :conditions => { :photos => { :copyright => false }})
5.4 新的动态查找器
Active Record 的动态查找器系列中添加了两组新方法。
5.4.1 find_last_by_attribute
find_last_by_attribute
方法等效于 Model.last(:conditions => {:attribute => value})
# Get the last user who signed up from London
User.find_last_by_city('London')
- 主要贡献者:Emilio Tagua
5.4.2 find_by_attribute!
find_by_attribute!
的新叹号版本等效于 Model.first(:conditions => {:attribute => value}) || raise ActiveRecord::RecordNotFound
如果它找不到匹配的记录,它不会返回 nil
,而是会在找不到匹配项时引发异常。
# Raise ActiveRecord::RecordNotFound exception if 'Moby' hasn't signed up yet!
User.find_by_name!('Moby')
- 主要贡献者:Josh Susser
5.5 关联尊重私有/保护作用域
Active Record 关联代理现在尊重代理对象上方法的作用域。以前(假设 User has_one :account)@user.account.private_method
会在关联的 Account 对象上调用私有方法。这在 Rails 2.2 中失败了;如果您需要此功能,您应该使用 @user.account.send(:private_method)
(或者将该方法改为 public 而不是 private 或 protected)。请注意,如果您正在覆盖 method_missing
,您也应该覆盖 respond_to
以匹配该行为,以便关联可以正常工作。
- 主要贡献者:Adam Milligan
- 更多信息
5.6 其他 Active Record 更改
rake db:migrate:redo
现在接受一个可选的 VERSION 来指定要重新运行的特定迁移。- 设置
config.active_record.timestamped_migrations = false
以使迁移具有数字前缀而不是 UTC 时间戳。 - 计数器缓存列(对于使用
:counter_cache => true
声明的关联)不再需要初始化为零。 ActiveRecord::Base.human_name
用于模型名称的国际化感知的友好翻译
6 Action Controller
在控制器方面,有一些更改将有助于整理您的路由。路由引擎中还有一些内部更改,以降低复杂应用程序的内存使用量。
6.1 浅层路由嵌套
浅层路由嵌套提供了解决使用深度嵌套资源的众所周知问题的解决方案。使用浅层嵌套,您只需要提供足够的信息来唯一地标识您要使用的资源。
map.resources :publishers, :shallow => true do |publisher|
publisher.resources :magazines do |magazine|
magazine.resources :photos
end
end
这将启用识别(除其他外)这些路由
/publishers/1 ==> publisher_path(1)
/publishers/1/magazines ==> publisher_magazines_path(1)
/magazines/2 ==> magazine_path(2)
/magazines/2/photos ==> magazines_photos_path(2)
/photos/3 ==> photo_path(3)
- 主要贡献者:S. Brent Faulkner
- 更多信息
6.2 成员或集合路由的 Method 数组
现在您可以为新的成员或集合路由提供一个方法数组。这消除了当您需要处理多个方法时,必须定义一个接受任何动词的路由的烦恼。在 Rails 2.2 中,这是一种合法的路由声明
map.resources :photos, :collection => { :search => [:get, :post] }
- 主要贡献者:Brennan Dunn
6.3 具有特定操作的资源
默认情况下,当您使用 map.resources
创建路由时,Rails 会为七个默认操作(index、show、create、new、edit、update 和 destroy)生成路由。但是,每个路由都会占用您应用程序中的内存,并导致 Rails 生成额外的路由逻辑。现在,您可以使用 :only
和 :except
选项来微调 Rails 将为资源生成的路由。您可以提供单个操作、操作数组,或者使用特殊的 :all
或 :none
选项。这些选项被嵌套资源继承。
map.resources :photos, :only => [:index, :show]
map.resources :products, :except => :destroy
- 主要贡献者:Tom Stuart
6.4 其他 Action Controller 更改
- 现在您可以轻松地 显示一个自定义错误页面 来处理在路由请求时抛出的异常。
- HTTP Accept 标头现在默认情况下被禁用。您应该优先使用格式化的 URL(例如
/customers/1.xml
)来指示您想要的格式。如果您需要 Accept 标头,可以使用config.action_controller.use_accept_header = true
将其重新打开。 - 基准测试数字现在以毫秒而不是秒的微小分数报告。
- Rails 现在支持 HTTP-only cookie(并将其用于会话),这有助于减轻一些较新浏览器中的跨站点脚本风险。
redirect_to
现在完全支持 URI 方案(因此,例如,您可以重定向到 svn`ssh: URI)。render
现在支持:js
选项,以使用正确的 MIME 类型呈现纯 JavaScript。- 请求伪造保护已收紧,仅适用于 HTML 格式的内容请求。
- 如果传递的参数为 nil,多态 URL 的行为会更合理。例如,调用
polymorphic_path([@project, @date, @area])
,如果日期为 nil,将返回project_area_path
。
7 Action View
javascript_include_tag
和stylesheet_link_tag
支持一个新的:recursive
选项,与:all
一起使用,这样您就可以用一行代码加载整个文件树。- 包含的 Prototype JavaScript 库已升级到 1.6.0.3 版本。
RJS#page.reload
通过 JavaScript 重新加载浏览器的当前位置。atom_feed
助手现在采用:instruct
选项,允许您插入 XML 处理指令。
8 Action Mailer
Action Mailer 现在支持邮件程序布局。您可以通过提供一个适当命名的布局来使您的 HTML 邮件与浏览器中的视图一样漂亮 - 例如,CustomerMailer
类期望使用 layouts/customer_mailer.html.erb
。
Action Mailer 现在通过自动开启 STARTTLS 为 GMail 的 SMTP 服务器提供内置支持。这需要安装 Ruby 1.8.7。
9 Active Support
Active Support 现在为 Rails 应用程序提供内置的记忆化功能,each_with_object
方法,委托上的前缀支持,以及各种其他新的实用程序方法。
9.1 记忆化
记忆化是一种初始化方法一次,然后将其值存储起来以便重复使用的模式。您可能已经在自己的应用程序中使用过这种模式。
def full_name
@full_name ||= "#{first_name} #{last_name}"
end
记忆化允许您以声明方式处理此任务。
extend ActiveSupport::Memoizable
def full_name
"#{first_name} #{last_name}"
end
memoize :full_name
记忆化的其他功能包括 unmemoize
、unmemoize_all
和 memoize_all
,用于打开或关闭记忆化。
- 主要贡献者:Josh Peek
- 更多信息
9.2 each_with_object
each_with_object
方法提供了一种替代 inject
的方法,使用从 Ruby 1.9 移植回来的方法。它遍历集合,将当前元素和备忘录传递给块。
%w(foo bar).each_with_object({}) { |str, hsh| hsh[str] = str.upcase } # => {'foo' => 'FOO', 'bar' => 'BAR'}
主要贡献者:Adam Keys
9.3 带有前缀的委托
如果您将行为从一个类委托给另一个类,您现在可以指定一个前缀,该前缀将用于标识委托的方法。例如
class Vendor < ActiveRecord::Base
has_one :account
delegate :email, :password, :to => :account, :prefix => true
end
这将产生委托的方法 vendor#account_email
和 vendor#account_password
。您还可以指定一个自定义前缀
class Vendor < ActiveRecord::Base
has_one :account
delegate :email, :password, :to => :account, :prefix => :owner
end
这将产生委托的方法 vendor#owner_email
和 vendor#owner_password
。
主要贡献者:Daniel Schierbeck
9.4 其他 Active Support 更改
- 对
ActiveSupport::Multibyte
的大量更新,包括 Ruby 1.9 兼容性修复。 - 添加了
ActiveSupport::Rescuable
,允许任何类混合rescue_from
语法。 past?
、today?
和future?
用于Date
和Time
类,以方便日期/时间比较。Array#second
到Array#fifth
作为Array#[1]
到Array#[4]
的别名。Enumerable#many?
用于封装collection.size > 1
。Inflector#parameterize
生成其输入的 URL 就绪版本,用于to_param
中。Time#advance
识别小数天数和星期数,因此您可以执行1.7.weeks.ago
、1.5.hours.since
等操作。- 包含的 TzInfo 库已升级到 0.3.12 版本。
ActiveSupport::StringInquirer
为您提供了一种漂亮的方式来测试字符串中的相等性:ActiveSupport::StringInquirer.new("abc").abc? => true
10 Railties
在 Railties(Rails 本身的核心代码)中,最大的变化是在 config.gems
机制中。
10.1 config.gems
为了避免部署问题并使 Rails 应用程序更加自包含,可以将 Rails 应用程序所需的所有 gem 的副本放置在 /vendor/gems
中。此功能首次出现在 Rails 2.1 中,但在 Rails 2.2 中更加灵活和健壮,处理 gem 之间的复杂依赖关系。Rails 中的 gem 管理包括以下命令
- 在您的
config/environment.rb
文件中使用config.gem _gem_name_
rake gems
用于列出所有配置的 gem,以及它们(及其依赖项)是否已安装、冻结或框架(框架 gem 是 Rails 在执行 gem 依赖项代码之前加载的 gem;此类 gem 不能冻结)。rake gems:install
用于将缺失的 gem 安装到计算机上。rake gems:unpack
用于将所需 gem 的副本放置到/vendor/gems
中。rake gems:unpack:dependencies
用于获取所需 gem 及其依赖项的副本,并将它们放入/vendor/gems
中。rake gems:build
用于构建任何缺失的原生扩展。rake gems:refresh_specs
用于使使用 Rails 2.1 创建的 vendored gem 与 Rails 2.2 存储它们的方式保持一致。
您可以通过在命令行中指定 GEM=_gem_name_
来解压或安装单个 gem。
10.2 其他 Railties 更改
- 如果您是 Thin Web 服务器的粉丝,您会很高兴知道
script/server
现在直接支持 Thin。 script/plugin install <plugin> -r <revision>
现在支持基于 git 的插件以及基于 svn 的插件。script/console
现在支持--debugger
选项。- Rails 源代码中包含了设置持续集成服务器以构建 Rails 本身的说明。
rake notes:custom ANNOTATION=MYFLAG
允许您列出自定义注释。- 将
Rails.env
包装在StringInquirer
中,以便您可以执行Rails.env.development?
。 - 为了消除弃用警告并正确处理 gem 依赖项,Rails 现在需要 rubygems 1.3.1 或更高版本。
11 弃用
此版本中弃用了部分较旧的代码。
Rails::SecretKeyGenerator
已被ActiveSupport::SecureRandom
替换。render_component
已弃用。如果您需要此功能,可以使用 render_components 插件。渲染部分时的隐式局部变量赋值已弃用。
def partial_with_implicit_local_assignment @customer = Customer.new("Marcel") render :partial => "customer" end
之前,上面的代码在部分 'customer' 中提供了一个名为
customer
的局部变量。您现在应该通过 :locals 哈希显式传递所有变量。country_select
已被删除。有关更多信息和插件替换,请参阅 弃用页面。ActiveRecord::Base.allow_concurrency
不再有任何效果。ActiveRecord::Errors.default_error_messages
已被I18n.translate('activerecord.errors.messages')
弃用。国际化的
%s
和%d
插值语法已弃用。String#chars
已被String#mb_chars
弃用。小数月数或小数年数的持续时间已弃用。请改用 Ruby 的核心
Date
和Time
类算术。Request#relative_url_root
已弃用。请改用ActionController::Base.relative_url_root
。
12 致谢
发行说明由 Mike Gunderloy 编写。