1 升级到 Rails 4.2
如果您要升级现有应用程序,建议在升级前拥有良好的测试覆盖率。您还应该首先升级到 Rails 4.1(如果您尚未升级),并确保您的应用程序在尝试升级到 Rails 4.2 之前能够正常运行。升级时需要注意的事项列表可在指南 升级 Ruby on Rails 中找到。
2 主要功能
2.1 Active Job
Active Job 是 Rails 4.2 中的新框架。它是在像 Resque、Delayed Job、Sidekiq 等排队系统之上的通用接口。
使用 Active Job API 编写的作业可以在任何支持的队列上运行,这得益于它们各自的适配器。Active Job 预先配置了一个内联运行器,它会立即执行作业。
作业通常需要将 Active Record 对象作为参数。Active Job 将对象引用作为 URI(统一资源标识符)传递,而不是序列化对象本身。新的 Global ID 库构建 URI 并查找它们引用的对象。通过在内部使用 Global ID,将 Active Record 对象作为作业参数传递可以正常工作。
例如,如果 trashable
是一个 Active Record 对象,那么此作业可以正常运行,无需进行任何序列化
class TrashableCleanupJob < ActiveJob::Base
def perform(trashable, depth)
trashable.cleanup(depth)
end
end
有关更多信息,请参阅 Active Job 基础 指南。
2.2 异步邮件
基于 Active Job,Action Mailer 现在提供了一个 deliver_later
方法,它通过队列发送电子邮件,因此如果队列是异步的(默认的内联队列会阻塞),它不会阻塞控制器或模型。
使用 deliver_now
仍然可以立即发送电子邮件。
2.3 Adequate Record
Adequate Record 是一组 Active Record 中的性能改进,它使常见的 find
和 find_by
调用以及一些关联查询的速度提高了 2 倍。
它通过将常见的 SQL 查询缓存为准备好的语句并在类似的调用中重复使用它们来工作,从而在后续调用中跳过大部分查询生成工作。有关更多详细信息,请参阅 Aaron Patterson 的博客文章。
Active Record 将在支持的操作上自动利用此功能,无需用户干预或代码更改。以下是一些受支持操作的示例
Post.find(1) # First call generates and cache the prepared statement
Post.find(2) # Subsequent calls reuse the cached prepared statement
Post.find_by_title('first post')
Post.find_by_title('second post')
Post.find_by(title: 'first post')
Post.find_by(title: 'second post')
post.comments
post.comments(true)
重要的是要注意,如上面的示例所示,准备好的语句不会缓存方法调用中传递的值;相反,它们会为它们提供占位符。
在以下情况下不使用缓存
- 模型具有默认作用域
- 模型使用单表继承
find
带 ID 列表,例如# not cached Post.find(1, 2, 3) Post.find([1,2])
find_by
带 SQL 片段Post.find_by('published_at < ?', 2.weeks.ago)
2.4 Web 控制台
使用 Rails 4.2 生成的新的应用程序现在默认情况下包含 Web 控制台 gem。Web 控制台在每个错误页面上添加了一个交互式 Ruby 控制台,并提供了一个 console
视图和控制器助手。
错误页面上的交互式控制台允许您在异常起源位置的上下文中执行代码。如果在视图或控制器中的任何地方调用 console
助手,它将在渲染完成后启动一个带最终上下文的交互式控制台。
2.5 外键支持
迁移 DSL 现在支持添加和删除外键。它们也转储到 schema.rb
中。目前,只有 mysql
、mysql2
和 postgresql
适配器支持外键。
# add a foreign key to `articles.author_id` referencing `authors.id`
add_foreign_key :articles, :authors
# add a foreign key to `articles.author_id` referencing `users.lng_id`
add_foreign_key :articles, :users, column: :author_id, primary_key: "lng_id"
# remove the foreign key on `accounts.branch_id`
remove_foreign_key :accounts, :branches
# remove the foreign key on `accounts.owner_id`
remove_foreign_key :accounts, column: :owner_id
有关完整描述,请参阅 add_foreign_key 和 remove_foreign_key 上的 API 文档。
3 不兼容性
以前已弃用的功能已被删除。请参阅各个组件以了解此版本中的新弃用内容。
以下更改可能需要在升级后立即采取措施。
3.1 render
带字符串参数
以前,在控制器操作中调用 render "foo/bar"
等效于 render file: "foo/bar"
。在 Rails 4.2 中,这已更改为改为表示 render template: "foo/bar"
。如果您需要渲染文件,请将您的代码更改为改为使用显式形式(render file: "foo/bar"
)。
3.2 respond_with
/ 类级 respond_to
respond_with
和相应的类级 respond_to
已移至 responders gem。将 gem "responders", "~> 2.0"
添加到您的 Gemfile
以使用它
# app/controllers/users_controller.rb
class UsersController < ApplicationController
respond_to :html, :json
def show
@user = User.find(params[:id])
respond_with @user
end
end
实例级 respond_to
不受影响
# app/controllers/users_controller.rb
class UsersController < ApplicationController
def show
@user = User.find(params[:id])
respond_to do |format|
format.html
format.json { render json: @user }
end
end
end
3.3 rails server
的默认主机
由于 Rack 中的更改,rails server
现在默认情况下在 localhost
上监听,而不是 0.0.0.0
。这应该对标准开发工作流程的影响最小,因为 http://127.0.0.1:3000 和 https://127.0.0.1:3000 将继续像以前一样在您自己的机器上工作。
但是,通过此更改,您将无法再从另一台机器访问 Rails 服务器,例如,如果您的开发环境位于虚拟机中,而您想从主机访问它。在这种情况下,请使用 rails server -b 0.0.0.0
启动服务器以恢复旧行为。
如果您这样做,请确保正确配置您的防火墙,以使只有网络上的受信任机器才能访问您的开发服务器。
3.4 更改 render
的状态选项符号
由于 Rack 中的更改,render
方法接受的 :status
选项的符号已更改
- 306:
:reserved
已被删除。 - 413:
:request_entity_too_large
已重命名为:payload_too_large
。 - 414:
:request_uri_too_long
已重命名为:uri_too_long
。 - 416:
:requested_range_not_satisfiable
已重命名为:range_not_satisfiable
。
请记住,如果使用未知符号调用 render
,则响应状态将默认为 500。
3.5 HTML 净化器
HTML 净化器已被一个新的、更强大的实现所取代,该实现基于Loofah和Nokogiri。新的净化器更加安全,其净化功能更强大、更灵活。
由于新算法,对于某些病态输入,净化后的输出可能会有所不同。
如果您需要旧净化器完全相同的输出,可以将rails-deprecated_sanitizer gem 添加到 Gemfile
中,以保持旧的行为。该 gem 不会发出弃用警告,因为它是可选的。
rails-deprecated_sanitizer
仅支持 Rails 4.2;它不会维护 Rails 5.0。
有关新净化器更改的更多详细信息,请参见这篇博文。
3.6 assert_select
assert_select
现在基于Nokogiri。因此,一些以前有效的选择器现在不支持。如果您的应用程序使用这些拼写中的任何一种,您需要更新它们。
属性选择器中的值可能需要加引号,如果它们包含非字母数字字符。
# before a[href=/] a[href$=/] # now a[href="/"] a[href$="/"]
从包含无效 HTML(嵌套不当的元素)的 HTML 源代码构建的 DOM 可能会有所不同。
例如
# content: <div><i><p></i></div> # before: assert_select('div > i') # => true assert_select('div > p') # => false assert_select('i > p') # => true # now: assert_select('div > i') # => true assert_select('div > p') # => true assert_select('i > p') # => false
如果所选数据包含实体,用于比较的所选值过去是原始的(例如
AT&T
),现在是评估后的(例如AT&T
)。# content: <p>AT&T</p> # before: assert_select('p', 'AT&T') # => true assert_select('p', 'AT&T') # => false # now: assert_select('p', 'AT&T') # => true assert_select('p', 'AT&T') # => false
此外,替换语法已更改。
现在您必须使用类似 CSS 的 :match
选择器
assert_select ":match('id', ?)", 'comment_1'
此外,当断言失败时,正则表达式替换看起来不同。请注意,/hello/
在这里
assert_select(":match('id', ?)", /hello/)
变为 "(?-mix:hello)"
Expected at least 1 element matching "div:match('id', "(?-mix:hello)")", found 0..
Expected 0 to be >= 1.
有关 assert_select
的更多信息,请参见Rails Dom Testing 文档。
4 Railties
有关详细更改,请参阅变更日志。
4.1 移除
4.2 弃用
弃用生产环境中缺少的
config.log_level
。(拉取请求)弃用
rake test:all
,改为rake test
,因为它现在运行test
文件夹中的所有测试。(拉取请求)弃用
rake test:all:db
,改为rake test:db
。(拉取请求)弃用
Rails::Rack::LogTailer
,没有替代品。(提交)
4.3 重要更改
在默认应用程序
Gemfile
中引入了web-console
。(拉取请求)为模型生成器中的关联添加了
required
选项。(拉取请求)引入了用于定义自定义配置选项的
x
命名空间# config/environments/production.rb config.x.payment_processing.schedule = :daily config.x.payment_processing.retries = 3 config.x.super_debugger = true
然后可以通过配置对象访问这些选项
Rails.configuration.x.payment_processing.schedule # => :daily Rails.configuration.x.payment_processing.retries # => 3 Rails.configuration.x.super_debugger # => true
(提交)
引入了
Rails::Application.config_for
用于加载当前环境的配置。# config/exception_notification.yml production: url: http://127.0.0.1:8080 namespace: my_app_production development: url: https://127.0.0.1:3001 namespace: my_app_development
# config/environments/production.rb Rails.application.configure do config.middleware.use ExceptionNotifier, config_for(:exception_notification) end
(拉取请求)
在应用程序生成器中引入了
--skip-turbolinks
选项,以便不生成 turbolinks 集成。(提交)引入了
bin/setup
脚本,作为在引导应用程序时使用自动设置代码的约定。(拉取请求)在开发环境中将
config.assets.digest
的默认值更改为true
。(拉取请求)引入了用于注册
rake notes
的新扩展的 API。(拉取请求)引入了
after_bundle
回调,供 Rails 模板使用。(拉取请求)引入了
Rails.gem_version
作为一种方便方法来返回Gem::Version.new(Rails.version)
。(拉取请求)
5 Action Pack
有关详细更改,请参阅变更日志。
5.1 移除
respond_with
和类级respond_to
已从 Rails 中删除,并移至responders
gem(版本 2.0)。将gem "responders", "~> 2.0"
添加到您的Gemfile
中以继续使用这些功能。(拉取请求,更多详细信息)删除了已弃用的
AbstractController::Helpers::ClassMethods::MissingHelperError
,改为AbstractController::Helpers::MissingHelperError
。(提交)
5.2 弃用
弃用了
*_path
帮助器上的only_path
选项。(提交)弃用
assert_tag
、assert_no_tag
、find_tag
和find_all_tag
,改为assert_select
。(提交)弃用了对在路由器上设置
:to
选项为符号或不包含“#”字符的字符串的支持get '/posts', to: MyRackApp => (No change necessary) get '/posts', to: 'post#index' => (No change necessary) get '/posts', to: 'posts' => get '/posts', controller: :posts get '/posts', to: :index => get '/posts', action: :index
(提交)
弃用了对 URL 帮助器中使用字符串键的支持
# bad root_path('controller' => 'posts', 'action' => 'index') # good root_path(controller: 'posts', action: 'index')
(拉取请求)
5.3 重要更改
*_filter
方法系列已从文档中删除。建议使用*_action
方法系列代替它们。after_filter => after_action append_after_filter => append_after_action append_around_filter => append_around_action append_before_filter => append_before_action around_filter => around_action before_filter => before_action prepend_after_filter => prepend_after_action prepend_around_filter => prepend_around_action prepend_before_filter => prepend_before_action skip_after_filter => skip_after_action skip_around_filter => skip_around_action skip_before_filter => skip_before_action skip_filter => skip_action_callback
如果您的应用程序当前依赖于这些方法,您应该使用替代的
*_action
方法。这些方法将在将来弃用,并最终从 Rails 中删除。render nothing: true
或渲染nil
主体不再向响应主体添加单个空格填充。(拉取请求)Rails 现在会自动在 ETag 中包含模板的摘要。(拉取请求)
传递到 URL 帮助器的段现在会自动转义。(提交)
引入了
always_permitted_parameters
选项来配置全局允许哪些参数。此配置的默认值为['controller', 'action']
。(拉取请求)*_fragment.action_controller
通知现在在有效负载中包含控制器和操作名称。(拉取请求)改进了路由错误页面,增加了对路由搜索的模糊匹配。(拉取请求)
添加了用于禁用记录 CSRF 失败的选项。(拉取请求)
当 Rails 服务器设置为提供静态资产时,如果客户端支持并存在预先生成的 gzip 文件(
.gz
),现在将提供 gzip 资产。默认情况下,资产管道为所有可压缩资产生成.gz
文件。提供 gzip 文件可以最大程度地减少数据传输并加快资产请求速度。如果您在生产环境中从 Rails 服务器提供资产,请始终使用 CDN。(拉取请求)在集成测试中调用
process
帮助器时,路径需要有一个前导斜杠。以前您可以省略它,但这只是实现的副产品,而不是有意为之的功能,例如test "list all posts" do get "/posts" assert_response :success end
6 Action View
有关详细更改,请参阅变更日志。
6.1 弃用
弃用
AbstractController::Base.parent_prefixes
。当您想要更改查找视图的位置时,请重写AbstractController::Base.local_prefixes
。(拉取请求)弃用
ActionView::Digestor#digest(name, format, finder, options = {})
。参数应作为哈希而不是单独传递。(拉取请求)
6.2 重要更改
render "foo/bar"
现在扩展为render template: "foo/bar"
而不是render file: "foo/bar"
。(拉取请求)表单帮助器不再围绕隐藏字段生成带有内联 CSS 的
<div>
元素。(拉取请求)引入了
#{partial_name}_iteration
特殊局部变量,供与集合一起渲染的局部变量使用。它通过index
、size
、first?
和last?
方法提供对迭代当前状态的访问。(拉取请求)占位符 I18n 遵循与
label
I18n 相同的约定。(拉取请求)
7 Action Mailer
有关详细更改,请参阅变更日志。
7.1 弃用
弃用了邮件程序中的
*_path
帮助器。始终使用*_url
帮助器代替。(拉取请求)弃用
deliver
/deliver!
,改为deliver_now
/deliver_now!
。(拉取请求)
7.2 重要更改
link_to
和url_for
在模板中默认生成绝对 URL,不再需要传递only_path: false
。(提交)引入了
deliver_later
,它在应用程序的队列上排队一个作业,以异步方式发送电子邮件。(拉取请求)添加了
show_previews
配置选项,用于在开发环境之外启用邮件程序预览。(拉取请求)
8 Active Record
有关详细更改,请参阅变更日志。
8.1 移除
删除了
cache_attributes
及其相关方法。所有属性都被缓存。(拉取请求)删除了已弃用的方法
ActiveRecord::Base.quoted_locking_column
。(拉取请求)删除了已弃用的
ActiveRecord::Migrator.proper_table_name
。请改用ActiveRecord::Migration
上的proper_table_name
实例方法。(拉取请求)删除了未使用的
:timestamp
类型。在所有情况下都将其透明地别名为:datetime
。修复了在将列类型发送到 Active Record 之外时(例如用于 XML 序列化)出现的不一致性。(拉取请求)
8.2 弃用
弃用了
after_commit
和after_rollback
内部对错误的吞咽。(拉取请求)弃用了对
has_many :through
关联中自动检测计数器缓存的错误支持。您应该改为在has_many
和belongs_to
关联中手动指定通过记录的计数器缓存。(拉取请求)弃用了将 Active Record 对象传递给
.find
或.exists?
。请先对对象调用id
。(提交 1,2)弃用了对 PostgreSQL 范围值与排除开头的半生不熟的支持。我们目前将 PostgreSQL 范围映射到 Ruby 范围。这种转换并不完全可行,因为 Ruby 范围不支持排除开头。
在开始处递增的当前解决方案不正确,现已弃用。对于我们不知道如何递增的子类型(例如,
succ
未定义),对于排除开始处的范围,它将引发ArgumentError
。(Commit)已弃用在没有连接的情况下调用
DatabaseTasks.load_schema
。请改用DatabaseTasks.load_schema_current
。(Commit)已弃用
sanitize_sql_hash_for_conditions
,没有替代方案。使用Relation
来执行查询和更新是首选的 API。(Commit)已弃用
add_timestamps
和t.timestamps
而不传递:null
选项。Rails 5 中的null: true
默认值将更改为null: false
。(Pull Request)已弃用
Reflection#source_macro
,没有替代方案,因为它在 Active Record 中不再需要。(Pull Request)已弃用
serialized_attributes
,没有替代方案。(Pull Request)已弃用当不存在列时从
column_for_attribute
返回nil
。在 Rails 5.0 中,它将返回一个空对象。(Pull Request)已弃用使用
.joins
、.preload
和.eager_load
与依赖于实例状态的关联(即那些使用接受参数的范围定义的关联),没有替代方案。(Commit)
8.3 重点更改
SchemaDumper
在create_table
上使用force: :cascade
。这使得在存在外键时重新加载模式成为可能。向单数关联添加了
:required
选项,该选项在关联上定义存在验证。(Pull Request)ActiveRecord::Dirty
现在可以检测可变值的原地更改。Active Record 模型上的序列化属性在没有更改时不再保存。这也适用于其他类型,例如字符串列和 PostgreSQL 上的 json 列。(Pull Requests 1,2,3)引入了
db:purge
Rake 任务来清空当前环境的数据库。(Commit)引入了
ActiveRecord::Base#validate!
,如果记录无效,则会引发ActiveRecord::RecordInvalid
。(Pull Request)引入了
validate
作为valid?
的别名。(Pull Request)touch
现在接受多个属性,以便一次性触碰多个属性。(Pull Request)PostgreSQL 适配器现在在 PostgreSQL 9.4+ 中支持
jsonb
数据类型。(Pull Request)PostgreSQL 和 SQLite 适配器不再在字符串列上添加 255 个字符的默认限制。(Pull Request)
在 PostgreSQL 适配器中添加了对
citext
列类型的支持。(Pull Request)在 PostgreSQL 适配器中添加了对用户创建的范围类型的支持。(Commit)
sqlite3:///some/path
现在解析为绝对系统路径/some/path
。对于相对路径,请改用sqlite3:some/path
。(以前,sqlite3:///some/path
解析为相对路径some/path
。这种行为在 Rails 4.1 中已弃用)。(Pull Request)添加了
ActiveRecord::Base#pretty_print
来美化打印模型。(Pull Request)ActiveRecord::Base#reload
现在与m = Model.find(m.id)
的行为相同,这意味着它不再保留来自自定义SELECT
的额外属性。(Pull Request)ActiveRecord::Base#reflections
现在返回一个带有字符串键而不是符号键的哈希表。(Pull Request)迁移中的
references
方法现在支持type
选项,用于指定外键的类型(例如:uuid
)。(Pull Request)
9 Active Model
有关详细更改,请参阅 Changelog。
9.1 删除
- 已弃用
Validator#setup
,没有替代方案。(Pull Request)
9.2 弃用
已弃用
reset_#{attribute}
,请改用restore_#{attribute}
。(Pull Request)已弃用
ActiveModel::Dirty#reset_changes
,请改用clear_changes_information
。(Pull Request)
9.3 重点更改
引入了
validate
作为valid?
的别名。(Pull Request)在
ActiveModel::Dirty
中引入了restore_attributes
方法,用于将更改的(脏的)属性恢复为它们以前的值。(Pull Request 1,2)has_secure_password
默认情况下不再禁止空白密码(即仅包含空格的密码)。(Pull Request)如果启用了验证,
has_secure_password
现在会验证给定密码是否少于 72 个字符。(Pull Request)
10 Active Support
有关详细更改,请参阅 Changelog。
10.1 删除
已弃用
Numeric#ago
、Numeric#until
、Numeric#since
、Numeric#from_now
。(Commit)已弃用基于字符串的
ActiveSupport::Callbacks
终止符。(Pull Request)
10.2 弃用
已弃用
Kernel#silence_stderr
、Kernel#capture
和Kernel#quietly
,没有替代方案。(Pull Request)已弃用
Class#superclass_delegating_accessor
,请改用Class#class_attribute
。(Pull Request)已弃用
ActiveSupport::SafeBuffer#prepend!
,因为ActiveSupport::SafeBuffer#prepend
现在执行相同的功能。(Pull Request)
10.3 重点更改
引入了新的配置选项
active_support.test_order
,用于指定执行测试用例的顺序。此选项目前默认值为:sorted
,但在 Rails 5.0 中将更改为:random
。(Commit)Object#try
和Object#try!
现在可以在块中使用,无需显式接收器。(Commit,Pull Request)travel_to
测试助手现在会将usec
组件截断为 0。(Commit)Object#with_options
现在可以在块中使用,无需显式接收器。(Pull Request)引入了
String#truncate_words
,用于按单词数量截断字符串。(Pull Request)添加了
Hash#transform_values
和Hash#transform_values!
,以简化哈希表的值必须更改但键保持不变的常见模式。(Pull Request)humanize
变形词助手现在会删除任何前导下划线。(Commit)引入了
Concern#class_methods
作为module ClassMethods
的替代方案,以及Kernel#concern
,以避免module Foo; extend ActiveSupport::Concern; end
模板。(Commit)新的 指南 关于常量自动加载和重新加载。
11 鸣谢
查看 Rails 的完整贡献者列表,了解那些花了很多时间让 Rails 成为今天这样稳定而健壮的框架的许多人。向他们所有人致敬。