更多内容请访问 rubyonrails.org:

Ruby on Rails 3.2 发行说明

Rails 3.2 的亮点

  • 更快的开发模式
  • 新的路由引擎
  • 自动查询解释
  • 带标签的日志

这些发行说明仅涵盖主要变更。要了解各种错误修复和变更,请参阅变更日志或查看 GitHub 上主 Rails 仓库中的提交列表

1. 升级到 Rails 3.2

如果您正在升级现有应用程序,最好在开始之前做好充分的测试覆盖。如果您尚未升级到 Rails 3.1,则应先升级到 Rails 3.1,并确保您的应用程序在尝试更新到 Rails 3.2 之前仍然按预期运行。然后注意以下更改:

1.1. Rails 3.2 至少需要 Ruby 1.8.7

Rails 3.2 需要 Ruby 1.8.7 或更高版本。对所有以前 Ruby 版本的支持已正式终止,您应尽快升级。Rails 3.2 也与 Ruby 1.9.2 兼容。

请注意,Ruby 1.8.7 p248 和 p249 存在导致 Rails 崩溃的封送处理错误。Ruby Enterprise Edition 自 1.8.7-2010.02 发布以来已修复这些错误。在 1.9 版本方面,Ruby 1.9.1 不可用,因为它会直接发生段错误,因此如果您想使用 1.9.x,请直接跳到 1.9.2 或 1.9.3 以确保顺利运行。

