0
votes

Rails is creating a parent object and it's children correctly and inserting new records into the database for each, but then it is deleting the children. The parent object is itself a child of another already created object. Here are models:

class Pool < ActiveRecord::Base
 has_many :addresses, dependent: :destroy

 accepts_nested_attributes_for :addresses, allow_destroy: true
end

class Address < ActiveRecord::Base
  belongs_to :pool
  has_one :ipv4, dependent: :destroy
  has_one :ipv6, dependent: :destroy
  has_one :mac_address, dependent: :destroy

  accepts_nested_attributes_for :ipv4, :ipv6, :mac_address
end

class Ipv4 < ActiveRecord::Base
end

Here's the controller

class AddressesController < ApplicationController
  def index
  end

  def create
    @pool = Pool.find(params[:pool_id])
    @address = @pool.addresses.create(addresses_params)
    #Maybe not needed here?
    ipv4 = @address.build_ipv4
    ipv6 = @address.build_ipv6
    mac_address = @address.build_mac_address
    redirect_to pool_path(@pool)
  end

  def destroy
    @pool = Pool.find(params[:pool_id])
    @address = @pool.addresses.find(params[:id])
    @address.destroy
    redirect_to pool_path(@pool)
  end

  private
    def addresses_params
      params.require(:address).permit(:name, :notes, :hostname, :device_description, :id, :ipv4_attribute
s => [:octet_1, :octet_2, :octet_3, :octet_4, :id], :ipv6_attributes => [:group_1, :group_2, :group_3, :g
roup_4, :group_5, :group_6, :group_7, :group_8, :id], :mac_address_attributes => [:octet_1, :octet_2, :oc
tet_3, :octet_4, :octet_5, :octet_6, :id])
    end
end

Here's the form:

<%= form_for @address, url:  pool_addresses_path(@address.pool) do |f| %>
<div class="field">
  <%= f.fields_for :ipv4 do |ipv4_fields| %>
     <%= label_tag :ipv4, 'IPv4' %>:
     <%= render 'ipv4', :f => ipv4_fields %>
  <% end %>
</div>

<div class="field">
  <%= f.fields_for :ipv6 do |ipv6_fields| %>
     <%= label_tag :ipv6, 'IPv6' %>:
     <%= render 'ipv6', :f => ipv6_fields %>
  <% end %>
</div>

<div class="field">
  <%= f.fields_for :mac_address do |mac_fields| %>
     <%= label_tag :mac_address, 'MAC' %>:
     <%= render 'mac', :f => mac_fields %>
  <% end %>
</div>

<div class="field">
  <%= f.label :hostname %>:
  <%= f.text_field :hostname %>
</div>

<div class="field">
  <%= f.label :device_description %>:
  <%= f.text_field :device_description %>
</div>

<div class="field">
  <%= f.label :notes %><br>
  <%= f.text_area :notes %>
</div>

<div class="actions">
  <%= f.submit %>
</div>
<% end %>

And this is what I see in the development log when I hit the submit button:

