diff --git a/source/zh-CN/association_basics.md b/source/zh-CN/association_basics.md index c7316a9..cfc3c33 100644 --- a/source/zh-CN/association_basics.md +++ b/source/zh-CN/association_basics.md @@ -849,6 +849,7 @@ a.first_name == b.writer.first_name # => true * `build_association(attributes = {})` * `create_association(attributes = {})` * `create_association!(attributes = {})` +* `reload_association` 这五个方法中的 `association` 要替换成传给 `belongs_to` 方法的第一个参数。对下述声明来说: @@ -866,6 +867,7 @@ author= build_author create_author create_author! +reload_author ``` NOTE: 在 `has_one` 和 `belongs_to` 关联中,必须使用 `build_*` 方法构建关联对象。`association.build` 方法是在 `has_many` 和 `has_and_belongs_to_many` 关联中使用的。创建关联对象要使用 `create_*` 方法。 @@ -881,10 +883,10 @@ NOTE: 在 `has_one` 和 `belongs_to` 关联中,必须使用 `build_*` 方法 @author = @book.author ``` -如果关联的对象之前已经取回,会返回缓存版本。如果不想使用缓存版本(强制读取数据库)在父对象上调用 `#reload` 方法。 +如果关联的对象之前已经取回,会返回缓存版本。如果不想使用缓存版本(强制读取数据库)在父对象上调用 `#reload_association` 方法。 ```ruby -@author = @book.reload.author +@author = @book.reload_author ``` @@ -1020,13 +1022,10 @@ NOTE: 只需在关联的 `belongs_to` 一侧指定 `:counter_cache` 选项。 ##### `:dependent` -`:dependent` 选项控制属主销毁后怎么处理关联的对象: +`:dependent` 选项可以设为以下几个值: -* `:destroy`:也销毁关联的对象 -* `:delete_all`:直接从数据库中删除关联的对象(不执行回调) -* `:nullify`:把外键设为 `NULL`(不执行回调) -* `:restrict_with_exception`:如果有关联的记录,抛出异常 -* `:restrict_with_error`:如果有关联的对象,为属主添加一个错误 +* `:destroy`:销毁对象时,在关联的对象上调用 `destroy` 方法 +* `:delete`:销毁对象时,关联的所有对象直接从数据库中删除,不在关联的对象上调用 `destroy` 方法 WARNING: 在 `belongs_to` 关联和 `has_many` 关联配对时,不应该设置这个选项,否则会导致数据库中出现无主记录。 @@ -1236,6 +1235,7 @@ TIP: 如果在 `belongs_to` 关联中使用 `select` 方法,应该同时设置 * `build_association(attributes = {})` * `create_association(attributes = {})` * `create_association!(attributes = {})` +* `reload_association` 这五个方法中的 `association` 要替换成传给 `has_one` 方法的第一个参数。对如下的声明来说: @@ -1253,6 +1253,7 @@ account= build_account create_account create_account! +reload_account ``` NOTE: 在 `has_one` 和 `belongs_to` 关联中,必须使用 `build_*` 方法构建关联对象。`association.build` 方法是在 `has_many` 和 `has_and_belongs_to_many` 关联中使用的。创建关联对象要使用 `create_*` 方法。 @@ -1268,10 +1269,10 @@ NOTE: 在 `has_one` 和 `belongs_to` 关联中,必须使用 `build_*` 方法 @account = @supplier.account ``` -如果关联的对象之前已经取回,会返回缓存版本。如果不想使用缓存版本,而是强制重新从数据库中读取,在父对象上调用 `#reload` 方法。 +如果关联的对象之前已经取回,会返回缓存版本。如果不想使用缓存版本,而是强制重新从数据库中读取,在父对象上调用 `#reload_association` 方法。 ```ruby -@account = @supplier.reload.account +@account = @supplier.reload_account ``` @@ -1567,6 +1568,7 @@ end * `collection.build(attributes = {}, …​)` * `collection.create(attributes = {})` * `collection.create!(attributes = {})` +* `collection.reload` 这些个方法中的 `collection` 要替换成传给 `has_many` 方法的第一个参数。`collection_singular` 要替换成第一个参数的单数形式。对如下的声明来说: @@ -1595,13 +1597,14 @@ books.exists?(...) books.build(attributes = {}, ...) books.create(attributes = {}) books.create!(attributes = {}) +books.reload ``` ##### `collection` -`collection` 方法返回一个数组,包含所有关联的对象。如果没有关联的对象,则返回空数组。 +`collection` 方法返回一个 `Relation` 对象,包含所有关联的对象。如果没有关联的对象,则返回一个空 `Relation` 对象。 ```ruby @books = @author.books @@ -1758,10 +1761,20 @@ WARNING: 如果设为 `dependent: :destroy`,对象会被删除,这与 `depen -#### `collection.create!(attributes = {})` +##### `collection.create!(attributes = {})` 作用与 `collection.create` 相同,但如果记录无效,会抛出 `ActiveRecord::RecordInvalid` 异常。 + + +##### `collection.reload` + +`collection.reload` 强制从数据库中读取,返回一个 `Relation` 对象,包含所有关联的对象。如果没有关联的对象,返回一个空 `Relation` 对象。 + +```ruby +@books = @author.books.reload +``` + #### `has_many` 方法的选项 @@ -2154,6 +2167,7 @@ person.articles << article unless person.articles.include?(article) * `collection.build(attributes = {})` * `collection.create(attributes = {})` * `collection.create!(attributes = {})` +* `collection.reload` 这些个方法中的 `collection` 要替换成传给 `has_and_belongs_to_many` 方法的第一个参数。`collection_singular` 要替换成第一个参数的单数形式。对如下的声明来说: @@ -2182,6 +2196,7 @@ assemblies.exists?(...) assemblies.build(attributes = {}, ...) assemblies.create(attributes = {}) assemblies.create!(attributes = {}) +assemblies.reload ``` @@ -2196,7 +2211,7 @@ WARNING: 在 `has_and_belongs_to_many` 关联的联结表中使用其他字段 ##### `collection` -`collection` 方法返回一个数组,包含所有关联的对象。如果没有关联的对象,则返回空数组。 +`collection` 方法返回一个 `Relation` 对象,包含所有关联的对象。如果没有关联的对象,则返回一个空 `Relation` 对象。 ```ruby @assemblies = @part.assemblies @@ -2336,6 +2351,16 @@ NOTE: 这个方法是 `collection.concat` 和 `collection.push` 的别名。 作用和 `collection.create` 相同,但如果记录无效,会抛出 `ActiveRecord::RecordInvalid` 异常。 + + +##### `collection.reload` + +`collection.reload` 方法强制从数据库中读取,返回一个 `Relation` 对象,包含所有关联的对象。如果没有关联的对象,返回一个空 `Relation` 对象。 + +```ruby +@assemblies = @part.assemblies.reload +``` + #### `has_and_belongs_to_many` 方法的选项 diff --git a/source/zh-CN/getting_started.md b/source/zh-CN/getting_started.md index f4fb83a..85f152d 100644 --- a/source/zh-CN/getting_started.md +++ b/source/zh-CN/getting_started.md @@ -349,38 +349,38 @@ end ### 第一个表单 -在模板中创建表单,可以使用表单构建器。Rails 中最常用的表单构建器是 `form_for` 辅助方法。让我们使用这个方法,在 `app/views/articles/new.html.erb` 文件中添加下面的代码: +在模板中创建表单,可以使用表单构建器。Rails 中最常用的表单构建器是 `form_with` 辅助方法。让我们使用这个方法,在 `app/views/articles/new.html.erb` 文件中添加下面的代码: ```erb -<%= form_for :article do |f| %> +<%= form_with scope: :article, local: true do |form| %>

