how to avoid saving empty records on a nested rails form

Chris Beck picture Chris Beck · Jul 15, 2012 · Viewed 9.6k times · Source

I'm using the nested_form gem for my AddressBook relation. When the user blanks out the value of an existing Addr, I want to delete that Addr rather than saving with a blank value

class Person < ActiveRecord::Base
  has_many :addrs, dependent: :destroy
  attr_accessible :name, :addrs_attributes
  accepts_nested_attributes_for :addrs, reject_if: :addr_blank, allow_destroy: true

  def addr_blank(a)
    valid? && a[:id].blank? && a[:value].blank? 
  end

class Addr < ActiveRecord::Base
  belongs_to :person
  attr_accessible :kind, :label, :value, :person_id

My :reject_if method works well but it doesn't give me everything I need

  1. valid? keeps my blank Addrs around through validation
  2. a[:id].blank? avoids rejections when the user blanks out and existing record

Now, I need to delete (rather than save) an existing Addr when the user blanks the value. Also, I'm exposing Persons and Addrs via a RESTful API. I see two possible options:

  1. Post process the params hash to add the magical _destroy=1 param. IOW, emulate the user activity of pressing the delete button.
  2. Encapsulate this inside the Addr model such that an update with a blank value is effectively considered a delete.

Based on the advice here is how I implemented it:

people_controller.rb

def update
  @person = Person.find(params[:id])
  @person.destroy_blank_addrs(params[:person])
  respond_to do |format|
  ...

person.rb

def destroy_blank_addrs(person_params)
  if valid? && person_params[:addrs_attributes]
    person_params[:addrs_attributes].each do |addr_params_array|
      addr_params= addr_params_array[1] 
      addr_params[:_destroy] = '1' if !addr_params[:id].blank? && addr_params[:value].blank? 
    end
  end
end

Answer

Shimaa Marzouk picture Shimaa Marzouk · Jul 21, 2014
accepts_nested_attributes_for :addrs, 
  allow_destroy: true, 
  :reject_if => proc { |att| att[:name].blank? && attr[:description].blank? }