Started POST "/pools/11/addresses" for 192.168.46.1 at 2014-06-12 13:28:16 -0700
Processing by AddressesController#create as HTML
  Parameters: {"utf8"=>"â", "authenticity_token"=>"pnWjd4/Tu8pjZL7PWttvHXmV3SDWPcx4JrSkB50ccws=", "address"=>{"ipv4_attributes"=>{"octet_1"=>"23", "octet_2"=>"", "octet_3"=>"", "octet_4"=>""}, "ipv6_attributes"=>{"group_1"=>"44", "group_2"=>"", "group_3"=>"", "group_4"=>"", "group_5"=>"", "group_6"=>"", "group_7"=>"", "group_8"=>""}, "mac_address_attributes"=>{"octet_1"=>"22", "octet_2"=>"", "octet_3"=>"", "octet_4"=>"", "octet_5"=>"", "octet_6"=>""}, "hostname"=>"cornery", "device_description"=>"peeler", "notes"=>"address notes"}, "commit"=>"Create Address", "pool_id"=>"11"}
  Pool Load (0.2ms)  SELECT  "pools".* FROM "pools"  WHERE "pools"."id" = ? LIMIT 1  [["id", 11]]
   (0.1ms)  begin transaction
  SQL (0.5ms)  INSERT INTO "addresses" ("created_at", "device_description", "hostname", "notes", "pool_id", "updated_at") VALUES (?, ?, ?, ?, ?, ?)  [["created_at", "2014-06-12 20:28:16.554014"], ["device_description", "peeler"], ["hostname", "cornery"], ["notes", "address notes"], ["pool_id", 11], ["updated_at", "2014-06-12 20:28:16.554014"]]
  SQL (0.2ms)  INSERT INTO "ipv4s" ("address_id", "created_at", "octet_1", "octet_2", "octet_3", "octet_4", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?)  [["address_id", 13], ["created_at", "2014-06-12 20:28:16.556819"], ["octet_1", "23"], ["octet_2", ""], ["octet_3", ""], ["octet_4", ""], ["updated_at", "2014-06-12 20:28:16.556819"]]
  SQL (0.2ms)  INSERT INTO "ipv6s" ("address_id", "created_at", "group_1", "group_2", "group_3", "group_4", "group_5", "group_6", "group_7", "group_8", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)  [["address_id", 13], ["created_at", "2014-06-12 20:28:16.559416"], ["group_1", "44"], ["group_2", ""], ["group_3", ""], ["group_4", ""], ["group_5", ""], ["group_6", ""], ["group_7", ""], ["group_8", ""], ["updated_at", "2014-06-12 20:28:16.559416"]]
  SQL (0.2ms)  INSERT INTO "mac_addresses" ("address_id", "created_at", "octet_1", "octet_2", "octet_3", "octet_4", "octet_5", "octet_6", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)  [["address_id", 13], ["created_at", "2014-06-12 20:28:16.562105"], ["octet_1", "22"], ["octet_2", ""], ["octet_3", ""], ["octet_4", ""], ["octet_5", ""], ["octet_6", ""], ["updated_at", "2014-06-12 20:28:16.562105"]]
   (7.0ms)  commit transaction
   (0.0ms)  begin transaction
  SQL (0.2ms)  DELETE FROM "ipv4s" WHERE "ipv4s"."id" = ?  [["id", 15]]
   (13.0ms)  commit transaction
   (0.1ms)  begin transaction
  SQL (0.2ms)  DELETE FROM "ipv6s" WHERE "ipv6s"."id" = ?  [["id", 15]]
   (9.0ms)  commit transaction
   (0.1ms)  begin transaction
  SQL (0.2ms)  DELETE FROM "mac_addresses" WHERE "mac_addresses"."id" = ?  [["id", 15]]
   (8.7ms)  commit transaction
Redirected to http://192.168.46.137:3000/pools/11
Completed 302 Found in 82ms (ActiveRecord: 53.1ms)

There is no error except the undefined method octet_1' for nil:NilClass error when Rails redirects to the Pool controller's show method because there's nothing there because Rails deleted all of the Address object's children!

Any clues what's going on here?

Thanks!

1
Also: if I create a new Pool object with an Address and it's associated children (IPv4 etc.) through the Pools controller then everything is fine - the Address' children are inserted into their respective tables and stay there. This is only happening when I attempt to add an Address and it's children to an existing Pool object through the Addresses controller.jacoulter

1 Answers

0
votes

Found the clue here: nested attributes works for create but fails when update a record [resolved]

I removed the build actions from the AddressesController create action:

class AddressesController < ApplicationController
  def index
  end

  def create
    @pool = Pool.find(params[:pool_id])
    @address = @pool.addresses.create(addresses_params)
    #Maybe not needed here?
    #ipv4 = @address.build_ipv4
    #ipv6 = @address.build_ipv6
    #mac_address = @address.create_mac_address
    redirect_to pool_path(@pool)
  end
end

I added the build actions because the form wasn't displaying the fields for the children objects. They're there now, so I think @address = @pool.addresses.create(addresses_params) is creating them?