I can't seem to get my forms working correctly despite following many guides, tutorials and examples.
I have a model 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
The joining table has an attribute bearing
and the model (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
The form looks like this (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>
Nested form (_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>
I'd like to add latitude
and longitude
for the gateway
association while adding the bearing
to the joining table location_gateway
.
However, my params comes out like this:
{ ... "location_gateways_attributes"=>
{"1593162006925"=>
{
"gateways"=>{"longitude"=>"12.3456", "latitude"=>"13.4567"},
"bearing"=>"123", "_destroy"=>"false"
}
}
}
Why does it become gateways
rather than gateways_attributes
?
I initially misread your code: I thought you created the gateways directly on the has_many :gateways
association. In which case you would be missing the
accepts_nested_attributes_for :gateways
on Location
level.
But after your feedback and looking a bit closer I noticed you correctly followed the associations (you have a double/nested fields_for
), so you have the correct accepts_nested_attributes_for
declared in your models.
However.... in your nested model you write fields_for :gateways
--- BUT since you are now nested in a LocationGateway
that association does not exist there, instead you have to write f.fields_for :gateway
and then it will all work as expected.
So what I said before still stands: That is also why the parameter is called gateways
instead of gateways_attributes
: that is indicative of a missing accepts_nested_attributes_for
. Or more precisely in this case: using the wrong association.
[EDIT] Now we have an link_to_add_association 'Add gateway', f, :location_gateways, partial: 'partials/gateway_fields'
which creates a new LocationGateway
, but not the nested Gateway
. So now you have two options:
link_to_add_association
for :gateway
but this would be confusing for the userLocationGateway
to include the Gateway
and for this last option we can use the cocoon option wrap_object
as follows:
link_to_add_association 'Add gateway', f, :location_gateways,
partial: 'partials/gateway_fields',
wrap_object: Proc.new {|x| x.build_gateway; x }