1.2. 应用程序中需要更新的内容

  • 更新您的 Gemfile 以依赖于

    • rails = 3.2.0
    • sass-rails ~> 3.2.3
    • coffee-rails ~> 3.2.1
    • uglifier >= 1.0.3
  • Rails 3.2 弃用了 vendor/plugins,Rails 4.0 将完全移除它们。您可以开始通过将这些插件提取为 gems 并将其添加到 Gemfile 中来替换它们。如果您选择不将其制成 gems,您可以将它们移动到(例如)lib/my_plugin/* 并将适当的初始化程序添加到 config/initializers/my_plugin.rb 中。

  • 您需要在 config/environments/development.rb 中添加几个新的配置更改

    # Raise exception on mass assignment protection for Active Record models
    config.active_record.mass_assignment_sanitizer = :strict
    
    # Log the query plan for queries taking more than this (works
    # with SQLite, MySQL, and PostgreSQL)
    config.active_record.auto_explain_threshold_in_seconds = 0.5
    

    mass_assignment_sanitizer 配置也需要在 config/environments/test.rb 中添加

    # Raise exception on mass assignment protection for Active Record models
    config.active_record.mass_assignment_sanitizer = :strict
    

1.3. 引擎中需要更新的内容

script/rails 中注释下方的代码替换为以下内容

ENGINE_ROOT = File.expand_path('../..', __FILE__)
ENGINE_PATH = File.expand_path('../../lib/your_engine_name/engine', __FILE__)

require "rails/all"
require "rails/engine/commands"

2. 创建 Rails 3.2 应用程序

# You should have the 'rails' RubyGem installed
$ rails new myapp
$ cd myapp

2.1. 嵌入 Gem

Rails 现在在应用程序根目录中使用 Gemfile 来确定您的应用程序启动所需的 gem。此 GemfileBundler gem 处理,然后安装所有依赖项。它甚至可以将所有依赖项本地安装到您的应用程序中,以便它不依赖于系统 gem。

更多信息:Bundler 主页

2.2. 前沿开发

BundlerGemfile 使冻结您的 Rails 应用程序变得轻而易举,使用新的专用 bundle 命令。如果您想直接从 Git 仓库捆绑,可以传递 --edge 标志

$ rails new myapp --edge

如果您本地签出了 Rails 仓库并希望使用它生成应用程序,您可以传递 --dev 标志

$ ruby /path/to/rails/railties/bin/rails new myapp --dev

3. 主要功能

3.1. 更快的开发模式 & 路由

Rails 3.2 带有一个明显更快的开发模式。受 Active Reload 的启发,Rails 仅在文件实际更改时才重新加载类。在大型应用程序中,性能提升是巨大的。由于新的 Journey 引擎,路由识别也快了很多。

3.2. 自动查询解释

Rails 3.2 带有一个很棒的功能,它通过在 ActiveRecord::Relation 中定义 explain 方法来解释 Arel 生成的查询。例如,您可以运行 puts Person.active.limit(5).explain,并且 Arel 生成的查询会被解释。这允许检查适当的索引和进一步的优化。

在开发模式下,运行时间超过半秒的查询会自动解释。当然,这个阈值可以更改。

3.3. 带标签的日志

当运行多用户、多账户应用程序时,能够按谁做了什么来筛选日志非常有帮助。Active Support 中的 TaggedLogging 正是通过为日志行打上子域名、请求 ID 和其他任何有助于调试此类应用程序的标签来实现这一点的。

4. 文档

从 Rails 3.2 开始,Rails 指南可用于 Kindle 以及适用于 iPad、iPhone、Mac、Android 等设备的免费 Kindle 阅读应用程序。

5. Railties

  • 通过仅在依赖文件更改时重新加载类来加速开发。可以通过将 config.reload_classes_only_on_change 设置为 false 来关闭此功能。

  • 新应用程序在环境配置文件中获得一个标志 config.active_record.auto_explain_threshold_in_seconds。在 development.rb 中值为 0.5,在 production.rb 中被注释掉。在 test.rb 中未提及。

  • 添加了 config.exceptions_app 以设置当异常发生时由 ShowException 中间件调用的异常应用程序。默认为 ActionDispatch::PublicExceptions.new(Rails.public_path)

  • 添加了一个 DebugExceptions 中间件,其中包含从 ShowExceptions 中间件中提取的功能。

  • rake routes 中显示已挂载引擎的路由。

  • 允许通过 config.railties_order 更改 railties 的加载顺序,例如

    config.railties_order = [Blog::Engine, :main_app, :all]
    
  • Scaffold 对于没有内容的 API 请求返回 204 No Content。这使得 scaffold 可以直接与 jQuery 配合使用。

  • 更新 Rails::Rack::Logger 中间件以将 config.log_tags 中设置的任何标签应用于 ActiveSupport::TaggedLogging。这使得用子域名和请求 ID 等调试信息标记日志行变得容易——这对于调试多用户生产应用程序非常有帮助。

  • rails new 的默认选项可以在 ~/.railsrc 中设置。您可以在主目录中的 .railsrc 配置文件中指定每次运行 rails new 时使用的额外命令行参数。

  • destroy 添加别名 d。这也适用于引擎。

  • scaffold 和模型生成器上的属性默认为字符串。这允许以下操作:bin/rails g scaffold Post title body:text author

  • 允许 scaffold/model/migration 生成器接受“index”和“uniq”修饰符。例如,

    $ bin/rails g scaffold Post title:string:index author:uniq price:decimal{7,2}
    

    将为 titleauthor 创建索引,其中后者是唯一索引。某些类型(如 decimal)接受自定义选项。在示例中,price 将是一个 decimal 列,精度和刻度分别设置为 7 和 2。

  • Turn gem 已从默认 Gemfile 中移除。

  • 删除旧的插件生成器 rails generate plugin,转而使用 rails plugin new 命令。

  • 删除旧的 config.paths.app.controller API,转而使用 config.paths["app/controller"]

5.1. 弃用

  • Rails::Plugin 已弃用,并将在 Rails 4.0 中移除。建议使用 gems 或带有路径或 git 依赖项的 bundler,而不是将插件添加到 vendor/plugins

6. Action Mailer

  • Mail 版本升级到 2.4.0。

  • 移除了自 Rails 3.0 以来已弃用的旧 Action Mailer API。

7. Action Pack

7.1. Action Controller

  • 使 ActiveSupport::Benchmarkable 成为 ActionController::Base 的默认模块,以便 #benchmark 方法再次在控制器上下文中可用,就像以前一样。

  • 添加 :gzip 选项到 caches_page。默认选项可以通过 page_cache_compression 全局配置。

  • 现在,当您使用 :only:except 条件指定布局,并且这些条件失败时,Rails 将使用您的默认布局(例如 "layouts/application")。

    class CarsController
      layout 'single_car', :only => :show
    end
    

    当请求到达 :show 动作时,Rails 将使用 layouts/single_car,当请求到达任何其他动作时,将使用 layouts/application(如果存在,则为 layouts/cars)。

  • 如果提供了 :as 选项,form_for 已更改为使用 #{action}_#{as} 作为 CSS 类和 ID。早期版本使用 #{as}_#{action}

  • Active Record 模型上的 ActionController::ParamsWrapper 现在只包装已设置的 attr_accessible 属性。如果未设置,则只包装由类方法 attribute_names 返回的属性。这通过将嵌套属性添加到 attr_accessible 来修复嵌套属性的包装。

  • 每次在回调暂停时,记录“Filter chain halted as CALLBACKNAME rendered or redirected”。

  • ActionDispatch::ShowExceptions 已重构。控制器负责选择是否显示异常。可以在控制器中覆盖 show_detailed_exceptions? 以指定哪些请求应在错误时提供调试信息。

  • 现在,Responders 对于没有响应体的 API 请求(如新脚手架)返回 204 No Content。

  • ActionController::TestCase cookies 已重构。现在,为测试用例分配 cookies 应使用 cookies[]

    cookies[:email] = 'user@example.com'
    get :index
    assert_equal 'user@example.com', cookies[:email]
    

    要清除 cookie,请使用 clear

    cookies.clear
    get :index
    assert_nil cookies[:email]
    

    我们现在不再写入 HTTP_COOKIE,并且 cookie jar 在请求之间是持久的,因此如果您需要为测试操作环境,则需要在创建 cookie jar 之前进行操作。

  • 如果未提供 :typesend_file 现在会从文件扩展名猜测 MIME 类型。

  • 添加了 PDF、ZIP 和其他格式的 MIME 类型条目。

  • 允许 fresh_when/stale? 接受记录而不是选项哈希。

  • 将缺少 CSRF 令牌的警告日志级别从 :debug 更改为 :warn

  • 默认情况下,资产应使用请求协议,如果没有请求可用,则默认为相对路径。

7.1.1. 弃用

  • 弃用控制器中父级已设置显式布局时的隐式布局查找

    class ApplicationController
      layout "application"
    end
    
    class PostsController < ApplicationController
    end
    

    在上面的例子中,PostsController 将不再自动查找 posts 布局。如果您需要此功能,可以从 ApplicationController 中移除 layout "application",或在 PostsController 中将其显式设置为 nil

  • 弃用 ActionController::UnknownAction,转而使用 AbstractController::ActionNotFound

  • 弃用 ActionController::DoubleRenderError,转而使用 AbstractController::DoubleRenderError

  • 弃用 method_missing,转而使用 action_missing 处理缺失的动作。

  • 弃用 ActionController#rescue_actionActionController#initialize_template_classActionController#assign_shortcuts

7.2. Action Dispatch

  • 添加 config.action_dispatch.default_charset 以配置 ActionDispatch::Response 的默认字符集。

  • 添加了 ActionDispatch::RequestId 中间件,它将使唯一的 X-Request-Id 标头可用于响应,并启用 ActionDispatch::Request#uuid 方法。这使得在堆栈中端到端地跟踪请求以及在像 Syslog 这样的混合日志中识别单个请求变得容易。

  • ShowExceptions 中间件现在接受一个异常应用程序,该应用程序负责在应用程序失败时渲染异常。该应用程序在 env["action_dispatch.exception"] 中带有一个异常副本,并且 PATH_INFO 被重写为状态码。

  • 允许通过 railtie 配置救援响应,如 config.action_dispatch.rescue_responses

7.2.1. 弃用

  • 弃用在控制器级别设置默认字符集的能力,请改用新的 config.action_dispatch.default_charset

7.3. Action View

  • ActionView::Helpers::FormBuilder 添加 button_tag 支持。此支持模仿 submit_tag 的默认行为。

    <%= form_for @post do |f| %>
      <%= f.button %>
    <% end %>
    
  • 日期辅助函数接受一个新选项 :use_two_digit_numbers => true,该选项会渲染月份和日期的选择框,其中包含前导零,但不会更改相应的值。例如,这对于显示 ISO 8601 风格的日期(如“2011-08-01”)很有用。

  • 您可以为表单提供一个命名空间,以确保表单元素上 ID 属性的唯一性。命名空间属性将在生成的 HTML ID 上添加下划线作为前缀。

    <%= form_for(@offer, :namespace => 'namespace') do |f| %>
      <%= f.label :version, 'Version' %>:
      <%= f.text_field :version %>
    <% end %>
    
  • select_year 的选项数量限制为 1000。传递 :max_years_allowed 选项以设置您自己的限制。

  • content_tag_fordiv_for 现在可以接受记录集合。如果您在块中设置了接收参数,它还将记录作为第一个参数 yield。因此,您无需执行此操作

    @items.each do |item|
      content_tag_for(:li, item) do
        Title: <%= item.title %>
      end
    end
    

    您可以这样做

    content_tag_for(:li, @items) do |item|
      Title: <%= item.title %>
    end
    
  • 添加了 font_path 辅助方法,用于计算 public/fonts 中字体资产的路径。

7.3.1. 弃用

  • 弃用向 render :template 和类似方法传递格式或处理程序,例如 render :template => "foo.html.erb"。相反,您可以直接将 :handlers:formats 作为选项提供:render :template => "foo", :formats => [:html, :js], :handlers => :erb

7.4. Sprockets

  • 添加了一个配置选项 config.assets.logger 来控制 Sprockets 日志记录。将其设置为 false 可关闭日志记录,设置为 nil 可默认为 Rails.logger

8. Active Record

  • 布尔列的“on”和“ON”值被类型转换为 true。

  • timestamps 方法创建 created_atupdated_at 列时,默认情况下它们是不可为空的。

  • 实现了 ActiveRecord::Relation#explain

  • 实现了 ActiveRecord::Base.silence_auto_explain,允许用户在块内选择性地禁用自动 EXPLAIN。

  • 实现了针对慢查询的自动 EXPLAIN 日志记录。一个新的配置参数 config.active_record.auto_explain_threshold_in_seconds 决定了什么被认为是慢查询。将其设置为 nil 会禁用此功能。在开发模式下默认为 0.5,在测试和生产模式下为 nil。Rails 3.2 在 SQLite、MySQL (mysql2 适配器) 和 PostgreSQL 中支持此功能。

  • 添加了 ActiveRecord::Base.store 用于声明简单的单列键/值存储。

    class User < ActiveRecord::Base
      store :settings, accessors: [ :color, :homepage ]
    end
    
    u = User.new(color: 'black', homepage: '37signals.com')
    u.color                          # Accessor stored attribute
    u.settings[:country] = 'Denmark' # Any attribute, even if not specified with an accessor
    
  • 添加了仅在给定范围内运行迁移的能力,这允许仅从一个引擎运行迁移(例如,撤销需要移除的引擎的更改)。

    rake db:migrate SCOPE=blog
    
  • 从引擎复制的迁移现在作用于引擎的名称,例如 01_create_posts.blog.rb

  • 实现了 ActiveRecord::Relation#pluck 方法,该方法直接从底层表中返回列值的数组。这也适用于序列化属性。

    Client.where(:active => true).pluck(:id)
    # SELECT id from clients where active = 1
    
  • 生成的关联方法在一个单独的模块中创建,以允许覆盖和组合。对于名为 MyModel 的类,该模块名为 MyModel::GeneratedFeatureMethods。它在 Active Model 中定义的 generated_attributes_methods 模块之后立即包含到模型类中,因此关联方法会覆盖同名属性方法。

  • 添加 ActiveRecord::Relation#uniq 以生成唯一查询。

    Client.select('DISTINCT name')
    

    ..可以写成

    Client.select(:name).uniq
    

    这还允许您在关系中恢复唯一性

    Client.select(:name).uniq.uniq(false)
    
  • 支持 SQLite、MySQL 和 PostgreSQL 适配器中的索引排序。

  • 允许关联的 :class_name 选项除了字符串之外,还可以接受符号。这是为了避免混淆新手,并与 :foreign_key 等其他选项已经允许符号或字符串的事实保持一致。

    has_many :clients, :class_name => :Client # Note that the symbol need to be capitalized
    
  • 在开发模式下,db:drop 也会删除测试数据库,以便与 db:create 对称。

  • 当 MySQL 列已使用不区分大小写的排序规则时,不区分大小写的唯一性验证会避免调用 LOWER。

  • 事务性 fixtures 会招募所有活动的数据库连接。您可以在不同的连接上测试模型而无需禁用事务性 fixtures。

  • 为 Active Record 添加 first_or_createfirst_or_create!first_or_initialize 方法。这比旧的 find_or_create_by 动态方法是一种更好的方法,因为它更清楚哪些参数用于查找记录,哪些用于创建记录。

    User.where(:first_name => "Scarlett").first_or_create!(:last_name => "Johansson")
    
  • 向 Active Record 对象添加了 with_lock 方法,该方法启动事务,悲观锁定对象,并 yield 到块。该方法接受一个(可选)参数并将其传递给 lock!

    这使得可以编写以下内容

    class Order < ActiveRecord::Base
      def cancel!
        transaction do
          lock!
          # ... cancelling logic
        end
      end
    end
    

    作为

    class Order < ActiveRecord::Base
      def cancel!
        with_lock do
          # ... cancelling logic
        end
      end
    end
    

8.1. 弃用

  • 弃用线程中连接的自动关闭。例如,以下代码已弃用

    Thread.new { Post.find(1) }.join
    

    应将其更改为在线程结束时关闭数据库连接

    Thread.new {
      Post.find(1)
      Post.connection.close
    }.join
    

    只有在应用程序代码中创建线程的人才需要担心此更改。

  • set_table_nameset_inheritance_columnset_sequence_nameset_primary_keyset_locking_column 方法已弃用。请改用赋值方法。例如,不使用 set_table_name,而是使用 self.table_name=

    class Project < ActiveRecord::Base
      self.table_name = "project"
    end
    

    或者定义您自己的 self.table_name 方法

    class Post < ActiveRecord::Base
      def self.table_name
        "special_" + super
      end
    end
    
    Post.table_name # => "special_posts"
    

9. Active Model

  • 添加 ActiveModel::Errors#added? 以检查是否已添加特定错误。

  • 添加通过 strict => true 定义严格验证的能力,当验证失败时总是抛出异常。

  • 提供 mass_assignment_sanitizer 作为替换消毒行为的简单 API。还支持 :logger(默认)和 :strict 消毒行为。

9.1. 弃用

  • 弃用 ActiveModel::AttributeMethods 中的 define_attr_method,因为这仅用于支持 Active Record 中像 set_table_name 这样的方法,而这些方法本身正在被弃用。

  • 弃用 Model.model_name.partial_path,转而使用 model.to_partial_path

10. Active Resource

  • 重定向响应:303 See Other 和 307 Temporary Redirect 现在表现得像 301 Moved Permanently 和 302 Found。

11. Active Support

  • 添加了 ActiveSupport:TaggedLogging,它可以包装任何标准 Logger 类以提供标记功能。

    Logger = ActiveSupport::TaggedLogging.new(Logger.new(STDOUT))
    
    Logger.tagged("BCX") { Logger.info "Stuff" }
    # Logs "[BCX] Stuff"
    
    Logger.tagged("BCX", "Jason") { Logger.info "Stuff" }
    # Logs "[BCX] [Jason] Stuff"
    
    Logger.tagged("BCX") { Logger.tagged("Jason") { Logger.info "Stuff" } }
    # Logs "[BCX] [Jason] Stuff"
    
  • DateTimeDateTime 中的 beginning_of_week 方法接受一个可选参数,表示一周开始的日期。

  • ActiveSupport::Notifications.subscribed 在块运行时提供事件订阅。

  • 定义了新方法 Module#qualified_const_defined?Module#qualified_const_getModule#qualified_const_set,它们类似于标准 API 中的相应方法,但接受限定常量名称。

  • 添加了 #deconstantize,它补充了 #demodulize 在变体中的作用。这会删除限定常量名称中最右边的片段。

  • 添加了 safe_constantize,它可以将字符串常量化,但如果常量(或其一部分)不存在,则返回 nil 而不是引发异常。

  • 当使用 Array#extract_options! 时,ActiveSupport::OrderedHash 现在被标记为可提取。

  • 添加 Array#prepend 作为 Array#unshift 的别名,以及 Array#append 作为 Array#<< 的别名。

  • Ruby 1.9 的空白字符串定义已扩展到 Unicode 空格。此外,在 Ruby 1.8 中,表意空格 U`3000 被认为是空白字符。

  • 变体器理解首字母缩略词。

  • 添加了 Time#all_dayTime#all_weekTime#all_quarterTime#all_year 作为生成范围的方法。

    Event.where(:created_at => Time.now.all_week)
    Event.where(:created_at => Time.now.all_day)
    
  • 添加了 instance_accessor: false 作为 Class#cattr_accessor 及其朋友的选项。

  • 当给定一个接受带有 splat 的参数的块时,ActiveSupport::OrderedHash 现在对 #each#each_pair 有不同的行为。

  • 添加了 ActiveSupport::Cache::NullStore 用于开发和测试。

  • 移除了 ActiveSupport::SecureRandom,转而使用标准库中的 SecureRandom

11.1. 弃用

  • 弃用 ActiveSupport::Base64,转而使用 ::Base64

  • 弃用 ActiveSupport::Memoizable,转而使用 Ruby 备忘模式。

  • Module#synchronize 已弃用,没有替代品。请使用 Ruby 标准库中的 monitor。

  • 弃用 ActiveSupport::MessageEncryptor#encryptActiveSupport::MessageEncryptor#decrypt

  • ActiveSupport::BufferedLogger#silence 已弃用。如果您想在特定块中抑制日志,请更改该块的日志级别。

  • ActiveSupport::BufferedLogger#open_log 已弃用。此方法最初不应公开。

  • ActiveSupport::BufferedLogger 自动为您的日志文件创建目录的行为已弃用。请务必在实例化之前为您的日志文件创建目录。

  • ActiveSupport::BufferedLogger#auto_flushing 已弃用。要么像这样设置底层文件句柄的同步级别。或者调整您的文件系统。现在由 FS 缓存控制刷新。

    f = File.open('foo.log', 'w')
    f.sync = true
    ActiveSupport::BufferedLogger.new f
    
  • ActiveSupport::BufferedLogger#flush 已弃用。在您的文件句柄上设置同步,或调整您的文件系统。

12. 鸣谢

请参阅Rails 贡献者完整列表,感谢许多人花费大量时间将 Rails 打造成如此稳定和健壮的框架。向他们所有人致敬。

Rails 3.2 发行说明由Vijay Dev编写。



回到顶部