Class: ActiveItem::UniquenessValidator
- Inherits:
-
ActiveModel::EachValidator
- Object
- ActiveModel::EachValidator
- ActiveItem::UniquenessValidator
- Defined in:
- lib/active_item/validations.rb
Overview
ActiveModel validator that checks attribute uniqueness by querying DynamoDB, with optional scope and custom condition support.
IMPORTANT LIMITATIONS:
-
TOCTOU race condition: DynamoDB is eventually consistent, so a check-then-write cannot guarantee uniqueness under concurrent writes. For strong uniqueness, use a DynamoDB conditional put (attribute_not_exists) at the persistence layer instead.
-
DoS vector: without an index, uniqueness checks fall back to table scans. Always ensure validated attributes have a GSI to avoid full-table scans on write paths.
Instance Method Summary collapse
Instance Method Details
#validate_each(record, attribute, value) ⇒ Object
16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 |
# File 'lib/active_item/validations.rb', line 16 def validate_each(record, attribute, value) return if value.nil? || value.to_s.empty? conditions = { attribute => value } if [:scope] Array([:scope]).each do |scope_attr| conditions[scope_attr] = record.send(scope_attr) end end relation = record.class.where(**conditions) if [:conditions] # Custom conditions require loading records for Ruby-side filtering existing = relation.to_a existing = existing.reject { |r| r.id == record.id } if record.id existing = existing.select { |r| [:conditions].call(r) } taken = existing.any? elsif record.id # Need to exclude current record — fetch up to 2 (current + one other) existing = relation.limit(2).to_a taken = existing.any? { |r| r.id != record.id } else # New record — just check if any match exists taken = !relation.first.nil? end record.errors.add(attribute, [:message] || 'has already been taken') if taken end |