更多内容请访问 rubyonrails.org:

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 中的一组性能改进,使常见的 findfind_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_by

    Post.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 中。目前,只有 mysqlmysql2postgresql 适配器支持外键。

# 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_keyremove_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:3000https://: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 清理器已替换为基于 LoofahNokogiri 的新的、更强大的实现。新的清理器更安全,其清理功能更强大、更灵活。

由于采用了新算法,对于某些病态输入,清理后的输出可能会有所不同。

如果您特别需要旧清理器的确切输出,您可以将 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&amp;T),现在是评估后的值(例如 AT&T)。

    # content: <p>AT&amp;T</p>
    
    # before:
    assert_select('p', 'AT&amp;T')  # => true
    assert_select('p', 'AT&T')      # => false
    
    # now:
    assert_select('p', 'AT&T')      # => true
    assert_select('p', 'AT&amp;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
    

    (Pull Request)

  • 在应用程序生成器中引入了 --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 中移除并移至 responders gem(版本 2.0)。将 gem "responders", "~> 2.0" 添加到您的 Gemfile 以继续使用这些功能。(Pull Request, 更多详情)

  • 已删除已弃用的 AbstractController::Helpers::ClassMethods::MissingHelperError,推荐使用 AbstractController::Helpers::MissingHelperError。(Commit)

5.2. 弃用

  • 已弃用 *_path 助手上的 only_path 选项。(Commit)

  • 已弃用 assert_tagassert_no_tagfind_tagfind_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')
    

    (Pull Request)

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 中删除。

    (提交 1, 2)

  • 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 特殊局部变量,用于与集合一起渲染的分部。它通过 indexsizefirst?last? 方法提供对迭代当前状态的访问。(Pull Request)

  • 占位符 I18n 遵循与 label I18n 相同的约定。(Pull Request)

7. Action Mailer

请参阅 更改日志 以获取详细更改。

7.1. 弃用

  • 已弃用邮件程序中的 *_path 助手。始终使用 *_url 助手。(Pull Request)

  • 已弃用 deliver / deliver!,推荐使用 deliver_now / deliver_now!。(Pull Request)

7.2. 值得注意的更改

  • link_tourl_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_commitafter_rollback 内部的错误吞噬。(Pull Request)

  • 已弃用对 has_many :through 关联自动检测计数器缓存的损坏支持。您应该改为手动指定 has_manybelongs_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_timestampst.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. 显著变更

  • SchemaDumpercreate_table 上使用 force: :cascade。这使得在存在外键时可以重新加载模式。

  • 为单数关联添加了 :required 选项,该选项定义了对关联的 presence 验证。(Pull Request)

  • ActiveRecord::Dirty 现在检测可变值的原地更改。Active Record 模型上的序列化属性在未更改时不再保存。这也适用于其他类型,例如 PostgreSQL 上的字符串列和 JSON 列。(拉取请求 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)

  • 添加了对 MySQL 5.6 及更高版本的小数秒支持。(拉取请求 1, 2)

  • 添加了 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#agoNumeric#untilNumeric#sinceNumeric#from_now。(Commit)

  • 已删除 ActiveSupport::Callbacks 已弃用的基于字符串的终止符。(Pull Request)

10.2. 弃用

  • 已弃用 Kernel#silence_stderrKernel#captureKernel#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#tryObject#try! 现在可以在块中没有显式接收者的情况下使用。(Commit, Pull Request)

  • travel_to 测试助手现在将 usec 组件截断为 0。(Commit)

  • 引入了 Object#itself 作为恒等函数。(提交 1, 2)

  • Object#with_options 现在可以在块中没有显式接收者的情况下使用。(Pull Request)

  • 引入了 String#truncate_words,用于按单词数截断字符串。(Pull Request)

  • 添加了 Hash#transform_valuesHash#transform_values!,以简化常见模式,即哈希的值必须更改,但键保持不变。(Pull Request)

  • humanize 变体助手现在会去除任何前导下划线。(Commit)

  • 引入了 Concern#class_methods 作为 module ClassMethods 的替代方案,以及 Kernel#concern,以避免 module Foo; extend ActiveSupport::Concern; end 的样板。(Commit)

  • 关于常量自动加载和重新加载的新指南

11. 鸣谢

请参阅Rails 贡献者完整列表,感谢许多人为使 Rails 成为今天这样稳定和健壮的框架所花费的大量时间。向他们所有人致敬。



回到顶部