Class: Predicates::Unique

Inherits:
Base
  • Object
show all
Defined in:
lib/predicates/unique.rb

Overview

Describes an attribute as being unique, possibly within a certain scope.

Options

  • :scope [array] - a list of other fields that define the context for uniqueness. it’s like defining a multi-column uniqueness constraint.

  • :case_sensitive [boolean, default false] - whether case matters for uniqueness.

Examples

field_is_unique :case_sensitive => true
field_is_unique :scope => [:other_field, :another_other_field]

Instance Attribute Summary collapse

Attributes inherited from Base

#full_message, #or_empty, #validate_if, #validate_on

Instance Method Summary collapse

Methods inherited from Base

#allow_empty?, #error, #error_binds, #normalize, #to_human

Constructor Details

#initialize(attribute, options = {}) ⇒ Unique

Returns a new instance of Unique.



14
15
16
17
18
19
20
# File 'lib/predicates/unique.rb', line 14

def initialize(attribute, options = {})
  defaults = {
    :scope => [],
    :case_sensitive => false
  }
  super attribute, defaults.merge(options)
end

Instance Attribute Details

#case_sensitiveObject

Returns the value of attribute case_sensitive.



11
12
13
# File 'lib/predicates/unique.rb', line 11

def case_sensitive
  @case_sensitive
end

#scopeObject

Returns the value of attribute scope.



12
13
14
# File 'lib/predicates/unique.rb', line 12

def scope
  @scope
end

Instance Method Details

#error_messageObject



22
23
24
# File 'lib/predicates/unique.rb', line 22

def error_message
  @error_message || :taken
end

#validate(value, record) ⇒ Object



26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
# File 'lib/predicates/unique.rb', line 26

def validate(value, record)  
  klass = record.class

  # merge all the scope fields with this one. they must all be unique together.
  # no special treatment -- case sensitivity applies to all or none.
  values = [scope].flatten.collect{ |attr| [attr, record.send(attr)] }
  values << [@attribute, value]

  sql = values.map do |(attr, attr_value)|
    comparison_for(attr, attr_value, klass)
  end

  unless record.new_record?
    sql << klass.send(:sanitize_sql, ["#{klass.quoted_table_name}.#{klass.primary_key} <> ?", record.id])
  end

  !klass.where(sql.join(" AND ")).exists?
end