The project is in a healthy, maintained state
Validates whether associations are uniqueness when using accepts_nested_attributes_for.
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
2025
 Dependencies

Development

>= 7.2.0
>= 3.12.0

Runtime

>= 7.2.0
 Project Readme

Validates Nested Uniqueness

Ruby GitHub release Gem Version License

Validates whether associations are uniqueness when using accepts_nested_attributes_for.

Solves the original Rails issue #20676.

This issue is very annoying and still open after years. And probably this will never be fixed.

This code is based on solutions proposed in the thread. Thanks everyone ❤️.

Installation

rails_validates_nested_uniqueness works with Rails 7.2 onwards.

Add this to your Rails project's Gemfile:

gem 'rails_validates_nested_uniqueness'

Or install directly:

gem install rails_validates_nested_uniqueness

Usage

Making sure that only one city of the country can be named "NY".

class City < ActiveRecord::Base
  belongs_to :country
end

class Country < ActiveRecord::Base
  has_many :cities, dependent: :destroy
  accepts_nested_attributes_for :cities, allow_destroy: true

  validates :cities, nested_uniqueness: {
    attribute: :name,
    scope: [:country_id],
    case_sensitive: false
  }
end

country = Country.new(name: 'US', cities: [City.new(name: 'NY'), City.new(name: 'NY')])
country.save
# => false

country.errors
# => #<ActiveModel::Errors [#<ActiveModel::NestedError attribute=cities.name, type=taken, options={:value=>"NY", :message=>nil}>]>

country.errors.messages
# => {"cities.name"=>["has already been taken"]}

Advanced Usage

Custom Comparison Logic

For more complex validation scenarios, you can provide custom comparison logic:

validates :cities, nested_uniqueness: {
  attribute: :name,
  scope: [:country_id],
  comparison: ->(value) { value.to_s.strip.downcase }
}

This is useful when you need to normalize values before comparison (e.g., trimming whitespace, handling special characters, etc.).

Configuration options:

  • :attribute - (Required) Specify the attribute name of associated model to validate.
  • :scope - One or more columns by which to limit the scope of the uniqueness constraint.
  • :case_sensitive - Looks for an exact match. Ignored by non-text columns (true by default).
  • :message - A custom error message (default is: "has already been taken").
  • :error_key - A custom error key to use (default is: :taken).
  • :comparison - A callable object (Proc/lambda) for custom value comparison logic.

Sponsorship

This library is sponsored by Faria Education Group, where it was originally developed and utilized in a production project. It has been extracted and refined for open-source use.

Contributing

  1. Fork it (https://github.com/mamantoha/validates_nested_uniqueness/fork)
  2. Create your feature branch (git checkout -b my-new-feature)
  3. Commit your changes (git commit -am 'Add some feature')
  4. Push to the branch (git push origin my-new-feature)
  5. Create a new Pull Request

Contributors

  • mamantoha Anton Maminov - creator, maintainer

License

Copyright: 2021-2025 Anton Maminov (anton.maminov@gmail.com)

This library is distributed under the MIT license. Please see the LICENSE file.