`validates_uniqueness_of` and `accepts_nested_attributes_for` only validates existing records #4568

sethvargo opened this Issue Jan 21, 2012 · 27 comments


None yet

If I have a nested model, such as:

class Contact < ActiveRecord::Base
  belongs_to :group

  validates_uniqueness_of :phone, :scope => [:group_id]
class Group < ActiveRecord::Base
  has_many :contacts

  accepts_nested_attributes_for :contacts

The uniqueness validator only applies to existing records in the database... If I submit the same duplicate record as a nested attribute:

  "group"  => {
    "name" => "Blah",
    "description" => "Foot",
    "contacts_attributes" => {
      "0" => {
        "id" => "5",
        "name" => "Seth Vargo",
        "1" => {
          "id" => "6",
          "name" => "Person B",
        "2" => {
          "name" => "Person C",
          "phone" => "1234567890"

It will add all those records, even though the phone is supposed to be unique...


Looks like a duplicate of #1572 . that may help you know whats happening.


Okay, but that doesn't actually specify a solution...

frodsan commented Apr 30, 2012

This is currently an active issue:

> g = Group.new(name: "Blah", description: "Foot")
=> #<Group id: nil, name: "Blah", description: "Foot", created_at: nil, updated_at: nil>

> g.contacts_attributes = [ { name: "Seth Vargo", phone: "1234567890"}, { name: "Person B", phone: "1234567890" } ]
=> [{:name=>"Seth Vargo", :phone=>"1234567890"}, {:name=>"Person B", :phone=>"1234567890"}]

> g.save!
> g.contacts
=> [#<Contact id: 3, name: "Seth Vargo", phone: "1234567890", group_id: 2>, #<Contact id: 4, name: "Person B", phone: "1234567890", group_id: 2>]






Backoo commented Nov 12, 2012

+1 ! ! !

mrwade commented Nov 12, 2012



Still present in Rails 3.2.8, +1


Here's the hacked solution I came up with, that allowed me to put the error on the failed attribute itself, and not on the base of the parent object as the solution floating around here suggests: http://stackoverflow.com/questions/2772236/validates-uniqueness-of-in-nested-model-rails#answers-header

class Event < ActiveRecord::Base
  has_many :vendors, dependent: :destroy
  before_validation do
    vendors.map do |e| 
      stream_ids = vendors.collect(&:audio_stream_id).compact
      stream_ids_counted = stream_ids.inject({}) { |hash,stream_id| hash[stream_id] = (hash[stream_id] || 0) + 1; hash }
      duplicate_stream_ids = stream_ids_counted.select { |k,v| v > 1 }.keys
      e.instance_variable_set "@duplicate_stream_ids", duplicate_stream_ids
class Vendor < ActiveRecord::Base
  belongs_to :event
  validate :ensure_unique_audio_stream_per_event

   def ensure_unique_audio_stream_per_event
      errors.add(:audio_stream_id, "taken") if @duplicate_stream_ids.present? and @duplicate_stream_ids.include?(audio_stream_id)

So, in usage:

@event = Event.first
@event.vendors << Vendor.new(audio_stream_id: 1)
@event.vendors << Vendor.new(audio_stream_id: 1)
@event.valid? #false
@event.full_messages # the :audio_stream_id attribute in the corresponding Vendor record is marked, so Formtastic & others displays the message nicely
jeyb commented Nov 26, 2012

I opened a pull request with a fix for this bug, take a look. Let me know if you have suggestions or comments.

mshappe commented Feb 25, 2013


Wangjohn's pull request #9364 looks like it goes a long way toward fixing this issue, but nobody has even commented on it yet.

sharp commented Jul 25, 2013

Same problem :)





xamut commented Aug 16, 2013


@Empact Empact added a commit to Empact/rails that referenced this issue Nov 21, 2013
@Empact Empact Simplify and improve jeyb and wangjohn's implementation of associatio…
…n uniqueness validation. Fixes #4568.

Remove the validation context-related changes because they were
removed from mainline in 75135a9



Hi guys!

I think it's not worth adding support for this case. It's going to change a lot of code just for a 'partial' fix. I mean partial, because it may not have database constraints.

Some information about this can be found here.





I agree with @laurocaetano. This is a partial fix that demands a lot of code.

The proper fix, as documented is to use database constraints.





QBD commented Apr 12, 2014

+1 seems to be an issue still in rails 4 (unless there's some easy solution that I have overlooked)

alagu commented May 17, 2014

+1 still seems to be happening to me.




@alagu @rderoldan1 : Please read Rafael's answer, this is not easily fixable so this issue has been marked as closed but the problem remains.

@matthewd matthewd locked and limited conversation to collaborators Oct 1, 2014
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.