1
0
Fork 0
mirror of https://github.com/rails/rails.git synced 2022-11-09 12:12:34 -05:00

Fix read_attribute_before_type_cast to consider attribute aliases

Numericality validations for aliased attributes are not able
to get the value of the attribute before type cast because
activerecord was trying to get the value of the attribute based
on attribute alias name and not the original attribute name.

Example of validation which would pass even if a invalid value
would be provided

    class MyModel < ActiveRecord::Base
      validates :aliased_balance, numericality: { greater_than_or_equal_to: 0 }
    end

If we instantiate MyModel like bellow it will be valid because
when numericality validation runs it will not be able to get the
value before type cast, so it uses the type casted value
which will be `0.0` and the validation will match.

    subject = MyModel.new(aliased_balance: "abcd")
    subject.valid?

But if we declare MyModel like this

    class MyModel < ActiveRecord::Base
      validates :balance, numericality: { greater_than_or_equal_to: 0 }
    end

and assign "abcd" value to `balance` when the validations
run the model will be invalid because activerecord will be able
to get the value before type cast.

With this change `read_attribute_before_type_cast` will be able to
get the value before type cast even when the attr_name is an
attribute_alias.
This commit is contained in:
Marcelo Lauxen 2020-10-15 09:06:44 -03:00
parent 28a4d97331
commit 5fdc7d385f
5 changed files with 24 additions and 1 deletions

View file

@ -1,3 +1,7 @@
* Fix `read_attribute_before_type_cast` to consider attribute aliases.
*Marcelo Lauxen*
* Support passing record to uniqueness validator `:conditions` callable: * Support passing record to uniqueness validator `:conditions` callable:
```ruby ```ruby

View file

@ -46,7 +46,10 @@ module ActiveRecord
# task.read_attribute_before_type_cast('completed_on') # => "2012-10-21" # task.read_attribute_before_type_cast('completed_on') # => "2012-10-21"
# task.read_attribute_before_type_cast(:completed_on) # => "2012-10-21" # task.read_attribute_before_type_cast(:completed_on) # => "2012-10-21"
def read_attribute_before_type_cast(attr_name) def read_attribute_before_type_cast(attr_name)
attribute_before_type_cast(attr_name.to_s) name = attr_name.to_s
name = self.class.attribute_aliases[name] || name
attribute_before_type_cast(name)
end end
# Returns a hash of attributes before typecasting and deserialization. # Returns a hash of attributes before typecasting and deserialization.

View file

@ -12,6 +12,7 @@ require "models/category"
require "models/reply" require "models/reply"
require "models/contact" require "models/contact"
require "models/keyboard" require "models/keyboard"
require "models/numeric_data"
class AttributeMethodsTest < ActiveRecord::TestCase class AttributeMethodsTest < ActiveRecord::TestCase
include InTimeZone include InTimeZone
@ -1087,6 +1088,11 @@ class AttributeMethodsTest < ActiveRecord::TestCase
assert_equal "Topic::GeneratedAttributeMethods", mod.inspect assert_equal "Topic::GeneratedAttributeMethods", mod.inspect
end end
test "read_attribute_before_type_cast with aliased attribute" do
model = NumericData.new(new_bank_balance: "abcd")
assert_equal "abcd", model.read_attribute_before_type_cast("new_bank_balance")
end
private private
def new_topic_like_ar_class(&block) def new_topic_like_ar_class(&block)
klass = Class.new(ActiveRecord::Base) do klass = Class.new(ActiveRecord::Base) do

View file

@ -102,4 +102,12 @@ class NumericalityValidationTest < ActiveRecord::TestCase
assert_not_predicate subject, :valid? assert_not_predicate subject, :valid?
end end
def test_aliased_attribute
model_class.validates_numericality_of(:new_bank_balance, greater_or_equal_than: 0)
subject = model_class.new(new_bank_balance: "abcd")
assert_not_predicate subject, :valid?
end
end end

View file

@ -7,4 +7,6 @@ class NumericData < ActiveRecord::Base
attribute :world_population, :big_integer attribute :world_population, :big_integer
attribute :my_house_population, :big_integer attribute :my_house_population, :big_integer
attribute :atoms_in_universe, :big_integer attribute :atoms_in_universe, :big_integer
alias_attribute :new_bank_balance, :bank_balance
end end