ruby-on-railsnested-formsvalidates-uniqueness-of

validates_uniqueness_of in destroyed nested model rails


I have a Project model which accepts nested attributes for Task.

class Project < ActiveRecord::Base  
  has_many :tasks
  accepts_nested_attributes_for :tasks, :allow_destroy => :true
end

class Task < ActiveRecord::Base  
  validates_uniqueness_of :name
end

Uniqueness validation in Task model gives problem while updating Project.

In edit of project i delete a task T1 and then add a new task with same name T1, uniqueness validation restricts the saving of Project.

params hash look something like

task_attributes => { {"id" =>
"1","name" => "T1", "_destroy" =>
"1"},{"name" => "T1"}}

Validation on task is done before destroying the old task. Hence validation fails.Any idea how to validate such that it doesn't consider task to be destroyed?


Solution

  • Andrew France created a patch in this thread, where the validation is done in memory.

    class Author
      has_many :books
    
      # Could easily be made a validation-style class method of course
      validate :validate_unique_books
    
      def validate_unique_books
        validate_uniqueness_of_in_memory(
          books, [:title, :isbn], 'Duplicate book.')
      end
    end
    
    module ActiveRecord
      class Base
        # Validate that the the objects in +collection+ are unique
        # when compared against all their non-blank +attrs+. If not
        # add +message+ to the base errors.
        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_to_base(message)
          end
        end
      end
    end