Skip to content

Instantly share code, notes, and snippets.

@jessevdp
Created September 5, 2025 04:40
Show Gist options
  • Select an option

  • Save jessevdp/12bc703048e7cf8ec8b0ba3e7728bc31 to your computer and use it in GitHub Desktop.

Select an option

Save jessevdp/12bc703048e7cf8ec8b0ba3e7728bc31 to your computer and use it in GitHub Desktop.
StoreModel array unique validation
class MyModel
attribute :my_array_of_store_models, MyStoreModel.to_array_type, default: -> { [] }
validates :my_array_of_store_models,
store_model: true,
"store_model_validators/unique": { attrs: [:name] }
end
class MyStoreModel
include StoreModel::Model
attribute :name, :string
validates :name, presence: true
end
class StoreModelValidatators::UniqueValidator < ActiveModel::EachValidator
def validate_each(record, attribute, value)
options[:attrs].each do |validated_attribute|
AttributeUniqueValidatorInstance.new(
record:,
collection_attribute: attribute,
collection: value,
attribute: validated_attribute
).validate
end
end
class AttributeUniqueValidatorInstance
def initialize(record:, collection_attribute:, collection:, attribute:)
@record = record
@collection_attribute = collection_attribute
@collection = collection
@attribute = attribute
end
def validate
add_duplicate_error if duplicate_attribute_values.any?
end
private
def duplicate_attribute_values
all_attribute_values
.select { |value| all_attribute_values.count(value) > 1 }
.uniq
end
def all_attribute_values = @collection.pluck(@attribute)
def add_duplicate_error
message = "can't contain duplicate #{@attribute}s (duplicates: #{duplicate_attribute_values.join(', ')})"
@record.errors.add(@collection_attribute, error_type, message:)
end
def error_type = :"duplicate_#{@attribute}"
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment