Class: Reform::Form::UniqueValidator
- Inherits:
-
ActiveModel::EachValidator
- Object
- ActiveModel::EachValidator
- Reform::Form::UniqueValidator
- Defined in:
- lib/reform/form/validation/unique_validator.rb
Overview
Unique Validation
Reform's own implementation for uniqueness which does not write to model
Usage
Pass a true boolean value to validate a field against all values available in the database: validates :title, unique: true
Options
Case Sensitivity
Case sensitivity is true by default, but can be set to false:
validates :title, unique: { case_sensitive: false }
Scope
A scope can be used to filter the records that need to be compare with the current value to validate. A scope array can have one to many fields define.
A scope can be define the following ways: validates :title, unique: { scope: :album_id } validates :title, unique: { scope: [:album_id] } validates :title, unique: { scope: [:album_id, ...] }
All fields included in a scope must be declared as a property like this: property :album_id validates :title, unique: { scope: :album_id }
Just remove write access to the property if the field must not be change: property :album_id, writeable: false validates :title, unique: { scope: :album_id }
This use case is useful if album_id is set to a Song this way: song = album.songs.new album_id is automatically set and can't be change by the operation
Conditions
A condition can be passed to filter the records with partial indexes
Conditions can be define the following ways: validates :title, unique: { conditions: -> { where(archived_at: nil) } }
- This will check that the title is unique for non archived records validates :title, unique: { conditions: ->(record) { published_at = record.published_at where(published_at: published_at.beginning_of_year..published_at.end_of_year) } }
Instance Method Summary collapse
Instance Method Details
#validate_each(form, attribute, value) ⇒ Object
52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 |
# File 'lib/reform/form/validation/unique_validator.rb', line 52 def validate_each(form, attribute, value) model = form.model_for_property(attribute) original_attribute = form.(attribute)[:private_name] # search for models with attribute equals to form field value query = if [:case_sensitive] == false && value model.class.where("lower(#{original_attribute}) = ?", value.downcase) else model.class.where(original_attribute => value) end # if model persisted, query should bypass model if model.persisted? query = query.where("#{model.class.primary_key} != ?", model.id) end # apply scope if options has been declared Array([:scope]).each do |field| # add condition to only check unique value with the same scope query = query.where(field => form.send(field)) end if [:conditions] conditions = [:conditions] query = if conditions.arity.zero? query.instance_exec(&conditions) else query.instance_exec(form, &conditions) end end form.errors.add(attribute, :taken) if query.count > 0 end |