class Shoulda::Matchers::ActiveRecord::ValidateUniquenessOfMatcher
@private
Public Class Methods
new(attribute)
click to toggle source
Calls superclass method
Shoulda::Matchers::ActiveModel::ValidationMatcher.new
# File lib/shoulda/matchers/active_record/validate_uniqueness_of_matcher.rb, line 202 def initialize(attribute) super(attribute) @options = {} end
Public Instance Methods
allow_blank()
click to toggle source
# File lib/shoulda/matchers/active_record/validate_uniqueness_of_matcher.rb, line 227 def allow_blank @options[:allow_blank] = true self end
allow_nil()
click to toggle source
# File lib/shoulda/matchers/active_record/validate_uniqueness_of_matcher.rb, line 222 def allow_nil @options[:allow_nil] = true self end
case_insensitive()
click to toggle source
# File lib/shoulda/matchers/active_record/validate_uniqueness_of_matcher.rb, line 217 def case_insensitive @options[:case_insensitive] = true self end
description()
click to toggle source
# File lib/shoulda/matchers/active_record/validate_uniqueness_of_matcher.rb, line 232 def description result = "require " result << "case sensitive " unless @options[:case_insensitive] result << "unique value for #{@attribute}" result << " scoped to #{@options[:scopes].join(', ')}" if @options[:scopes].present? result end
matches?(subject)
click to toggle source
# File lib/shoulda/matchers/active_record/validate_uniqueness_of_matcher.rb, line 240 def matches?(subject) @original_subject = subject @subject = subject.class.new @expected_message ||= :taken set_scoped_attributes && validate_everything_except_duplicate_nils_or_blanks? && validate_after_scope_change? && allows_nil? && allows_blank? ensure Uniqueness::TestModels.remove_all end
scoped_to(*scopes)
click to toggle source
# File lib/shoulda/matchers/active_record/validate_uniqueness_of_matcher.rb, line 207 def scoped_to(*scopes) @options[:scopes] = [*scopes].flatten self end
with_message(message)
click to toggle source
# File lib/shoulda/matchers/active_record/validate_uniqueness_of_matcher.rb, line 212 def with_message(message) @expected_message = message self end
Private Instance Methods
allows_blank?()
click to toggle source
# File lib/shoulda/matchers/active_record/validate_uniqueness_of_matcher.rb, line 265 def allows_blank? if @options[:allow_blank] ensure_blank_record_in_database allows_value_of('', @expected_message) else true end end
allows_nil?()
click to toggle source
# File lib/shoulda/matchers/active_record/validate_uniqueness_of_matcher.rb, line 256 def allows_nil? if @options[:allow_nil] ensure_nil_record_in_database allows_value_of(nil, @expected_message) else true end end
available_enum_values_for(scope, previous_value)
click to toggle source
# File lib/shoulda/matchers/active_record/validate_uniqueness_of_matcher.rb, line 422 def available_enum_values_for(scope, previous_value) @subject.defined_enums[scope.to_s].reject do |key, _| key == previous_value end end
class_name()
click to toggle source
# File lib/shoulda/matchers/active_record/validate_uniqueness_of_matcher.rb, line 428 def class_name @subject.class.name end
correct_type_for_column(column)
click to toggle source
# File lib/shoulda/matchers/active_record/validate_uniqueness_of_matcher.rb, line 395 def correct_type_for_column(column) if column.type == :string '0' elsif column.type == :datetime DateTime.now elsif column.type == :uuid SecureRandom.uuid else 0 end end
create_record_in_database(options = {})
click to toggle source
# File lib/shoulda/matchers/active_record/validate_uniqueness_of_matcher.rb, line 302 def create_record_in_database(options = {}) @original_subject.tap do |instance| instance.__send__("#{@attribute}=", value_for_new_record(options)) ensure_secure_password_set(instance) instance.save(validate: false) @created_record = instance end end
create_record_with_value()
click to toggle source
# File lib/shoulda/matchers/active_record/validate_uniqueness_of_matcher.rb, line 356 def create_record_with_value @existing_record = create_record_in_database end
ensure_blank_record_in_database()
click to toggle source
# File lib/shoulda/matchers/active_record/validate_uniqueness_of_matcher.rb, line 288 def ensure_blank_record_in_database unless existing_record_is_blank? create_record_in_database(blank_value: true) end end
ensure_nil_record_in_database()
click to toggle source
# File lib/shoulda/matchers/active_record/validate_uniqueness_of_matcher.rb, line 282 def ensure_nil_record_in_database unless existing_record_is_nil? create_record_in_database(nil_value: true) end end
ensure_secure_password_set(instance)
click to toggle source
# File lib/shoulda/matchers/active_record/validate_uniqueness_of_matcher.rb, line 311 def ensure_secure_password_set(instance) if has_secure_password? instance.password = "password" instance.password_confirmation = "password" end end
existing_record()
click to toggle source
# File lib/shoulda/matchers/active_record/validate_uniqueness_of_matcher.rb, line 274 def existing_record @existing_record ||= first_instance end
existing_record_is_blank?()
click to toggle source
# File lib/shoulda/matchers/active_record/validate_uniqueness_of_matcher.rb, line 298 def existing_record_is_blank? @existing_record.present? && existing_value.strip == '' end
existing_record_is_nil?()
click to toggle source
# File lib/shoulda/matchers/active_record/validate_uniqueness_of_matcher.rb, line 294 def existing_record_is_nil? @existing_record.present? && existing_value.nil? end
existing_value()
click to toggle source
# File lib/shoulda/matchers/active_record/validate_uniqueness_of_matcher.rb, line 432 def existing_value value = existing_record.__send__(@attribute) if @options[:case_insensitive] && value.respond_to?(:swapcase!) value.swapcase! end value end
first_instance()
click to toggle source
# File lib/shoulda/matchers/active_record/validate_uniqueness_of_matcher.rb, line 278 def first_instance @subject.class.first || create_record_in_database end
has_secure_password?()
click to toggle source
# File lib/shoulda/matchers/active_record/validate_uniqueness_of_matcher.rb, line 326 def has_secure_password? @subject.class.ancestors.map(&:to_s).include?('ActiveModel::SecurePassword::InstanceMethodsOnActivation') end
model_class?(model_name)
click to toggle source
# File lib/shoulda/matchers/active_record/validate_uniqueness_of_matcher.rb, line 360 def model_class?(model_name) model_name.constantize.ancestors.include?(::ActiveRecord::Base) rescue NameError false end
next_value_for(scope, previous_value)
click to toggle source
# File lib/shoulda/matchers/active_record/validate_uniqueness_of_matcher.rb, line 407 def next_value_for(scope, previous_value) if @subject.class.respond_to?(:defined_enums) && @subject.defined_enums[scope.to_s] available_values = available_enum_values_for(scope, previous_value) available_values.keys.last elsif scope.to_s =~ /_type$/ && model_class?(previous_value) Uniqueness::TestModels.create(previous_value).to_s elsif previous_value.respond_to?(:next) previous_value.next elsif previous_value.respond_to?(:to_datetime) previous_value.to_datetime.next else previous_value.to_s.next end end
set_scoped_attributes()
click to toggle source
# File lib/shoulda/matchers/active_record/validate_uniqueness_of_matcher.rb, line 330 def set_scoped_attributes if @options[:scopes].present? @options[:scopes].all? do |scope| setter = :"#{scope}=" if @subject.respond_to?(setter) @subject.__send__(setter, existing_record.__send__(scope)) true else @failure_message = "#{class_name} doesn't seem to have a #{scope} attribute." false end end else true end end
validate_after_scope_change?()
click to toggle source
# File lib/shoulda/matchers/active_record/validate_uniqueness_of_matcher.rb, line 366 def validate_after_scope_change? if @options[:scopes].blank? true else all_records = @subject.class.all @options[:scopes].all? do |scope| previous_value = all_records.map(&scope).max # Assume the scope is a foreign key if the field is nil previous_value ||= correct_type_for_column(@subject.class.columns_hash[scope.to_s]) next_value = next_value_for(scope, previous_value) @subject.__send__("#{scope}=", next_value) if allows_value_of(existing_value, @expected_message) @subject.__send__("#{scope}=", previous_value) @failure_message_when_negated << " (with different value of #{scope})" true else @failure_message << " (with different value of #{scope})" false end end end end
validate_everything_except_duplicate_nils_or_blanks?()
click to toggle source
# File lib/shoulda/matchers/active_record/validate_uniqueness_of_matcher.rb, line 347 def validate_everything_except_duplicate_nils_or_blanks? if (@options[:allow_nil] && existing_value.nil?) || (@options[:allow_blank] && existing_value.blank?) create_record_with_value end disallows_value_of(existing_value, @expected_message) end
value_for_new_record(options = {})
click to toggle source
# File lib/shoulda/matchers/active_record/validate_uniqueness_of_matcher.rb, line 318 def value_for_new_record(options = {}) case when options[:nil_value] then nil when options[:blank_value] then '' else 'a' end end