allow_value: Fix compatibility with enum columns

When used against an attribute that's an enum, `allow_value` will raise
an AttributeValueChangedError. This commit prevents that from happening.
This commit is contained in:
Elliot Winkler 2015-12-30 13:55:17 -05:00
parent 335971a87c
commit 9e8603eb74
3 changed files with 61 additions and 7 deletions

21
NEWS.md
View File

@ -1,5 +1,17 @@
# HEAD
### Bug fixes
* Update `validate_numericality_of` so that submatchers are applied lazily
instead of immediately. Previously, qualifiers were order-dependent, meaning
that if you used `strict` before you used, say, `odd`, then `strict` wouldn't
actually apply to `odd`. Now the order that you specify qualifiers doesn't
matter.
* Fix `allow_value` so that it does not raise an AttributeChangedValueError
(formerly CouldNotSetAttributeError) when used against an attribute that is an
enum in an ActiveRecord model.
### Improvements
* Improve failure messages and descriptions of all matchers across the board so
@ -7,15 +19,12 @@
(You'll see a huge difference in the output of the numericality and uniqueness
matchers in particular.)
* The CouldNotSetAttributeError that you have probably seen is now called
AttributeChangedValueError.
* Matchers now raise an error if any attributes that the matcher is attempting
to set do not exist on the model.
* Update `validate_numericality_of` so that submatchers are applied lazily
instead of immediately. Previously, qualifiers were order-dependent, meaning
that if you used `strict` before you used, say, `odd`, then `strict` wouldn't
actually apply to `odd`. Now the order that you specify qualifiers doesn't
matter.
* Update `validate_numericality_of` so that it doesn't always run all of the
submatchers, but stops on the first one that fails. Since failure messages
now contain information as to what value the matcher set on the attribute when

View File

@ -78,7 +78,7 @@ module Shoulda
@result_of_checking = successful_check
if attribute_changed_value? && !ignoring_interference_by_writer?
if raise_attribute_changed_value_error?
@result_of_setting = attribute_changed_value_error
false
else
@ -156,6 +156,33 @@ module Shoulda
!!@ignoring_interference_by_writer
end
def raise_attribute_changed_value_error?
attribute_changed_value? &&
!(attribute_is_an_enum? && value_read_is_expected_for_an_enum?) &&
!ignoring_interference_by_writer?
end
def attribute_is_an_enum?
enum_values.any?
end
def value_read_is_expected_for_an_enum?
enum_values.key?(value_read) &&
enum_values[value_read] == value_written
end
def enum_values
defined_enums.fetch(attribute_name.to_s, {})
end
def defined_enums
if model.respond_to?(:defined_enums)
model.defined_enums
else
{}
end
end
def successful_check
SuccessfulCheck.new
end
@ -192,6 +219,10 @@ module Shoulda
def active_resource_object?
object.respond_to?(:known_attributes)
end
def model
object.class
end
end
end
end

View File

@ -641,4 +641,18 @@ value", but that attribute does not exist.
end
end
end
if active_record_supports_enum?
context 'given an ActiveRecord model' do
context 'where the attribute under test is an enum and the given value is a value in that enum' do
it 'accepts' do
model = define_model('Shipment', status: :integer) do
enum status: { pending: 1, shipped: 2, delivered: 3 }
end
expect(model.new).to allow_value(1).for(:status)
end
end
end
end
end