No release in over 3 years
Low commit activity in last 3 years
Guarantee uniqueness of a single attribute across one or more children of an ActiveRecord object Works around https://github.com/rails/rails/issues/4568
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
 Dependencies

Development

= 2.0.2
~> 10.4
~> 3.0
~> 0.51

Runtime

< 5.2.0, >= 3.2.0
< 5.2.0, >= 3.2.0
< 5.2.0, >= 3.2.0
 Project Readme

activerecord-validate_unique_child_attribute

Guarantee uniqueness of a single attribute value across one or more children of an ActiveRecord object

A simplistic but functional workaround for rails/rails#4568

Usage

Install the gem:

gem 'activerecord-validate_unique_child_attribute',
  require: 'active_record/validate_unique_child_attribute'

Add the functionality to your ActiveRecord class:

class MyParentRecord < ActiveRecord::Base
  include ActiveRecord::ValidateUniqueChildAttribute

  has_many :children
  accepts_nested_attributes_for :children

  # Add an error to the MyParentRecord object whenever two or
  # more children have the same value of some_attribute
  validates_uniqueness_of_child_attribute :children, :some_attribute
end

But wait, Rails already does this!

Yeah, in theory it does.

However, if you use accepts_nested_attributes_for in your parent class then the validates_uniqueness_of validations in your child class will only be triggered for existing records. This means that nested attributes in a standard controller #create method will only fail at the DB constraint level, which often results in a very ugly error experience for the end user.

This is a long-standing Rails bug that is not expected to be fixed any time soon.

Additional Options

validates_uniqueness_of_child_attribute :children, :some_attribute,
  validate: true, error_formatter: :my_error_formatter
  
def my_error_formatter(attribute, duplicates)
  "Oh no! Duplicate #{attribute.singularize.humanize} values: #{duplicates.join(', ')}"
end
  • validate: Whether to call valid? on each of the children before looking for duplicate values of some_attribute. This is useful if your before_validation code munges the value of some_attribute by stripping, downcasing, or otherwise normalizing its value.
  • error_formatter: A method for formatting the error message that is attached to the parent record's errors[:children] array. A default formatter is provided. Alternatively you can pass a block to the validates_uniqueness_of_child_attribute class method:
  validates_uniqueness_of_child_attribute :children, :some_attribute do |attribute, duplicates|
    "Oh no! Duplicate #{attribute.singularize.humanize} values: #{duplicates.join(', ')}"
  end

Contributing

This is a really simple implementation! Please open a pull request if you've got ideas on how to improve it.

Compatibility

Tested with active* versions 3.2.22.5, 4.0.13, 4.1.12, 4.2.10, 5.0.0.1, 5.1.4, and 5.2.3. See Appraisals.

Code Status

Build Status

License

This gem is released under the MIT License