1. 基础设施
Rails 2.2 是 Rails 基础设施的一个重要版本,它使 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! 的新 bang! 版本等效于 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)(或者将方法设置为公共而不是私有或受保护)。请注意,如果你正在重写 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. 成员或集合路由的方法数组
你现在可以为新的成员或集合路由提供一个方法数组。这消除了当你需要路由处理多个动词时,必须将路由定义为接受任何动词的烦恼。在 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 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语法。Date和Time类新增past?、today?和future?,以方便日期/时间比较。Array#second到Array#fifth作为Array#[1]到Array#[4]的别名Enumerable#many?用于封装collection.size > 1Inflector#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 应用程序所需的所有 gems 的副本放在 /vendor/gems 中。此功能首次出现在 Rails 2.1 中,但在 Rails 2.2 中它更加灵活和健壮,可以处理 gems 之间复杂的依赖关系。Rails 中的 gem 管理包括这些命令
- 在你的
config/environment.rb文件中设置config.gem _gem_name_ rake gems列出所有已配置的 gems,以及它们(及其依赖项)是否已安装、已冻结或框架(框架 gem 是 Rails 在执行 gem 依赖代码之前加载的 gem;此类 gem 不能冻结)rake gems:install将缺失的 gems 安装到计算机rake gems:unpack将所需 gems 的副本放入/vendor/gemsrake gems:unpack:dependencies将所需 gems 及其依赖项的副本放入/vendor/gemsrake gems:build构建任何缺失的本机扩展rake gems:refresh_specs使使用 Rails 2.1 创建的供应商 gems 与 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 整理