- <%= f.label :title %>
- <%= f.text_field :title %> + <%= form.label :title %>
+ <%= form.text_field :title %>

- <%= f.label :text %>
- <%= f.text_area :text %> + <%= form.label :text %>
+ <%= form.text_area :text %>

- <%= f.submit %> + <%= form.submit %>

<% end %> ``` 现在刷新页面,会看到和前文截图一样的表单。在 Rails 中创建表单就是这么简单! -调用 `form_for` 辅助方法时,需要为表单传递一个标识对象作为参数,这里是 `:article` 符号。这个符号告诉 `form_for` 辅助方法表单用于处理哪个对象。在 `form_for` 辅助方法的块中,`f` 表示 `FormBuilder` 对象,用于创建两个标签和两个文本字段,分别用于添加文章的标题和正文。最后在 `f` 对象上调用 `submit` 方法来为表单创建提交按钮。 +调用 `form_with` 辅助方法时,需要为表单传递一个标识作用域作为参数,这里是 `:article` 符号。这个符号告诉 `form_with` 辅助方法表单用于处理哪个对象。在 `form_with` 辅助方法的块中,`form` 表示 `FormBuilder` 对象,用于创建两个标签和两个文本字段,分别用于添加文章的标题和正文。最后在 `form` 对象上调用 `submit` 方法来为表单创建提交按钮。 不过这个表单还有一个问题,查看 HTML 源代码会看到表单 `action` 属性的值是 `/articles/new`,指向的是当前页面,而当前页面只是用于显示新建文章的表单。 -应该把表单指向其他 URL,为此可以使用 `form_for` 辅助方法的 `:url` 选项。在 Rails 中习惯用 `create` 动作来处理提交的表单,因此应该把表单指向这个动作。 +应该把表单指向其他 URL,为此可以使用 `form_with` 辅助方法的 `:url` 选项。在 Rails 中习惯用 `create` 动作来处理提交的表单,因此应该把表单指向这个动作。 -修改 `app/views/articles/new.html.erb` 文件的 `form_for` 这一行,改为: +修改 `app/views/articles/new.html.erb` 文件的 `form_with` 这一行,改为: ```erb -<%= form_for :article, url: articles_path do |f| %> +<%= form_with scope: :article, url: articles_path, local: true do |form| %> ``` 这里我们把 `articles_path` 辅助方法传递给 `:url` 选项。要想知道这个方法有什么用,我们可以回过头看一下 `bin/rails routes` 的输出结果: @@ -407,6 +407,9 @@ edit_article GET /articles/:id/edit(.:format) articles#edit 解决问题的方法是在 `ArticlesController` 中创建 `create` 动作。 +NOTE: 默认情况下,`form_with` 通过 Ajax 提交表单,因此不会做完整的重定向。这是一篇入门指南,为了便于理解,我们使用 `local: true` 禁用了这个行为。 + + ### 创建文章 @@ -685,7 +688,7 @@ class ArticlesController < ApplicationController 接下来在 `app/views/articles/new.html.erb` 文件中添加返回 `index` 动作的链接,把这个链接放在表单之后: ```erb -<%= form_for :article, url: articles_path do |f| %> +<%= form_with scope: :article, url: articles_path, local: true do |form| %> ... <% end %> @@ -766,7 +769,7 @@ private 刷新 ,试着提交一篇没有标题的文章,Rails 会返回这个表单,但这种处理方式没有多大用处,更好的做法是告诉用户哪里出错了。为此需要修改 `app/views/articles/new.html.erb` 文件,添加显示错误信息的代码: ```erb -<%= form_for :article, url: articles_path do |f| %> +<%= form_with scope: :article, url: articles_path, local: true do |form| %> <% if @article.errors.any? %>
@@ -783,17 +786,17 @@ private <% end %>

- <%= f.label :title %>
- <%= f.text_field :title %> + <%= form.label :title %>
+ <%= form.text_field :title %>

- <%= f.label :text %>
- <%= f.text_area :text %> + <%= form.label :text %>
+ <%= form.text_area :text %>

- <%= f.submit %> + <%= form.submit %>

<% end %> @@ -846,7 +849,7 @@ end ```erb

