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.0sass-rails ~> 3.2.3coffee-rails ~> 3.2.1uglifier >= 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.5mass_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。此 Gemfile 由 Bundler gem 处理,然后安装所有依赖项。它甚至可以将所有依赖项本地安装到您的应用程序中,以便它不依赖于系统 gem。
更多信息:Bundler 主页
2.2. 前沿开发
Bundler 和 Gemfile 使冻结您的 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}将为
title和author创建索引,其中后者是唯一索引。某些类型(如 decimal)接受自定义选项。在示例中,price将是一个 decimal 列,精度和刻度分别设置为 7 和 2。Turn gem 已从默认
Gemfile中移除。删除旧的插件生成器
rails generate plugin,转而使用rails plugin new命令。删除旧的
config.paths.app.controllerAPI,转而使用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::TestCasecookies 已重构。现在,为测试用例分配 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 之前进行操作。
如果未提供
:type,send_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_action、ActionController#initialize_template_class和ActionController#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_for和div_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_at和updated_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_create、first_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_name、set_inheritance_column、set_sequence_name、set_primary_key、set_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"Date、Time和DateTime中的beginning_of_week方法接受一个可选参数,表示一周开始的日期。ActiveSupport::Notifications.subscribed在块运行时提供事件订阅。定义了新方法
Module#qualified_const_defined?、Module#qualified_const_get和Module#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_day、Time#all_week、Time#all_quarter和Time#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#encrypt和ActiveSupport::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 fActiveSupport::BufferedLogger#flush已弃用。在您的文件句柄上设置同步,或调整您的文件系统。
12. 鸣谢
请参阅Rails 贡献者完整列表,感谢许多人花费大量时间将 Rails 打造成如此稳定和健壮的框架。向他们所有人致敬。
Rails 3.2 发行说明由Vijay Dev编写。