Randy Girard

Validating uniqueness of nested model on create

I recently ran into the issue where I setup a uniqueness validator on a field, with a scope on the parent’s ID. This was fine for updating with an existing parent, but if I ever created two or more new fields, the validation would fail because there was no ID on the parent model yet for the child to validate against. This is apparently still an open issue with rails, as found by this url: https://rails.lighthouseapp.com/projects/8994/tickets/2160-nested_attributes-validates_uniqueness_of-fails. There is a solution in that link, but I have came up with a similar method, with less code that seems to work fine and passes all my tests. I have also added to my solution the ability to add an error to the individual nested items that duplicate. This is how I fixed this (note that I make a lot of assumptions with code, just showing the example):

class Child < ActiveRecord::Base
  belongs_to :parent

  validates :value, :uniqueness => { :scope => :parent_id }
end

class Parent < ActiveRecord::Base
  has_many :children
  accepted_nested_attributes_for :children

  validate :uniqueness_of_children
 
  private
  
  def uniqueness_of_children
    hash = {}
    
    children.each do |child|
      if hash[child.value]
        # This line is needed to form the parent to error out,
        # otherwise the save would still happen
        if errors[:"children.value"].blank?
          errors.add(:"children.value", "duplicate error")
        end
     
        # This line adds the error to the child to view in your fields_for
        child.errors.add(:value, "has already been taken")
      end
    
      hash[child.value] = true
    end
  end
end

Let me know if you try this out and it works for you, or if it needs any improvements. Thanks!