1 升级到 Rails 3.2
如果您要升级现有应用程序,建议您在进行升级之前拥有良好的测试覆盖率。您还应该先升级到 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 崩溃的序列化错误。自 1.8.7-2010.02 版本发布以来,Ruby Enterprise Edition 已修复了这些错误。在 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 将完全删除它们。您可以开始通过将这些插件提取为 gem 并将它们添加到您的Gemfile
中来替换它们。如果您选择不将它们制作成 gem,您可以将它们移动到例如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。此 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]
对于没有内容的 API 请求,脚手架返回 204 无内容。这使得脚手架能够与 jQuery 开箱即用。
更新
Rails::Rack::Logger
中间件以将config.log_tags
中设置的任何标签应用于ActiveSupport::TaggedLogging
。这使得用调试信息(如子域和请求 ID)标记日志行变得容易 - 这些信息对调试多用户生产应用程序非常有帮助。可以在
~/.railsrc
中设置rails new
的默认选项。您可以在主目录中的.railsrc
配置文件中指定每次运行rails new
时要使用的额外命令行参数。为
destroy
添加了一个别名d
。这也适用于引擎。脚手架和模型生成器上的属性默认设置为字符串。这允许以下操作:
bin/rails g scaffold Post title body:text author
允许脚手架/模型/迁移生成器接受“index”和“uniq”修饰符。例如,
$ bin/rails g scaffold Post title:string:index author:uniq price:decimal{7,2}
将为
title
和author
创建索引,其中后者是唯一索引。某些类型(如 decimal)接受自定义选项。在示例中,price
将是一个精度和比例分别设置为 7 和 2 的 decimal 列。从默认
Gemfile
中删除了 turn gem。删除了旧的插件生成器
rails generate plugin
,转而使用rails plugin new
命令。移除旧的
config.paths.app.controller
API,转而使用config.paths["app/controller"]
。
5.1 已弃用功能
Rails::Plugin
已弃用,将在 Rails 4.0 中移除。请使用 gems 或 bundler 添加带有路径或 git 依赖项的插件,而不是将插件添加到vendor/plugins
中。
6 Action Mailer
将
mail
版本升级到 2.4.0。移除旧的 Action Mailer API,该 API 自 Rails 3.0 起已弃用。
7 Action Pack
7.1 Action Controller
将
ActiveSupport::Benchmarkable
设为ActionController::Base
的默认模块,以便#benchmark
方法再次在控制器上下文中可用,就像以前一样。向
caches_page
添加了:gzip
选项。默认选项可以使用page_cache_compression
在全局配置中设置。现在,当使用
:only
和:except
条件指定布局,而这些条件不满足时,Rails 将使用您的默认布局(例如 "layouts/application")。class CarsController layout 'single_car', :only => :show end
当请求进入
:show
操作时,Rails 将使用layouts/single_car
,当请求进入任何其他操作时,Rails 将使用layouts/application
(如果存在,则使用layouts/cars
)。form_for
更改为使用#{action}_#{as}
作为 CSS 类和 ID(如果提供了:as
选项)。早期版本使用#{as}_#{action}
。Active Record 模型上的
ActionController::ParamsWrapper
现在仅在设置了attr_accessible
属性时才会包装它们。如果没有,则只会包装类方法attribute_names
返回的属性。这通过将嵌套属性添加到attr_accessible
中来修复嵌套属性的包装。每次 before 回调停止时,记录 "Filter chain halted as CALLBACKNAME rendered or redirected"。
ActionDispatch::ShowExceptions
已重构。控制器负责选择是否显示异常。可以在控制器中覆盖show_detailed_exceptions?
来指定哪些请求应在错误时提供调试信息。响应器现在针对没有响应正文的 API 请求返回 204 No Content(如新的脚手架)。
ActionController::TestCase
的 cookies 已重构。现在,为测试用例分配 cookie 应使用cookies[]
cookies[:email] = '[email protected]' get :index assert_equal '[email protected]', cookies[:email]
要清除 cookie,请使用
clear
。cookies.clear get :index assert_nil cookies[:email]
我们现在不再写出 HTTP_COOKIE,并且 cookie 容器在请求之间是持久的,因此如果您需要为测试操作环境,则需要在创建 cookie 容器之前进行。
如果未提供
: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
现在可以接受记录的集合。如果您在块中设置接收参数,它也会将记录作为第一个参数传递。因此,您不必这样做@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。
事务性夹具列出所有活动的数据库连接。您可以在不禁用事务性夹具的情况下测试不同连接上的模型。
向 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
方法,该方法会启动事务,锁定对象(悲观地),然后向代码块传递控制权。该方法接受一个(可选)参数,并将其传递给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
方法已弃用。请改用赋值方法。例如,请使用self.table_name=
而不是set_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
作为替换 sanitiser 行为的简单 API。也支持:logger
(默认)和:strict
sanitiser 行为。
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
及其朋友的一个选项添加。ActiveSupport::OrderedHash
在使用接受其参数并使用展开运算符的块时,#each
和#each_pair
的行为现在有所不同。添加了
ActiveSupport::Cache::NullStore
用于开发和测试。删除了
ActiveSupport::SecureRandom
,转而使用标准库中的SecureRandom
。
11.1 弃用
ActiveSupport::Base64
已被弃用,转而使用::Base64
。弃用了
ActiveSupport::Memoizable
,转而使用 Ruby 的记忆化模式。Module#synchronize
已被弃用,没有替代方案。请使用 ruby 标准库中的监视器。弃用了
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 f
ActiveSupport::BufferedLogger#flush
已被弃用。在文件句柄上设置同步,或者调整您的文件系统。
12 贡献者
查看Rails 的完整贡献者列表,了解为使 Rails 成为一个稳定而强大的框架而花费大量时间的人们。向他们所有人表示感谢。
Rails 3.2 版本说明由Vijay Dev 编写。