Numericality validation of virtual attributes
Commit #18b2859d2522a4866c398b9a32ebc3de4ec79389 broke numericality validation of virtual attributes in ActiveRecord models. This commit added a `column_type` method that assumes if `columns_hash` is a thing then our attribute would be present within it. This is not true for virtual attributes and leads to: ``` NoMethodError: undefined method `type' for nil:NilClass # /Users/bdmac/.gem/ruby/2.2.2/gems/shoulda-matchers-3.0.1/lib/shoulda/matchers/active_model/validate_numericality_of_matcher.rb:442:in # `column_type' ```
This commit is contained in:
parent
a9c3e9d0f2
commit
12e788f1d0
4
NEWS.md
4
NEWS.md
|
@ -17,6 +17,10 @@
|
|||
get a CouldNotSetAttributeError again.* (You may get some more information if
|
||||
a test fails, however.)
|
||||
|
||||
* Fix `validate_numericality_of` so that it does not blow up when used against
|
||||
a virtual attribute defined in an ActiveRecord model (that is, an attribute
|
||||
that is not present in the database but is defined using `attr_accessor`).
|
||||
|
||||
### Improvements
|
||||
|
||||
* Improve failure messages and descriptions of all matchers across the board so
|
||||
|
|
|
@ -491,7 +491,8 @@ module Shoulda
|
|||
end
|
||||
|
||||
def given_numeric_column?
|
||||
[:integer, :float, :decimal].include?(column_type)
|
||||
attribute_is_active_record_column? &&
|
||||
[:integer, :float, :decimal].include?(column_type)
|
||||
end
|
||||
|
||||
private
|
||||
|
@ -512,9 +513,19 @@ module Shoulda
|
|||
)
|
||||
end
|
||||
|
||||
def attribute_is_active_record_column?
|
||||
columns_hash.key?(@attribute.to_s)
|
||||
end
|
||||
|
||||
def column_type
|
||||
columns_hash[@attribute.to_s].type
|
||||
end
|
||||
|
||||
def columns_hash
|
||||
if @subject.class.respond_to?(:columns_hash)
|
||||
@subject.class.columns_hash[@attribute.to_s].type
|
||||
@subject.class.columns_hash
|
||||
else
|
||||
{}
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -152,6 +152,13 @@ Example did not properly validate that :attr looks like a number.
|
|||
}
|
||||
)
|
||||
|
||||
context 'when the attribute is a virtual attribute in an ActiveRecord model' do
|
||||
it 'accepts' do
|
||||
record = build_record_validating_numericality_of_virtual_attribute
|
||||
expect(record).to validate_numericality
|
||||
end
|
||||
end
|
||||
|
||||
context 'when the column is an integer column' do
|
||||
it 'accepts (and does not raise an AttributeChangedValueError)' do
|
||||
record = build_record_validating_numericality(column_type: :integer)
|
||||
|
@ -360,6 +367,15 @@ Example did not properly validate that :attr looks like an odd number.
|
|||
end
|
||||
end
|
||||
|
||||
context 'when the attribute is a virtual attribute in ActiveRecord model' do
|
||||
it 'accepts' do
|
||||
record = build_record_validating_numericality_of_virtual_attribute(
|
||||
odd: true
|
||||
)
|
||||
expect(record).to validate_numericality.odd
|
||||
end
|
||||
end
|
||||
|
||||
context 'when the column is an integer column' do
|
||||
it 'accepts (and does not raise an error)' do
|
||||
record = build_record_validating_numericality(
|
||||
|
@ -453,6 +469,15 @@ Example did not properly validate that :attr looks like an even number.
|
|||
end
|
||||
end
|
||||
|
||||
context 'when the attribute is a virtual attribute in an ActiveRecord model' do
|
||||
it 'accepts' do
|
||||
record = build_record_validating_numericality_of_virtual_attribute(
|
||||
even: true,
|
||||
)
|
||||
expect(record).to validate_numericality.even
|
||||
end
|
||||
end
|
||||
|
||||
context 'when the column is an integer column' do
|
||||
it 'accepts (and does not raise an error)' do
|
||||
record = build_record_validating_numericality(
|
||||
|
@ -551,6 +576,15 @@ than or equal to 18.
|
|||
end
|
||||
end
|
||||
|
||||
context 'when the attribute is a virtual attribute in an ActiveRecord model' do
|
||||
it 'accepts' do
|
||||
record = build_record_validating_numericality_of_virtual_attribute(
|
||||
less_than_or_equal_to: 18,
|
||||
)
|
||||
expect(record).to validate_numericality.is_less_than_or_equal_to(18)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when the column is an integer column' do
|
||||
it 'accepts (and does not raise an error)' do
|
||||
record = build_record_validating_numericality(
|
||||
|
@ -648,6 +682,15 @@ than 18.
|
|||
end
|
||||
end
|
||||
|
||||
context 'when the attribute is a virtual attribute in an ActiveRecord model' do
|
||||
it 'accepts' do
|
||||
record = build_record_validating_numericality_of_virtual_attribute(
|
||||
less_than: 18,
|
||||
)
|
||||
expect(record).to validate_numericality.is_less_than(18)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when the column is an integer column' do
|
||||
it 'accepts (and does not raise an error)' do
|
||||
record = build_record_validating_numericality(
|
||||
|
@ -743,6 +786,15 @@ to 18.
|
|||
end
|
||||
end
|
||||
|
||||
context 'when the attribute is a virtual attribute in an ActiveRecord model' do
|
||||
it 'accepts' do
|
||||
record = build_record_validating_numericality_of_virtual_attribute(
|
||||
equal_to: 18,
|
||||
)
|
||||
expect(record).to validate_numericality.is_equal_to(18)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when the column is an integer column' do
|
||||
it 'accepts (and does not raise an error)' do
|
||||
record = build_record_validating_numericality(
|
||||
|
@ -841,6 +893,16 @@ than or equal to 18.
|
|||
end
|
||||
end
|
||||
|
||||
context 'when the attribute is a virtual attribute in an ActiveRecord model' do
|
||||
it 'accepts' do
|
||||
record = build_record_validating_numericality_of_virtual_attribute(
|
||||
greater_than_or_equal_to: 18,
|
||||
)
|
||||
expect(record).to validate_numericality.
|
||||
is_greater_than_or_equal_to(18)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when the column is an integer column' do
|
||||
it 'accepts (and does not raise an error)' do
|
||||
record = build_record_validating_numericality(
|
||||
|
@ -942,6 +1004,15 @@ than 18.
|
|||
end
|
||||
end
|
||||
|
||||
context 'when the attribute is a virtual attribute in an ActiveRecord model' do
|
||||
it 'accepts' do
|
||||
record = build_record_validating_numericality_of_virtual_attribute(
|
||||
greater_than: 18,
|
||||
)
|
||||
expect(record).to validate_numericality.is_greater_than(18)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when the column is an integer column' do
|
||||
it 'accepts (and does not raise an error)' do
|
||||
record = build_record_validating_numericality(
|
||||
|
@ -1715,6 +1786,19 @@ Example did not properly validate that :attr looks like a number.
|
|||
end
|
||||
end
|
||||
|
||||
def define_model_validating_numericality_of_virtual_attribute(options = {})
|
||||
attribute_name = options.delete(:attribute_name) { self.attribute_name }
|
||||
|
||||
define_model 'Example' do |model|
|
||||
model.send(:attr_accessor, attribute_name)
|
||||
model.validates_numericality_of(attribute_name, options)
|
||||
end
|
||||
end
|
||||
|
||||
def build_record_validating_numericality_of_virtual_attribute(options = {})
|
||||
define_model_validating_numericality_of_virtual_attribute(options).new
|
||||
end
|
||||
|
||||
def build_record_validating_numericality(options = {})
|
||||
define_model_validating_numericality(options).new
|
||||
end
|
||||
|
|
Loading…
Reference in New Issue