Rails

Validating Uniqueness Of Field(s) In Accepts_nested_attributes_for Accounting For Those Marked For Destruction

Posted by Weston Ganger on October 07, 2015

Sometimes you have a dynamic form that uses accepts_nested_attributes_for with uniqueness validations in the nested models. This can cause problems for uniqueness validation.

For example: You have unique numbers for each. You have an existing 1, 2, 3. You delete/mark number 3 for destruction. You then add a new one which now has the number three. If you just use default validation for this it will complain about the new one saying that number has already been taken. This is because the validations are done before the deletion.

You need to validate them in memory. Heres how:


class Parent < ActiveRecord::Base
  has_many :children
  accept_nested_attributes_for :children, reject_if: :all_blank, allow_destroy: true

  validate :validate_unique_connection_numbers
  def validate_unique_connection_numbers
    #the second argument is an array so it can take multiple fields
    validate_uniqueness_of_in_memory(children, [:number], 'Child already exists with that number')
  end
end

### config/initializers/validates_uniqueness_in_memory.rb - could probably be in app/validations/ instead
module ActiveRecord
  class Base
    def validate_uniqueness_of_in_memory(collection, attrs, message)
      hashes = collection.inject({}) do |hash, record|
        key = attrs.map {|a| record.send(a).to_s }.join
        if key.blank? || record.marked_for_destruction?
          key = record.object_id
        end
        hash[key] = record unless hash[key]
        hash
      end
      if collection.length > hashes.length
        self.errors.add(:base, message)
      end
    end
  end
end

Now it will be verified in memory taking into account the ones marked for deletion.

**Note: This is written for Rails 3.2. I heard somewhere this was changed in Rails 4 but I dont know if that is true.

**Credits: Andrew France originally wrote this for Rails 2. Thanks bud!


Related External Links:


Posted in Rails and Tagged with rails accepts_nested_attributes_for nested-forms forms 


Need help on your next project or application?

I specialize in Ruby-on-Rails, AngularJS, Javascript, Bootstrap, and Hybrid Mobile Apps with Cordova & Ionic.

Contact Me

Recommended Posts