edge
更多信息请访问 rubyonrails.org: 更多 Ruby on Rails

Ruby on Rails 2.2 发布说明

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

除了 Rails,2.2 还标志着 Ruby on Rails Guides 的发布,这是持续进行中的 Rails Guides hackfest 的第一个成果。该网站将提供 Rails 主要功能的高质量文档。

1 基础设施

Rails 2.2 对保持 Rails 运行和与世界其他部分连接的基础设施进行了重要的更新。

1.1 国际化

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

1.2 与 Ruby 1.9 和 JRuby 的兼容性

除了线程安全性,还进行了大量工作,使得 Rails 在 JRuby 和即将发布的 Ruby 1.9 上能够良好运行。由于 Ruby 1.9 是一个不断变化的目标,运行最新版的 Rails 在最新版的 Ruby 上仍然是一个试错的过程,但是当后者发布时,Rails 已经准备好过渡到 Ruby 1.9。

2 文档

Rails 的内部文档,以代码注释的形式,在许多地方得到了改进。此外,Ruby on Rails Guides 项目是关于主要 Rails 组件信息的权威来源。在其首次正式发布中,Guides 页面包括:

总的来说,这些指南为初学者和中级 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])

    # 如果请求发送的标头与 stale? 方法提供的选项不同,那么请求确实是过期的,respond_to 块将被触发(并且 stale? 调用的选项将设置在响应中)。
    #
    # 如果请求标头匹配,那么请求是新鲜的,respond_to 块不会被触发。相反,将发生默认渲染,它将检查上次修改和 ETag 标头,并得出只需要发送 "304 Not Modified" 而不是渲染模板。
    if stale?(:last_modified => @article.published_at.utc, :etag => @article)
      respond_to do |wants|
        # 正常的响应处理
      end
    end
  end

  def show_with_implied_render
    @article = Article.find(params[:id])

    # 设置响应标头并将其与请求进行比较,如果请求是过期的(即 etag 或 last-modified 没有匹配),那么默认渲染模板将发生。
    # 如果请求是新鲜的,那么默认渲染将返回 "304 Not Modified" 而不是渲染模板。
    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

# 获取所有具有无版权照片的产品:
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})

# 获取最后一个来自伦敦注册的用户
User.find_last_by_city('London')

5.4.2 find_by_attribute!

find_by_attribute!的新版本是Model.first(:conditions => {:attribute => value}) || raise ActiveRecord::RecordNotFound。如果找不到匹配的记录,这个方法不会返回nil,而是会引发异常。

# 如果'Moby'尚未注册,则引发ActiveRecord::RecordNotFound异常!
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 其他动作控制器的变化

  • 现在,您可以轻松地为路由请求时引发的异常显示自定义错误页面
  • 默认情况下,禁用了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将更加合理。例如,使用nil日期调用polymorphic_path([@project, @date, @area])将给出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现在支持邮件布局。您可以通过提供一个适当命名的布局(例如,CustomerMailer类希望使用layouts/customer_mailer.html.erb)使您的HTML邮件与浏览器视图一样漂亮。

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,用于打开或关闭记忆化。 * 主要贡献者:Josh Peek * 更多信息: * Edge Rails的新功能:简单的记忆化 * 记忆化指南

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应用程序所需的所有gem的副本放在/vendor/gems中。这个功能首次出现在Rails 2.1中,但在Rails 2.2中更加灵活和健壮,处理了gem之间的复杂依赖关系。Rails中的gem管理包括以下命令:

  • config/environment.rb文件中使用config.gem _gem_name_
  • 使用rake gems列出所有配置的gem,以及它们(和它们的依赖项)是否已安装、冻结或框架(框架gem是在执行gem依赖代码之前由Rails加载的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 &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 编写

反馈

欢迎您帮助改进本指南的质量。

如果您发现任何拼写错误或事实错误,请贡献您的意见。 要开始,请阅读我们的 文档贡献 部分。

您还可能会发现不完整的内容或过时的内容。 请为主要内容添加任何缺失的文档。请先检查 Edge 指南,以验证问题是否已经修复或尚未修复。 请参阅 Ruby on Rails 指南准则 以了解样式和规范。

如果您发现需要修复但无法自行修复的问题,请 提交问题

最后但同样重要的是,欢迎您在 官方 Ruby on Rails 论坛 上讨论有关 Ruby on Rails 文档的任何问题。