Leandro França
Leandro França

Reputation: 2004

Nested form is always inserting a new row after update

I need to associate my parties model to two kind of addresses: main_address and billing_address.

I´m using a has_one/belongs_to association. Everything runs fine on creating a new party.

But every time I update any party, a new row is created on addresses table, instead of just updating the current associated one. I think I´m missing something.

This is what I have now:

Party Model

class Party < ActiveRecord::Base
  has_one :main_address, :class_name => "Address"
  has_one :billing_address, :class_name => "Address"

  accepts_nested_attributes_for :main_address, :allow_destroy => true
  accepts_nested_attributes_for :billing_address, :allow_destroy => true
end

Party DB

create_table "parties", force: :cascade do |t|
    t.string   "name"
    t.datetime "created_at",                        null: false
    t.datetime "updated_at",                        null: false
    t.string   "type"
    t.hstore   "additional_information"
    t.string   "cpf_or_cnpj",            limit: 15
    t.integer  "main_address_id"
    t.integer  "billing_address_id"
  end

Address Model

class Address < ActiveRecord::Base
  belongs_to :party
end

Address DB

  create_table "addresses", force: :cascade do |t|
    t.string   "line1"
    t.string   "line2"
    t.string   "city"
    t.string   "state"
    t.string   "zip"
    t.datetime "created_at"
    t.datetime "updated_at"
    t.integer  "party_id"
  end

On my parties view, I´m using:

<%= simple_form_for @party, :validate => true  do |f| %>
   <div id="main_address">
     <%= f.simple_fields_for :main_address do |main_address| %>
        <%= render "address", :f => main_address %>
      <% end %>
    </div>
<% end %>

Address Partial:

<div class="nested-fields form-inline">
  <%= f.input :zip %>
  <%= f.input :line1 %>
  <%= f.input :line2 %>
  <%= f.input :city %>
  <%= f.input :state %>
</div>

Parties Controller

class PartiesController < ApplicationController

  before_action :set_party, only: [:show, :edit, :update, :destroy]
  before_action :set_type

  def show
  end

  def index
    @parties = type_class.all
  end

  def new
    @party = type_class.new
  end

  def edit
     @party.build_main_address unless @party.main_address.present?
  end

  def create 
      @party = type_class.new(party_params)
      if @party.save
          redirect_to parties_url, notice: (t "#{type}") +" successfully created."
        else
          render action: 'new'
      end
  end

  def update
    if @party.update(party_params )
      redirect_to @party, notice: "#{type} was successfully created."
    else
      render action: 'edit'
    end
  end

private

  def set_type 
     @type = type
  end

  def type 
      Party.types.include?(params[:type]) ? params[:type] : "Party"
  end

  def type_class 
      type.constantize 
  end

  def set_party
    @party = type_class.find(params[:id])
  end

  def party_params   
      params.require(type.underscore.to_sym).permit(:name, :type,:cpf_or_cnpj,main_address_attributes:[:zip,:line1,:line2,:state,:city,:type], contact_informations_attributes: [:id, :_destroy, :type, :label, :info])
  end

end

Upvotes: 1

Views: 327

Answers (1)

Pavan
Pavan

Reputation: 33542

Add :id to main_address_attributes in party_params for the update to work correctly.

def party_params   
  params.require(type.underscore.to_sym).permit(:name, :type,:cpf_or_cnpj,main_address_attributes:[:id, :zip,:line1,:line2,:state,:city,:type], contact_informations_attributes: [:id, :_destroy, :type, :label, :info])
end

Upvotes: 2

Related Questions