更多内容请访问 rubyonrails.org:

Ruby on Rails 2.2 发行说明

Rails 2.2 提供了几个新增和改进的功能。此列表涵盖了主要的升级,但不包括所有的细微错误修复和更改。如果你想查看所有内容,请查看 GitHub 上主 Rails 仓库中的提交列表

除了 Rails,2.2 还标志着 Ruby on Rails 指南的发布,这是正在进行的 Rails 指南编程马拉松的首批成果。本网站将提供高质量的 Rails 主要功能文档。

1. 基础设施

Rails 2.2 是 Rails 基础设施的一个重要版本,它使 Rails 保持正常运行并与世界其他地方保持连接。

1.1. 国际化

Rails 2.2 提供了一个简单的国际化系统(或者 i18n,对于那些厌倦打字的人)。

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 开发人员提供了数万字的指导。

如果你想在应用程序中本地生成这些指南

$ rake doc:guides

这将把指南放在 Rails.root/doc/guides 中,你可以通过在你喜欢的浏览器中打开 Rails.root/doc/guides/index.html 立即开始浏览。

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 适配器。

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

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')

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')

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 以匹配行为,以便关联正常工作。

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)

6.2. 成员或集合路由的方法数组

你现在可以为新的成员或集合路由提供一个方法数组。这消除了当你需要路由处理多个动词时,必须将路由定义为接受任何动词的烦恼。在 Rails 2.2 中,这是一个合法的路由声明

map.resources :photos, :collection => { :search => [:get, :post] }

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

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_tagstylesheet_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

记忆化的其他功能包括 unmemoizeunmemoize_allmemoize_all,用于开启或关闭记忆化。

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_emailvendor#account_password。你还可以指定自定义前缀

class Vendor < ActiveRecord::Base
  has_one :account
  delegate :email, :password, :to => :account, :prefix => :owner
end

这将生成委托方法 vendor#owner_emailvendor#owner_password

主要贡献者:Daniel Schierbeck

9.4. 其他 Active Support 更改

  • ActiveSupport::Multibyte 进行了大量更新,包括 Ruby 1.9 兼容性修复。
  • ActiveSupport::Rescuable 的添加允许任何类混入 rescue_from 语法。
  • DateTime 类新增 past?today?future?,以方便日期/时间比较。
  • Array#secondArray#fifth 作为 Array#[1]Array#[4] 的别名
  • Enumerable#many? 用于封装 collection.size > 1
  • Inflector#parameterize 生成其输入的 URL 就绪版本,用于 to_param
  • Time#advance 识别分数天和周,因此你可以执行 1.7.weeks.ago1.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/gems
  • rake gems:unpack:dependencies 将所需 gems 及其依赖项的副本放入 /vendor/gems
  • rake 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 &lt;plugin&gt; -r &lt;revision&gt; 现在适用于基于 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 的核心 DateTime 类算术。

  • Request#relative_url_root 已弃用。请改用 ActionController::Base.relative_url_root

12. 鸣谢

发行说明由 Mike Gunderloy 整理



回到顶部