edge
更多信息请访问 rubyonrails.org: 更多 Ruby on Rails

Ruby on Rails 4.2 发布说明

Rails 4.2 的亮点:

这些发布说明仅涵盖了主要更改。要了解其他功能、错误修复和更改,请参考变更日志或查看 GitHub 上主要 Rails 仓库的提交列表

1 升级到 Rails 4.2

如果您要升级现有应用程序,在进行升级之前最好有良好的测试覆盖率。您还应该先升级到 Rails 4.1(如果尚未升级),并确保您的应用程序在升级到 Rails 4.2 之前仍然按预期运行。在升级时需要注意的事项列表可在升级 Ruby on Rails指南中找到。

2 主要功能

2.1 Active Job

Active Job 是 Rails 4.2 中的一个新框架。它是在诸如 ResqueDelayed JobSidekiq 等排队系统之上的一个通用接口。

使用 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 中的一组性能改进,可以使常见的 findfind_by 调用以及一些关联查询速度提高最多 2 倍。

它通过将常见的 SQL 查询缓存为预编译语句并在类似的调用上重用它们,跳过大部分查询生成工作。有关更多详细信息,请参阅 Aaron Patterson 的博客文章

Active Record 将自动在支持的操作中利用此功能,无需用户参与或更改代码。以下是一些受支持操作的示例:

Post.find(1)  # 第一次调用生成并缓存预编译语句
Post.find(2)  # 后续调用重用缓存的预编译语句

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,例如:

```ruby
# 不使用缓存
Post.find(1, 2, 3)
Post.find([1,2])
```
  • 使用SQL片段进行find_by

    Post.find_by('published_at < ?', 2.weeks.ago)
    

2.4 Web控制台

使用Rails 4.2生成的新应用程序现在默认带有Web Console gem。Web Console在每个错误页面上添加了一个交互式Ruby控制台,并提供了一个console视图和控制器助手。

错误页面上的交互式控制台允许您在异常发生的地方执行代码。如果在视图或控制器的任何位置调用console助手,则在渲染完成后会启动一个带有最终上下文的交互式控制台。

2.5 外键支持

迁移DSL现在支持添加和删除外键。它们也会被转储到schema.rb中。目前,只有mysqlmysql2postgresql适配器支持外键。

# 添加一个外键到`articles.author_id`,引用`authors.id`
add_foreign_key :articles, :authors

# 添加一个外键到`articles.author_id`,引用`users.lng_id`
add_foreign_key :articles, :users, column: :author_id, primary_key: "lng_id"

# 删除`accounts.branch_id`上的外键
remove_foreign_key :accounts, :branches

# 删除`accounts.owner_id`上的外键
remove_foreign_key :accounts, column: :owner_id

请参阅API文档中的add_foreign_keyremove_foreign_key 以获取完整的描述。

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。在您的Gemfile中添加gem 'responders', '~> 2.0'以使用它:

# 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:3000http://localhost: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。因此,一些先前有效的选择器现在不再受支持。如果您的应用程序使用了这些拼写,请务必更新它们:

  • 如果属性选择器中的值包含非字母数字字符,则可能需要对其进行引用。

    # 之前
    a[href=/]
    a[href$=/]
    
    # 现在
    a[href="/"]
    a[href$="/"]
    
  • 从包含有不正确嵌套元素的 HTML 源构建的 DOM 可能会有所不同。

    例如:

    # 内容: <div><i><p></i></div>
    
    # 之前:
    assert_select('div > i')  # => true
    assert_select('div > p')  # => false
    assert_select('i > p')    # => true
    
    # 现在:
    assert_select('div > i')  # => true
    assert_select('div > p')  # => true
    assert_select('i > p')    # => false
    
  • 如果所选数据包含实体,则用于比较的值之前是原始的(例如 AT&amp;T),现在是经过评估的(例如 AT&T)。

    # 内容: <p>AT&amp;T</p>
    
    # 之前:
    assert_select('p', 'AT&amp;T')  # => true
    assert_select('p', 'AT&T')      # => false
    
    # 现在:
    assert_select('p', 'AT&T')      # => true
    assert_select('p', 'AT&amp;T')  # => false
    

此外,替换语法也发生了变化。

现在您需要使用 :match 类似于 CSS 的选择器:

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: http://localhost: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)

  • 引入了一个after_bundle回调,用于Rails模板中的使用。 (Pull Request)

  • 引入了Rails.gem_version作为一个方便的方法,返回Gem::Version.new(Rails.version)。 (Pull Request)

5 Action Pack

详细更改请参阅Changelog

