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

Posted By Weston Ganger

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:

### 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:

Article Topic:Software Development - Ruby / Rails

Date:October 07, 2015