Edit article

-<%= form_for(@article) do |f| %> +<%= form_with(model: @article) do |form| %> <% if @article.errors.any? %>
@@ -863,17 +866,17 @@ end <% end %>

- <%= f.label :title %>
- <%= f.text_field :title %> + <%= form.label :title %>
+ <%= form.text_field :title %>

- <%= f.label :text %>
- <%= f.text_area :text %> + <%= form.label :text %>
+ <%= form.text_area :text %>

- <%= f.submit %> + <%= form.submit %>

<% end %> @@ -887,7 +890,7 @@ end `method: :patch` 选项告诉 Rails 使用 `PATCH` 方法提交表单。根据 REST 协议,`PATCH` 方法是**更新**资源时使用的 HTTP 方法。 -`form_for` 辅助方法的第一个参数可以是对象,例如 `@article`,`form_for` 辅助方法会用这个对象的字段来填充表单。如果传入和实例变量(`@article`)同名的符号(`:article`),也会自动产生相同效果,上面的代码使用的就是符号。关于 `form_for` 辅助方法参数的更多介绍,请参阅 [`form_for` 的文档](http://api.rubyonrails.org/classes/ActionView/Helpers/FormHelper.html#method-i-form_for)。 +`form_with` 辅助方法的参数可以是模型对象,例如 `model: @article`;此时,`form_with` 辅助方法会用这个对象的字段来填充表单。如果传入符号形式的作用域(`scope: :article`),只创建字段,而不填入任何值。关于 `form_with` 辅助方法参数的更多介绍,请参阅[文档](http://api.rubyonrails.org/classes/ActionView/Helpers/FormHelper.html#method-i-form_with)。 接下来在 `app/controllers/articles_controller.rb` 文件中创建 `update` 动作,把这个动作放在 `create` 动作和 `private` 方法之间: @@ -969,7 +972,7 @@ TIP: 关于局部视图的更多介绍,请参阅[Rails 布局和视图渲染]( 新建 `app/views/articles/_form.html.erb` 文件,添加下面的代码: ```erb -<%= form_for @article do |f| %> +<%= form_with model: @article, local: true do |form| %> <% if @article.errors.any? %>
@@ -986,23 +989,23 @@ TIP: 关于局部视图的更多介绍,请参阅[Rails 布局和视图渲染]( <% end %>

- <%= f.label :title %>
- <%= f.text_field :title %> + <%= form.label :title %>
+ <%= form.text_field :title %>

- <%= f.label :text %>
- <%= f.text_area :text %> + <%= form.label :text %>
+ <%= form.text_area :text %>

- <%= f.submit %> + <%= form.submit %>

<% end %> ``` -除了第一行 `form_for` 的用法变了之外,其他代码都和之前一样。之所以能用这个更短、更简单的 `form_for` 声明来代替新建文章页面和编辑文章页面的两个表单,是因为 `@article` 是一个资源,对应于一套 REST 式路由,Rails 能够推断出应该使用哪个地址和方法。关于 `form_for` 用法的更多介绍,请参阅“[面向资源的风格](http://api.rubyonrails.org/classes/ActionView/Helpers/FormHelper.html#method-i-form_for-label-Resource-oriented+style)”。 +除了第一行 `form_with` 的用法变了之外,其他代码都和之前一样。之所以能用这个更短、更简单的 `form_with` 声明来代替新建文章页面和编辑文章页面的两个表单,是因为 `@article` 是一个资源,对应于一套 REST 式路由,Rails 能够推断出应该使用哪个地址和方法。关于 `form_with` 用法的更多介绍,请参阅“[面向资源的风格](http://api.rubyonrails.org/classes/ActionView/Helpers/FormHelper.html#method-i-form_with-label-Resource-oriented+style)”。 现在更新 `app/views/articles/new.html.erb` 视图,以使用新建的局部视图。把文件内容替换为下面的代码: @@ -1295,17 +1298,17 @@ $ bin/rails generate controller Comments

Add a comment:

-<%= form_for([@article, @article.comments.build]) do |f| %> +<%= form_with(model: [ @article, @article.comments.build ], local: true) do |form| %>

- <%= f.label :commenter %>
- <%= f.text_field :commenter %> + <%= form.label :commenter %>
+ <%= form.text_field :commenter %>

- <%= f.label :body %>
- <%= f.text_area :body %> + <%= form.label :body %>
+ <%= form.text_area :body %>

- <%= f.submit %> + <%= form.submit %>

<% end %> @@ -1313,7 +1316,7 @@ $ bin/rails generate controller Comments <%= link_to 'Back', articles_path %> ``` -上面的代码在显示文章的页面中添加了用于新建评论的表单,通过调用 `CommentsController` 的 `create` 动作来发表评论。这里 `form_for` 辅助方法以数组为参数,会创建嵌套路由,例如 `/articles/1/comments`。 +上面的代码在显示文章的页面中添加了用于新建评论的表单,通过调用 `CommentsController` 的 `create` 动作来发表评论。这里 `form_with` 辅助方法以数组为参数,会创建嵌套路由,例如 `/articles/1/comments`。 接下来在 `app/controllers/comments_controller.rb` 文件中添加 `create` 动作: @@ -1363,17 +1366,17 @@ end <% end %>

Add a comment:

-<%= form_for([@article, @article.comments.build]) do |f| %> +<%= form_with(model: [ @article, @article.comments.build ]) do |form| %>

- <%= f.label :commenter %>
- <%= f.text_field :commenter %> + <%= form.label :commenter %>
+ <%= form.text_field :commenter %>

- <%= f.label :body %>
- <%= f.text_area :body %> + <%= form.label :body %>
+ <%= form.text_area :body %>

- <%= f.submit %> + <%= form.submit %>

<% end %> @@ -1426,17 +1429,17 @@ end <%= render @article.comments %>

Add a comment:

-<%= form_for([@article, @article.comments.build]) do |f| %> +<%= form_with(model: [ @article, @article.comments.build ]) do |form| %>

- <%= f.label :commenter %>
- <%= f.text_field :commenter %> + <%= form.label :commenter %>
+ <%= form.text_field :commenter %>

- <%= f.label :body %>
- <%= f.text_area :body %> + <%= form.label :body %>
+ <%= form.text_area :body %>

- <%= f.submit %> + <%= form.submit %>

<% end %> @@ -1453,17 +1456,17 @@ end 我们把添加评论的代码也移到局部视图中。创建 `app/views/comments/_form.html.erb` 文件,添加下面的代码: ```erb -<%= form_for([@article, @article.comments.build]) do |f| %> +<%= form_with(model: [ @article, @article.comments.build ]) do |form| %>

- <%= f.label :commenter %>
- <%= f.text_field :commenter %> + <%= form.label :commenter %>
+ <%= form.text_field :commenter %>

- <%= f.label :body %>
- <%= f.text_area :body %> + <%= form.label :body %>
+ <%= form.text_area :body %>

- <%= f.submit %> + <%= form.submit %>

<% end %> ``` diff --git a/source/zh-CN/initialization.md b/source/zh-CN/initialization.md index 1b742b6..fe87491 100644 --- a/source/zh-CN/initialization.md +++ b/source/zh-CN/initialization.md @@ -97,7 +97,7 @@ require 'bundler/setup' # 设置 Gemfile 中列出的所有 gem * arel * builder * bundler -* erubis +* erubi * i18n * mail * mime-types diff --git a/source/zh-CN/upgrading_ruby_on_rails.md b/source/zh-CN/upgrading_ruby_on_rails.md index 306e93e..3142f80 100644 --- a/source/zh-CN/upgrading_ruby_on_rails.md +++ b/source/zh-CN/upgrading_ruby_on_rails.md @@ -81,7 +81,7 @@ Rails 5.1 的变动参见[发布记](5_1_release_notes.html)。 如果你的应用使用顶层 `HashWithIndifferentAccess` 类,应该逐渐转用 `ActiveSupport::HashWithIndifferentAccess` 类。 -这只是一项温和的弃用,目前代码不受影响,也不看看到提醒,但是以后会删除这个常量。 +这只是一项温和的弃用,目前代码不受影响,也不会看到提醒,但是以后会删除这个常量。 此外,如果 YAML 文档转储中包含这个类的对象,要重新加载并转储,以便引用正确的常量,防止以后无法加载。 @@ -274,6 +274,18 @@ params.permit([:proceed_to, :return_to]).to_h <% # Template Dependency: recordings/threads/events/* %> ``` + + +### `ActionView::Helpers::RecordTagHelper` 移到外部 gem 中(record_tag_helper) + +`content_tag_for` 和 `div_for` 现已移除,统一使用 `content_tag`。如果想继续使用,在 Gemfile 中添加 `record_tag_helper` gem: + +```ruby +gem 'record_tag_helper', '~> 1.0' +``` + +详情参见 [#18411](https://github.com/rails/rails/pull/18411)。 + ### 不再支持 `protected_attributes` gem @@ -415,6 +427,12 @@ config.ssl_options = { hsts: { subdomains: true } } ActiveSupport.to_time_preserves_timezone = false ``` + + +#### JSON/JSONB 序列化的变化 + +Rails 5 改变了 JSON/JSONB 属性的序列化和反序列化方式。现在,如果列与字符串相等,Active Record 不再将字符串转换成散列,而是直接返回字符串。这不仅影响与模型交互的代码,还涉及 `db/schema.rb` 中的 `:default` 列设置。建议不要把列设为与一个字符串相等,而是传递散列,以便自动转换成 JSON 字符串。 + ## 从 Rails 4.1 升级到 4.2 diff --git a/source/zh-CN/working_with_javascript_in_rails.md b/source/zh-CN/working_with_javascript_in_rails.md index b3a249b..a25c8f8 100644 --- a/source/zh-CN/working_with_javascript_in_rails.md +++ b/source/zh-CN/working_with_javascript_in_rails.md @@ -115,7 +115,7 @@ Rails 提供了很多视图辅助方法协助你生成 HTML,如果想在元素 因为使用的是非侵入式 JavaScript,所以 Ajax 相关的辅助方法其实分成两部分,一部分是 JavaScript 代码,一部分是 Ruby 代码。 -如果没有禁用 Asset Pipeline,[rails-ujs](https://github.com/rails/rails-ujs/blob/master/src/rails-ujs.coffee) 负责提供 JavaScript 代码,常规的 Ruby 视图辅助方法负责生成 DOM 标签。 +如果没有禁用 Asset Pipeline,[rails-ujs](https://github.com/rails/rails/tree/master/actionview/app/assets/javascripts) 负责提供 JavaScript 代码,常规的 Ruby 视图辅助方法负责生成 DOM 标签。 应用在处理远程元素的过程中触发的不同事件参见下文。