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 关联添加 latitudelongitude,同时将 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 :gatewaysLocation 级别。

但是在你的反馈和仔细观察之后,我注意到你正确地遵循了关联(你有一个 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