has_many 通过和值加入 table 与 Cocoon
has_many through and values on the join table with Cocoon
尽管遵循了许多指南、教程和示例,但我似乎无法让我的表单正常工作。
我有一个模型location.rb
:
class Location < ActiveRecord::Base
has_many :location_gateways
has_many :gateways, through: :location_gateways, dependent: :destroy
accepts_nested_attributes_for :location_gateways, reject_if: :all_blank, allow_destroy: true
end
加入 table 有一个属性 bearing
和模型 (location_gateway.rb
):
class LocationGateway < ActiveRecord::Base
belongs_to :location
belongs_to :gateway, dependent: :destroy
accepts_nested_attributes_for :gateway, reject_if: :all_blank, allow_destroy: true
end
表单如下所示 (location/new.html.erb
):
<div id="locations-form">
<%= form_with model: @location do |f| %>
<%= render 'partials/locations_form', f:f %>
<div class="form-group" id="location_gateways">
<b><%= 'Add gateway', f, :location_gateways, partial: 'partials/gateway_fields'%></b>
</div>
<div class="actions">
<%= f.submit nil, :class => "btn btn-primary" %>
</div>
<% end %>
</div>
嵌套形式(_gateway_fields.html.erb
)
<div class="nested-fields" >
<div class="row">
<%= f.fields_for :gateways do |g| %>
<div class="col-md-4" >
<%= g.text_field :longitude, class: 'form-control' %>
</div>
<div class="col-md-4">
<%= g.text_field :latitude, class: 'form-control' %>
</div>
<% end %>
<div class="col-md-2" >
<%= f.text_field :bearing, class: 'form-control gateway-longitude' %>
</div>
<div class="col-md-2">
<%= link_to_remove_association raw(icon_trash), f %>
</div>
</div>
</div>
</div>
我想为 gateway
关联添加 latitude
和 longitude
,同时将 bearing
添加到加入 table location_gateway
.
然而,我的params是这样出来的:
{ ... "location_gateways_attributes"=>
{"1593162006925"=>
{
"gateways"=>{"longitude"=>"12.3456", "latitude"=>"13.4567"},
"bearing"=>"123", "_destroy"=>"false"
}
}
}
为什么变成gateways
而不是gateways_attributes
?
我最初误读了您的代码:我以为您直接在 has_many :gateways
关联上创建了网关。在这种情况下你会错过
accepts_nested_attributes_for :gateways
在 Location
级别。
但是在你的反馈和仔细观察之后,我注意到你正确地遵循了关联(你有一个 double/nested fields_for
),所以你在你的声明中有正确的 accepts_nested_attributes_for
型号。
但是....在你的嵌套模型中你写 fields_for :gateways
--- 但是因为你现在嵌套在一个 LocationGateway
中那个关联不存在,你必须写 f.fields_for :gateway
然后一切都会按预期工作。
所以我之前说的仍然成立:这也是参数被称为 gateways
而不是 gateways_attributes
的原因:这表明缺少 accepts_nested_attributes_for
。或者更准确地说,在这种情况下:使用了错误的关联。
[编辑] 现在我们有一个 link_to_add_association 'Add gateway', f, :location_gateways, partial: 'partials/gateway_fields'
创建一个新的 LocationGateway
,但是 不是 嵌套的 Gateway
。所以现在你有两个选择:
- 为
:gateway
添加第二个 link_to_add_association
,但这会使用户感到困惑
- 直接初始化
LocationGateway
以包含 Gateway
对于最后一个选项,我们可以使用 cocoon 选项 wrap_object
,如下所示:
link_to_add_association 'Add gateway', f, :location_gateways,
partial: 'partials/gateway_fields',
wrap_object: Proc.new {|x| x.build_gateway; x }
这绝不是一个干净的答案,但如果我将参数的字段更改为此(请注意网关的非复数版本),我就可以使用它了:
<%= f.fields_for :gateway_attributes do |g| %>
有了这个“解决方案”,位置模型就不需要 accepts_nested_attributes_for :gateways
。
尽管遵循了许多指南、教程和示例,但我似乎无法让我的表单正常工作。
我有一个模型location.rb
:
class Location < ActiveRecord::Base
has_many :location_gateways
has_many :gateways, through: :location_gateways, dependent: :destroy
accepts_nested_attributes_for :location_gateways, reject_if: :all_blank, allow_destroy: true
end
加入 table 有一个属性 bearing
和模型 (location_gateway.rb
):
class LocationGateway < ActiveRecord::Base
belongs_to :location
belongs_to :gateway, dependent: :destroy
accepts_nested_attributes_for :gateway, reject_if: :all_blank, allow_destroy: true
end
表单如下所示 (location/new.html.erb
):
<div id="locations-form">
<%= form_with model: @location do |f| %>
<%= render 'partials/locations_form', f:f %>
<div class="form-group" id="location_gateways">
<b><%= 'Add gateway', f, :location_gateways, partial: 'partials/gateway_fields'%></b>
</div>
<div class="actions">
<%= f.submit nil, :class => "btn btn-primary" %>
</div>
<% end %>
</div>
嵌套形式(_gateway_fields.html.erb
)
<div class="nested-fields" >
<div class="row">
<%= f.fields_for :gateways do |g| %>
<div class="col-md-4" >
<%= g.text_field :longitude, class: 'form-control' %>
</div>
<div class="col-md-4">
<%= g.text_field :latitude, class: 'form-control' %>
</div>
<% end %>
<div class="col-md-2" >
<%= f.text_field :bearing, class: 'form-control gateway-longitude' %>
</div>
<div class="col-md-2">
<%= link_to_remove_association raw(icon_trash), f %>
</div>
</div>
</div>
</div>
我想为 gateway
关联添加 latitude
和 longitude
,同时将 bearing
添加到加入 table location_gateway
.
然而,我的params是这样出来的:
{ ... "location_gateways_attributes"=>
{"1593162006925"=>
{
"gateways"=>{"longitude"=>"12.3456", "latitude"=>"13.4567"},
"bearing"=>"123", "_destroy"=>"false"
}
}
}
为什么变成gateways
而不是gateways_attributes
?
我最初误读了您的代码:我以为您直接在 has_many :gateways
关联上创建了网关。在这种情况下你会错过
accepts_nested_attributes_for :gateways
在 Location
级别。
但是在你的反馈和仔细观察之后,我注意到你正确地遵循了关联(你有一个 double/nested fields_for
),所以你在你的声明中有正确的 accepts_nested_attributes_for
型号。
但是....在你的嵌套模型中你写 fields_for :gateways
--- 但是因为你现在嵌套在一个 LocationGateway
中那个关联不存在,你必须写 f.fields_for :gateway
然后一切都会按预期工作。
所以我之前说的仍然成立:这也是参数被称为 gateways
而不是 gateways_attributes
的原因:这表明缺少 accepts_nested_attributes_for
。或者更准确地说,在这种情况下:使用了错误的关联。
[编辑] 现在我们有一个 link_to_add_association 'Add gateway', f, :location_gateways, partial: 'partials/gateway_fields'
创建一个新的 LocationGateway
,但是 不是 嵌套的 Gateway
。所以现在你有两个选择:
- 为
:gateway
添加第二个link_to_add_association
,但这会使用户感到困惑 - 直接初始化
LocationGateway
以包含Gateway
对于最后一个选项,我们可以使用 cocoon 选项 wrap_object
,如下所示:
link_to_add_association 'Add gateway', f, :location_gateways,
partial: 'partials/gateway_fields',
wrap_object: Proc.new {|x| x.build_gateway; x }
这绝不是一个干净的答案,但如果我将参数的字段更改为此(请注意网关的非复数版本),我就可以使用它了:
<%= f.fields_for :gateway_attributes do |g| %>
有了这个“解决方案”,位置模型就不需要 accepts_nested_attributes_for :gateways
。