【发布时间】:2021-04-16 21:49:01
【问题描述】:
我有一些accepts_nested_attributes_for的模型
class SomeModel < ApplicationRecord
has_many :some_resources
accepts_nested_attributes_for :some_resources, allow_destroy: true
...
在 View 中看起来是这样的
<%= form_with(model: @some_model, ...) do |form| %>
...
<%= form.fields_for :some_resources do |some_resource_form| %>
<table>
<tbody>
<%= some_resource_form.hidden_field :_destroy, value: '0' %>
<tr>
<th>
<%= some_resource_form.label :some_field_1, 'Some field 1' %>
</th>
<td>
<%= some_resource_form.text_field :some_field_1 %>
</td>
</tr>
<tr>
<th>
<%= some_resource_form.label :some_field_2, 'Some field 2' %>
</th>
<td>
<%= some_resource_form.text_field :some_field_2 %>
</td>
</tr>
</tbody>
</table>
<% end %>
...
<% end %>
在控制器中
def new
3.times do |i|
@some_model.some_resources.build
end
end
配置
...
config.active_record.index_nested_attribute_errors = true
绘制页面时是这样的
<table>
<tbody>
<input value="0" type="hidden" name="some_model[some_resources_attributes][0][_destroy]" id="some_model_some_resources_attributes_0__destroy">
<tr>
<th>
<label for="some_model_some_resources_attributes_0_some_field_1">Some field 1</label>
</th>
<td>
<input type="text" name="some_model[some_resources_attributes][0][some_field_1]" id="some_model_some_resources_attributes_0_some_field_1">
</td>
</tr>
<tr>
<th><label for="some_model_some_resources_attributes_0_some_field_2">Some field 2</label></th>
<td>
<input type="text" name="some_model[some_resources_attributes][0][some_field_2]" id="some_model_some_resources_attributes_0_some_field_2">
</td>
</tr>
</tbody>
</table>
<table>
<tbody>
<input value="0" type="hidden" name="some_model[some_resources_attributes][1][_destroy]" id="some_model_some_resources_attributes_1__destroy">
<tr>
<th>
<label for="some_model_some_resources_attributes_1_some_field_1">Some field 1</label>
</th>
<td>
<input type="text" name="some_model[some_resources_attributes][1][some_field_1]" id="some_model_some_resources_attributes_1_some_field_1">
</td>
</tr>
<tr>
<th><label for="some_model_some_resources_attributes_1_some_field_2">Some field 2</label></th>
<td>
<input type="text" name="some_model[some_resources_attributes][1][some_field_2]" id="some_model_some_resources_attributes_1_some_field_2">
</td>
</tr>
</tbody>
</table>
<table>
<tbody>
<input value="0" type="hidden" name="some_model[some_resources_attributes][2][_destroy]" id="some_model_some_resources_attributes_2__destroy">
<tr>
<th>
<label for="some_model_some_resources_attributes_2_some_field_1">Some field 1</label>
</th>
<td>
<input type="text" name="some_model[some_resources_attributes][2][some_field_1]" id="some_model_some_resources_attributes_2_some_field_1">
</td>
</tr>
<tr>
<th><label for="some_model_some_resources_attributes_2_some_field_2">Some field 2</label></th>
<td>
<input type="text" name="some_model[some_resources_attributes][2][some_field_2]" id="some_model_some_resources_attributes_2_some_field_2">
</td>
</tr>
</tbody>
</table>
存在使用_destroy 属性仅创建选定对象的能力。
触发验证时,errors 具有以下结构
#<ActiveModel::Errors:0x00007f4f695a5720 @base=#<SomeModel id: nil, label: "Label", ..., created_at: nil, updated_at: nil, deleted_at: nil>,
@messages={
:"some_resources[0].some_field_1"=>["can't be empty"], :"some_resources[0].some_field_2"=>["can't be empty"],
:"some_resources[1].some_field_1"=>["can't be empty"], :"some_resources[1].some_field_2"=>["can't be empty"],
:"some_resources[2].some_field_1"=>["can't be empty"], :"some_resources[2].some_field_2"=>["can't be empty"]
},
@details={
:"some_resources[0].some_field_1"=>[{:error=>:blank}], :"some_resources[0].some_field_2"=>[{:error=>:blank}],
:"some_resources[1].some_field_1"=>[{:error=>:blank}], :"some_resources[1].some_field_2"=>[{:error=>:blank}],
:"some_resources[2].some_field_1"=>[{:error=>:blank}], :"some_resources[2].some_field_2"=>[{:error=>:blank}]
}>
例如,当我不想保存第二个对象(带有字段name="some_model[some_resources_attributes][1][some_field_1]")时,就会出现问题。为此,我为参数_destroy 设置了值“1”。之后,errors 包含以下内容
#<ActiveModel::Errors:0x00007f4f627d4d18 @base=#<SomeModel id: nil, label: "Label", ..., created_at: nil, updated_at: nil, deleted_at: nil>,
@messages={
:"some_resources[0].some_field_1"=>["can't be empty"], :"some_resources[0].some_field_2"=>["can't be empty"],
:"some_resources[1].some_field_1"=>["can't be empty"], :"some_resources[1].some_field_2"=>["can't be empty"]
},
@details={
:"some_resources[0].some_field_1"=>[{:error=>:blank}], :"some_resources[0].some_field_2"=>[{:error=>:blank}],
:"some_resources[1].some_field_1"=>[{:error=>:blank}], :"some_resources[1].some_field_2"=>[{:error=>:blank}]
}>
可以看出,嵌套属性的错误只包含errors中对象的序号。
因此场
name="some_model[some_resources_attributes][0][some_field_1]" 错误索引为 0
错误中缺少name="some_model[some_resources_attributes][1][some_field_1]"
name="some_model[some_resources_attributes][2][some_field_1]" 错误索引为 1
由于这种行为不可能在正确的字段中绘制错误消息。 我认为这个问题很普遍。但我什么也没找到。是否有任何解决方案以及存在哪些更好的实践来实现这样的功能? 谢谢!
附:我使用 Rails 6.0.3.6
【问题讨论】:
标签: ruby-on-rails validation nested-attributes