5.1 移除

  • 从Rails中移除了respond_with和类级别的respond_to,并将其移到responders gem(版本2.0)中。在Gemfile中添加gem 'responders', '~> 2.0'以继续使用这些功能。 (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    => (无需更改)
    get '/posts', to: 'post#index' => (无需更改)
    get '/posts', to: 'posts'      => get '/posts', controller: :posts
    get '/posts', to: :index       => get '/posts', action: :index
    

    (Commit)

  • 弃用了URL助手中的字符串键的支持:

    # 错误
    root_path('controller' => 'posts', 'action' => 'index')
    
    # 正确
    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中删除。

    (Commit 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通知现在在有效负载中包含控制器和动作名称。 (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

有关详细更改,请参阅Changelog

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

有关详细更改,请参阅Changelog

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

有关详细更改,请参阅Changelog

8.1 删除

  • 删除了cache_attributes和相关内容。所有属性都会被缓存。 (Pull Request)

  • 删除了弃用的方法ActiveRecord::Base.quoted_locking_column。 (Pull Request)

  • 删除了弃用的ActiveRecord::Migrator.proper_table_name。改用ActiveRecord::Migrationproper_table_name实例方法。 (Pull Request)

  • 删除了未使用的:timestamp类型。在所有情况下,将其透明地别名为:datetime。修复了在列类型发送到Active Record之外时的不一致性,例如用于XML序列化。 (Pull Request)

    弃用

  • 弃用在 after_commitafter_rollback 中吞噬错误的功能。 (Pull Request)

  • 弃用对 has_many :through 关联自动检测计数缓存的支持。您应该手动在 has_manybelongs_to 关联上指定计数缓存,以用于通过记录。 (Pull Request)

  • 弃用将 Active Record 对象传递给 .find.exists?。请先在对象上调用 id。 (Commit 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。在 Rails 5 中,默认值 null: true 将更改为 null: false。 (Pull Request)

  • 弃用不再需要的 Reflection#source_macro,没有替代方法。 (Pull Request)

  • 弃用 serialized_attributes,没有替代方法。 (Pull Request)

  • 弃用在没有列存在时从 column_for_attribute 返回 nil。在 Rails 5.0 中,它将返回一个空对象。 (Pull Request)

  • 弃用在依赖于实例状态的关联(即使用接受参数的作用域定义的关联)中使用 .joins.preload.eager_load,没有替代方法。 (Commit)

8.2 显著变化

  • SchemaDumpercreate_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)

  • 在 MySQL 5.6 及以上版本中添加了对分数秒的支持。 (Pull Request 1, 2)

  • 添加了ActiveRecord::Base#pretty_print来美化打印模型。 (拉取请求)

  • ActiveRecord::Base#reload现在的行为与m = Model.find(m.id)相同, 这意味着它不再保留来自自定义SELECT的额外属性。 (拉取请求)

  • ActiveRecord::Base#reflections现在返回一个带有字符串键而不是符号键的哈希。 (拉取请求)

  • 迁移中的references方法现在支持type选项,用于指定外键的类型(例如:uuid)。 (拉取请求)

9 Active Model

详细更改请参阅更新日志

9.1 移除

  • 移除了已弃用的Validator#setup,没有替代方法。 (拉取请求)

9.2 弃用

  • 弃用了reset_#{attribute},推荐使用restore_#{attribute}。 (拉取请求)

  • 弃用了ActiveModel::Dirty#reset_changes,推荐使用clear_changes_information。 (拉取请求)

9.3 显著更改

  • 引入了validate作为valid?的别名。 (拉取请求)

  • ActiveModel::Dirty中引入了restore_attributes方法,用于恢复已更改(脏)的属性为其先前的值。 (拉取请求 1, 2)

  • has_secure_password现在默认情况下不再禁止空密码(即只包含空格的密码)。 (拉取请求)

  • 如果启用了验证,has_secure_password现在会验证给定的密码是否少于72个字符。 (拉取请求)

10 Active Support

详细更改请参阅更新日志

10.1 移除

  • 移除了已弃用的Numeric#agoNumeric#untilNumeric#sinceNumeric#from_now。 (提交)

  • 移除了ActiveSupport::Callbacks中基于字符串的终止符的弃用。 (拉取请求)

10.2 弃用

  • 弃用了Kernel#silence_stderrKernel#captureKernel#quietly,没有替代方法。 (拉取请求)

  • 弃用了Class#superclass_delegating_accessor,请使用Class#class_attribute。 (拉取请求)

  • 弃用了ActiveSupport::SafeBuffer#prepend!,因为ActiveSupport::SafeBuffer#prepend现在具有相同的功能。 (拉取请求)

10.3 显著更改

  • 引入了一个新的配置选项active_support.test_order,用于指定测试用例的执行顺序。该选项当前默认为:sorted,但在Rails 5.0中将更改为:random。 (提交)

  • Object#tryObject#try!现在可以在块中不使用显式接收者。 (提交, 拉取请求)

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

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

  • Object#with_options现在可以在块中不使用显式接收者。 (拉取请求)

  • 引入了String#truncate_words,用于按单词数截断字符串。 (拉取请求)

  • 添加了Hash#transform_valuesHash#transform_values!,以简化一个常见模式,其中哈希的值必须更改,但键保持不变。 (拉取请求)

  • humanize词形变换助手现在会去除任何前导下划线。 (提交)

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

  • 新的指南,介绍了常量自动加载和重新加载。

11 贡献者

请参阅Rails的完整贡献者列表,感谢所有为Rails付出了大量时间的人,使其成为一个稳定和强大的框架。向他们致敬。

反馈

欢迎您帮助改进本指南的质量。

如果您发现任何拼写错误或事实错误,请贡献您的意见。 要开始,请阅读我们的 文档贡献 部分。

您还可能会发现不完整的内容或过时的内容。 请为主要内容添加任何缺失的文档。请先检查 Edge 指南,以验证问题是否已经修复或尚未修复。 请参阅 Ruby on Rails 指南准则 以了解样式和规范。

如果您发现需要修复但无法自行修复的问题,请 提交问题

最后但同样重要的是,欢迎您在 官方 Ruby on Rails 论坛 上讨论有关 Ruby on Rails 文档的任何问题。