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 并查找它们引用的对象。将 Active Record 对象作为作业参数传递只需在内部使用 Global ID 即可。
例如,如果 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)
需要强调的是,如上面的示例所示,预处理语句不缓存方法调用中传递的值;相反,它们有占位符。
在以下场景中不使用缓存
- 模型具有默认作用域
- 模型使用单表继承
使用 ID 列表的
find,例如# not cached Post.find(1, 2, 3) Post.find([1,2])使用 SQL 片段的
find_byPost.find_by('published_at < ?', 2.weeks.ago)
2.4. Web Console
使用 Rails 4.2 生成的新应用程序现在默认附带 Web Console gem。Web Console 在每个错误页面上添加了一个交互式 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://: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. 移除
应用程序生成器中已删除
--skip-action-view选项。(Pull Request)rails application命令已被删除,没有替代。(Pull Request)
4.2. 弃用
生产环境中缺少
config.log_level已弃用。(Pull Request)已弃用
rake test:all,推荐使用rake test,因为它现在运行test文件夹中的所有测试。(Pull Request)已弃用
rake test:all:db,推荐使用rake test:db。(Pull Request)已弃用
Rails::Rack::LogTailer,没有替代。(Commit)
4.3. 显著变更
在默认应用程序
Gemfile中引入了web-console。(Pull Request)为关联的模型生成器添加了
required选项。(Pull Request)引入了
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(Commit)
引入了
Rails::Application.config_for来加载当前环境的配置。# config/exception_notification.yml production: url: http://127.0.0.1:8080 namespace: my_app_production development: url: https://: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 集成。(Commit)引入了
bin/setup脚本作为引导应用程序时自动化设置代码的约定。(Pull Request)开发环境中
config.assets.digest的默认值已更改为true。(Pull Request)引入了一个 API 来为
rake notes注册新的扩展。(Pull Request)在 Rails 模板中引入了
after_bundle回调。(Pull Request)引入了
Rails.gem_version作为方便的方法,用于返回Gem::Version.new(Rails.version)。(Pull Request)
5. Action Pack
请参阅 更改日志 以获取详细更改。
5.1. 移除
respond_with和类级别的respond_to已从 Rails 中移除并移至respondersgem(版本 2.0)。将gem "responders", "~> 2.0"添加到您的Gemfile以继续使用这些功能。(Pull Request, 更多详情)已删除已弃用的
AbstractController::Helpers::ClassMethods::MissingHelperError,推荐使用AbstractController::Helpers::MissingHelperError。(Commit)
5.2. 弃用
已弃用
*_path助手上的only_path选项。(Commit)已弃用
assert_tag、assert_no_tag、find_tag和find_all_tag,推荐使用assert_select。(Commit)已弃用路由器
: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(Commit)
已弃用 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正文不再向响应正文添加单个空格填充。(Pull Request)Rails 现在自动将模板的摘要包含在 ETags 中。(Pull Request)
传递给 URL 助手的片段现在会自动转义。(Commit)
引入了
always_permitted_parameters选项,用于配置哪些参数全局允许。此配置的默认值为['controller', 'action']。(Pull Request)添加了 RFC 4791 中的 HTTP 方法
MKCALENDAR。(Pull Request)*_fragment.action_controller通知现在在 payload 中包含控制器和动作名称。(Pull Request)通过对路由搜索进行模糊匹配,改进了路由错误页面。(Pull Request)
添加了一个选项来禁用 CSRF 失败的日志记录。(Pull Request)
当 Rails 服务器设置为提供静态资产时,如果客户端支持并且磁盘上存在预生成的 gzip 文件 (
.gz),则将提供 gzip 资产。默认情况下,资产管道为所有可压缩资产生成.gz文件。提供 gzip 文件可最大程度地减少数据传输并加快资产请求。如果您在生产环境中从 Rails 服务器提供资产,请始终使用 CDN。(Pull Request)在集成测试中调用
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。(Pull Request)已弃用
ActionView::Digestor#digest(name, format, finder, options = {})。参数应改为以哈希形式传递。(Pull Request)
6.2. 值得注意的更改
render "foo/bar"现在扩展为render template: "foo/bar",而不是render file: "foo/bar"。(Pull Request)表单助手不再生成带有内联 CSS 的
<div>元素来包裹隐藏字段。(Pull Request)引入了
#{partial_name}_iteration特殊局部变量,用于与集合一起渲染的分部。它通过index、size、first?和last?方法提供对迭代当前状态的访问。(Pull Request)占位符 I18n 遵循与
labelI18n 相同的约定。(Pull Request)
7. Action Mailer
请参阅 更改日志 以获取详细更改。
7.1. 弃用
已弃用邮件程序中的
*_path助手。始终使用*_url助手。(Pull Request)已弃用
deliver/deliver!,推荐使用deliver_now/deliver_now!。(Pull Request)
7.2. 值得注意的更改
link_to和url_for默认在模板中生成绝对 URL,不再需要传递only_path: false。(Commit)引入了
deliver_later,它将作业排队到应用程序的队列以异步发送电子邮件。(Pull Request)添加了
show_previews配置选项,用于在开发环境之外启用邮件程序预览。(Pull Request)
8. Active Record
请参阅 更改日志 以获取详细更改。
8.1. 移除
已删除
cache_attributes和相关功能。所有属性都已缓存。(Pull Request)已删除已弃用的方法
ActiveRecord::Base.quoted_locking_column。(Pull Request)已删除已弃用的
ActiveRecord::Migrator.proper_table_name。请改用ActiveRecord::Migration上的proper_table_name实例方法。(Pull Request)已删除未使用的
:timestamp类型。在所有情况下都透明地将其别名为:datetime。修复了当列类型发送到 Active Record 之外时(例如 XML 序列化)的不一致问题。(Pull Request)
8.2. 弃用
已弃用
after_commit和after_rollback内部的错误吞噬。(Pull Request)已弃用对
has_many :through关联自动检测计数器缓存的损坏支持。您应该改为手动指定has_many和belongs_to关联的计数器缓存,以用于通过记录。(Pull Request)已弃用将 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)已弃用在不传递
:null选项的情况下使用add_timestamps和t.timestamps。默认的null: true将在 Rails 5 中更改为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选项,该选项定义了对关联的 presence 验证。(Pull Request)ActiveRecord::Dirty现在检测可变值的原地更改。Active Record 模型上的序列化属性在未更改时不再保存。这也适用于其他类型,例如 PostgreSQL 上的字符串列和 JSON 列。(拉取请求 1, 2, 3)引入了
db:purgeRake 任务,用于清空当前环境的数据库。(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
请参阅 更改日志 以获取详细更改。
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方法,用于将已更改(脏)属性恢复到其以前的值。(拉取请求 1, 2)has_secure_password不再默认禁止空白密码(即只包含空格的密码)。(Pull Request)如果启用了验证,
has_secure_password现在会验证给定密码是否小于 72 个字符。(Pull Request)
10. Active Support
请参阅 更改日志 以获取详细更改。
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 成为今天这样稳定和健壮的框架所花费的大量时间。向他们所有人致敬。