diff --git a/lib/shoulda/matchers/active_record/validate_uniqueness_of_matcher.rb b/lib/shoulda/matchers/active_record/validate_uniqueness_of_matcher.rb index b0ecf90dc..dd4283bf5 100644 --- a/lib/shoulda/matchers/active_record/validate_uniqueness_of_matcher.rb +++ b/lib/shoulda/matchers/active_record/validate_uniqueness_of_matcher.rb @@ -244,6 +244,7 @@ def matches?(subject) set_scoped_attributes && validate_everything_except_duplicate_nils_or_blanks? && + validate_case_sensitivity? && validate_after_scope_change? && allows_nil? && allows_blank? @@ -353,6 +354,22 @@ def validate_everything_except_duplicate_nils_or_blanks? disallows_value_of(existing_value, @expected_message) end + def validate_case_sensitivity? + value = existing_value + + if value.respond_to?(:swapcase) + swapcased_value = value.swapcase + + if @options[:case_insensitive] + disallows_value_of(swapcased_value, @expected_message) + else + allows_value_of(swapcased_value, @expected_message) + end + else + true + end + end + def create_record_with_value @existing_record = create_record_in_database end @@ -462,11 +479,7 @@ def available_enum_values_for(scope, previous_value) end def existing_value - value = existing_record.__send__(@attribute) - if @options[:case_insensitive] && value.respond_to?(:swapcase!) - value.swapcase! - end - value + existing_record.__send__(@attribute) end def class_name diff --git a/spec/unit/shoulda/matchers/active_record/validate_uniqueness_of_matcher_spec.rb b/spec/unit/shoulda/matchers/active_record/validate_uniqueness_of_matcher_spec.rb index c6bdab730..32cd7b829 100644 --- a/spec/unit/shoulda/matchers/active_record/validate_uniqueness_of_matcher_spec.rb +++ b/spec/unit/shoulda/matchers/active_record/validate_uniqueness_of_matcher_spec.rb @@ -392,7 +392,7 @@ end end - context 'when the model has a case-sensitive validation on a string attribute' do + context 'when the model has a case-sensitive validation' do context 'when case_insensitive is not specified' do it 'accepts' do record = build_record_validating_uniqueness( @@ -416,6 +416,30 @@ end end + context 'when the model has a case-insensitive validation' do + context 'when case_insensitive is not specified' do + it 'rejects' do + record = build_record_validating_uniqueness( + attribute_type: :string, + validation_options: { case_sensitive: false } + ) + + expect(record).not_to validate_uniqueness + end + end + + context 'when case_insensitive is specified' do + it 'accepts' do + record = build_record_validating_uniqueness( + attribute_type: :string, + validation_options: { case_sensitive: false } + ) + + expect(record).to validate_uniqueness.case_insensitive + end + end + end + context 'when the validation is declared with allow_nil' do context 'given a new record whose attribute is nil' do it 'accepts' do