Fixes uniqueness matcher for enum columns

In Rails 4.1, if the scope from a validates_uniqueness_of matcher is an
enum, next_value won't get the correct value, then tests will fail even
that validation works. This adds a way to check if the scoped attribute
is an enum, and correctly get the next value.
This commit is contained in:
Ivan Valdes (@ivanvc) 2014-04-19 10:53:51 -05:00 committed by Elliot Winkler
parent ee2eca4098
commit d4b1fc2fa1
3 changed files with 50 additions and 1 deletions

View File

@ -32,6 +32,8 @@
* Fix `delegate_method` so that it does not stub the target method forever,
returning it to its original implementation after the match ends.
* Fix `validate_uniqueness_of` to work with Rails 4.1 enum columns.
# 2.6.0
* The boolean argument to `have_db_index`'s `unique` option is now optional, for

View File

@ -173,7 +173,12 @@ module Shoulda # :nodoc:
previous_value ||= correct_type_for_column(@subject.class.columns_hash[scope.to_s])
next_value =
if previous_value.respond_to?(:next)
if @subject.class.respond_to?(:defined_enums) && @subject.defined_enums[scope.to_s]
available_values = @subject.defined_enums[scope.to_s].reject do |key, _|
key == previous_value
end
available_values.keys.last
elsif previous_value.respond_to?(:next)
previous_value.next
elsif previous_value.respond_to?(:to_datetime)
previous_value.to_datetime.next

View File

@ -122,6 +122,40 @@ describe Shoulda::Matchers::ActiveModel::ValidateUniquenessOfMatcher do
not_to matcher.scoped_to(:fake)
end
if rails_gte_4_1?
context 'when the scoped attribute is an enum' do
it 'accepts' do
expect(validating_scoped_uniqueness_with_enum([:scope1], scope1: 0)).
to matcher.scoped_to(:scope1)
end
context 'with a nil value' do
it 'accepts' do
expect(validating_scoped_uniqueness_with_enum([:scope1], scope1: nil)).
to matcher.scoped_to(:scope1)
end
end
context 'when too narrow of a scope is specified' do
it 'rejects' do
expect(validating_scoped_uniqueness_with_enum_with_two_scopes).
not_to matcher.scoped_to(:scope1, :scope2, :other)
end
end
context 'when too broad of a scope is specified' do
it 'rejects' do
expect(validating_scoped_uniqueness_with_enum_with_two_scopes).
not_to matcher.scoped_to(:scope1)
end
end
def validating_scoped_uniqueness_with_enum_with_two_scopes
validating_scoped_uniqueness_with_enum([:scope1, :scope2], scope1: 0, scope2: 0)
end
end
end
context 'when the scoped attribute is a date' do
it "accepts" do
expect(validating_scoped_uniqueness([:scope1], :date, scope1: Date.today)).
@ -250,6 +284,14 @@ describe Shoulda::Matchers::ActiveModel::ValidateUniquenessOfMatcher do
model
end
def validating_scoped_uniqueness_with_enum(*args)
attributes = args.extract_options!
model = define_scoped_model(*args)
model.enum scope1: [:foo, :bar]
create_existing_record(attributes)
model.new
end
def validating_scoped_uniqueness_with_conflicting_next(*args)
attributes = args.extract_options!
model = define_scoped_model(*args).new