Class: Reform::Form::UniqueValidator

Inherits:
ActiveModel::EachValidator
  • Object
show all
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 use 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

Instance Method Summary collapse

Instance Method Details

#validate_each(form, attribute, value) ⇒ Object



38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
# File 'lib/reform/form/validation/unique_validator.rb', line 38

def validate_each(form, attribute, value)
  model = form.model_for_property(attribute)
  original_attribute = form.options_for(attribute)[:private_name]

  # search for models with attribute equals to form field value
  query = if options[: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(options[:scope]).each do |field|
    # add condition to only check unique value with the same scope
    query = query.where(field => form.send(field))
  end

  form.errors.add(attribute, :taken) if query.count > 0
end