From 5fdc7d385ff02b5fa79e107c32e6fdad0f932871 Mon Sep 17 00:00:00 2001 From: Marcelo Lauxen Date: Thu, 15 Oct 2020 09:06:44 -0300 Subject: [PATCH] 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. --- activerecord/CHANGELOG.md | 4 ++++ .../active_record/attribute_methods/before_type_cast.rb | 5 ++++- activerecord/test/cases/attribute_methods_test.rb | 6 ++++++ .../cases/validations/numericality_validation_test.rb | 8 ++++++++ activerecord/test/models/numeric_data.rb | 2 ++ 5 files changed, 24 insertions(+), 1 deletion(-) diff --git a/activerecord/CHANGELOG.md b/activerecord/CHANGELOG.md index 3730dfac34..af82919268 100644 --- a/activerecord/CHANGELOG.md +++ b/activerecord/CHANGELOG.md @@ -1,3 +1,7 @@ +* Fix `read_attribute_before_type_cast` to consider attribute aliases. + + *Marcelo Lauxen* + * Support passing record to uniqueness validator `:conditions` callable: ```ruby diff --git a/activerecord/lib/active_record/attribute_methods/before_type_cast.rb b/activerecord/lib/active_record/attribute_methods/before_type_cast.rb index 52649d9271..59aa3a8b53 100644 --- a/activerecord/lib/active_record/attribute_methods/before_type_cast.rb +++ b/activerecord/lib/active_record/attribute_methods/before_type_cast.rb @@ -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" 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 # Returns a hash of attributes before typecasting and deserialization. diff --git a/activerecord/test/cases/attribute_methods_test.rb b/activerecord/test/cases/attribute_methods_test.rb index d66e37a903..f181e86570 100644 --- a/activerecord/test/cases/attribute_methods_test.rb +++ b/activerecord/test/cases/attribute_methods_test.rb @@ -12,6 +12,7 @@ require "models/category" require "models/reply" require "models/contact" require "models/keyboard" +require "models/numeric_data" class AttributeMethodsTest < ActiveRecord::TestCase include InTimeZone @@ -1087,6 +1088,11 @@ class AttributeMethodsTest < ActiveRecord::TestCase assert_equal "Topic::GeneratedAttributeMethods", mod.inspect 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 def new_topic_like_ar_class(&block) klass = Class.new(ActiveRecord::Base) do diff --git a/activerecord/test/cases/validations/numericality_validation_test.rb b/activerecord/test/cases/validations/numericality_validation_test.rb index 5b96d8f7ca..ffb8fd17b2 100644 --- a/activerecord/test/cases/validations/numericality_validation_test.rb +++ b/activerecord/test/cases/validations/numericality_validation_test.rb @@ -102,4 +102,12 @@ class NumericalityValidationTest < ActiveRecord::TestCase assert_not_predicate subject, :valid? 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 diff --git a/activerecord/test/models/numeric_data.rb b/activerecord/test/models/numeric_data.rb index 666e1a5778..60b382cda7 100644 --- a/activerecord/test/models/numeric_data.rb +++ b/activerecord/test/models/numeric_data.rb @@ -7,4 +7,6 @@ class NumericData < ActiveRecord::Base attribute :world_population, :big_integer attribute :my_house_population, :big_integer attribute :atoms_in_universe, :big_integer + + alias_attribute :new_bank_balance, :bank_balance end