From 85bff802585a341ede2a5d7b438f2b820c153518 Mon Sep 17 00:00:00 2001 From: Kyle Burgess Date: Thu, 11 Dec 2025 15:36:01 -0500 Subject: [PATCH 1/5] Trying to avoid returning nil --- lib/mongoid/extensions/float.rb | 2 + lib/mongoid/extensions/integer.rb | 2 + spec/mongoid/validatable/numericality_spec.rb | 111 ++++++++++++++---- 3 files changed, 91 insertions(+), 24 deletions(-) diff --git a/lib/mongoid/extensions/float.rb b/lib/mongoid/extensions/float.rb index 52f45a0f4d..e09796cccf 100644 --- a/lib/mongoid/extensions/float.rb +++ b/lib/mongoid/extensions/float.rb @@ -43,6 +43,8 @@ def mongoize(object) if object.is_a?(String) if object.numeric? object.to_f + else + object end else object.try(:to_f) diff --git a/lib/mongoid/extensions/integer.rb b/lib/mongoid/extensions/integer.rb index ec35ee97bd..806145652c 100644 --- a/lib/mongoid/extensions/integer.rb +++ b/lib/mongoid/extensions/integer.rb @@ -53,6 +53,8 @@ def mongoize(object) if object.is_a?(String) if object.numeric? object.to_i + else + object end else object.try(:to_i) diff --git a/spec/mongoid/validatable/numericality_spec.rb b/spec/mongoid/validatable/numericality_spec.rb index 43b5dc7d30..037bbe32fd 100644 --- a/spec/mongoid/validatable/numericality_spec.rb +++ b/spec/mongoid/validatable/numericality_spec.rb @@ -4,47 +4,110 @@ require "spec_helper" describe ActiveModel::Validations::NumericalityValidator do - describe "#validate_each" do + context "when allow_blank is false" do + before(:all) do + class TestModel + include Mongoid::Document + field :amount, type: BigDecimal + validates_numericality_of :amount, allow_blank: false + end + end - before(:all) do - class TestModel - include Mongoid::Document - field :amount, type: BigDecimal - validates_numericality_of :amount, allow_blank: false + after(:all) do + Object.send(:remove_const, :TestModel) end - end - after(:all) do - Object.send(:remove_const, :TestModel) - end + context "when the value is non numeric" do - context "when the value is non numeric" do + let(:model) do + TestModel.new(amount: "asdf") + end - let(:model) do - TestModel.new(amount: "asdf") + it "returns false" do + expect(model).to_not be_valid + end end - it "returns false" do - expect(model).to_not be_valid + context 'when the value is numeric' do + let(:model) { TestModel.new(amount: '15.0') } + + it 'returns true' do + expect(model).to be_valid + end + end + + context 'when the value is a BSON::Decimal128' do + min_rails_version '6.1' + + let(:model) { TestModel.new(amount: BSON::Decimal128.new('15.0')) } + + it 'returns true' do + expect(model).to be_valid + end end end - context 'when the value is numeric' do - let(:model) { TestModel.new(amount: '15.0') } + context "when allow_blank is true and amount is Integer" do + before(:all) do + class TestModelAllowBlank + include Mongoid::Document + field :amount, type: Integer + validates_numericality_of :amount, allow_blank: true + end + end - it 'returns true' do - expect(model).to be_valid + after(:all) do + Object.send(:remove_const, :TestModelAllowBlank) + end + + context "when the value is blank" do + + let(:model) do + TestModelAllowBlank.new(amount: "") + end + + it "returns true" do + expect(model).to be_valid + end + end + + context "when the value is a nonempty string" do + + let(:model) do + TestModelAllowBlank.new(amount: "A non-numeric string") + end + + it "returns false" do + puts model.inspect + expect(model).to_not be_valid + end end end + + context "when allow_blank is true and amount is Float" do + before(:all) do + class TestModelAllowBlank + include Mongoid::Document + field :amount, type: Float + validates_numericality_of :amount, allow_blank: true + end + end + + after(:all) do + Object.send(:remove_const, :TestModelAllowBlank) + end - context 'when the value is a BSON::Decimal128' do - min_rails_version '6.1' + context "when the value is a nonempty string" do - let(:model) { TestModel.new(amount: BSON::Decimal128.new('15.0')) } + let(:model) do + TestModelAllowBlank.new(amount: "A non-numeric string") + end - it 'returns true' do - expect(model).to be_valid + it "returns false" do + puts model.inspect + expect(model).to_not be_valid + end end end end From a145cef13108a127838df2adeeab867342b2cb4d Mon Sep 17 00:00:00 2001 From: Kyle Burgess Date: Thu, 11 Dec 2025 16:31:37 -0500 Subject: [PATCH 2/5] Trying a new approach --- lib/mongoid/extensions/float.rb | 2 -- lib/mongoid/extensions/integer.rb | 2 -- lib/mongoid/validatable.rb | 2 ++ 3 files changed, 2 insertions(+), 4 deletions(-) diff --git a/lib/mongoid/extensions/float.rb b/lib/mongoid/extensions/float.rb index e09796cccf..52f45a0f4d 100644 --- a/lib/mongoid/extensions/float.rb +++ b/lib/mongoid/extensions/float.rb @@ -43,8 +43,6 @@ def mongoize(object) if object.is_a?(String) if object.numeric? object.to_f - else - object end else object.try(:to_f) diff --git a/lib/mongoid/extensions/integer.rb b/lib/mongoid/extensions/integer.rb index 806145652c..ec35ee97bd 100644 --- a/lib/mongoid/extensions/integer.rb +++ b/lib/mongoid/extensions/integer.rb @@ -53,8 +53,6 @@ def mongoize(object) if object.is_a?(String) if object.numeric? object.to_i - else - object end else object.try(:to_i) diff --git a/lib/mongoid/validatable.rb b/lib/mongoid/validatable.rb index 921f417984..fbb7ef87af 100644 --- a/lib/mongoid/validatable.rb +++ b/lib/mongoid/validatable.rb @@ -80,6 +80,8 @@ def read_attribute_for_validation(attr) relation.try(:in_memory) || relation elsif fields[attribute].try(:localized?) attributes[attribute] + elsif fields[attribute]&.type == BigDecimal || fields[attribute]&.type == Float || fields[attribute]&.type == Integer + send("#{attr}_before_type_cast") else send(attr) end From 22a9f34a20c918e98bbecde161eaa3042e73c9c0 Mon Sep 17 00:00:00 2001 From: Kyle Burgess Date: Thu, 11 Dec 2025 16:53:55 -0500 Subject: [PATCH 3/5] fixing naming and spacing, adding test for bigdecimal --- spec/mongoid/validatable/numericality_spec.rb | 43 ++++++++++++++----- 1 file changed, 33 insertions(+), 10 deletions(-) diff --git a/spec/mongoid/validatable/numericality_spec.rb b/spec/mongoid/validatable/numericality_spec.rb index 037bbe32fd..c921de7b36 100644 --- a/spec/mongoid/validatable/numericality_spec.rb +++ b/spec/mongoid/validatable/numericality_spec.rb @@ -50,7 +50,7 @@ class TestModel context "when allow_blank is true and amount is Integer" do before(:all) do - class TestModelAllowBlank + class TestModelAllowBlankInteger include Mongoid::Document field :amount, type: Integer validates_numericality_of :amount, allow_blank: true @@ -58,13 +58,13 @@ class TestModelAllowBlank end after(:all) do - Object.send(:remove_const, :TestModelAllowBlank) + Object.send(:remove_const, :TestModelAllowBlankInteger) end context "when the value is blank" do let(:model) do - TestModelAllowBlank.new(amount: "") + TestModelAllowBlankInteger.new(amount: "") end it "returns true" do @@ -75,19 +75,18 @@ class TestModelAllowBlank context "when the value is a nonempty string" do let(:model) do - TestModelAllowBlank.new(amount: "A non-numeric string") + TestModelAllowBlankInteger.new(amount: "A non-numeric string") end it "returns false" do - puts model.inspect expect(model).to_not be_valid end end end - + context "when allow_blank is true and amount is Float" do before(:all) do - class TestModelAllowBlank + class TestModelAllowBlankFloat include Mongoid::Document field :amount, type: Float validates_numericality_of :amount, allow_blank: true @@ -95,17 +94,41 @@ class TestModelAllowBlank end after(:all) do - Object.send(:remove_const, :TestModelAllowBlank) + Object.send(:remove_const, :TestModelAllowBlankFloat) end context "when the value is a nonempty string" do let(:model) do - TestModelAllowBlank.new(amount: "A non-numeric string") + TestModelAllowBlankFloat.new(amount: "A non-numeric string") + end + + it "returns false" do + expect(model).to_not be_valid + end + end + end + + context "when allow_blank is true and amount is BigDecimal" do + before(:all) do + class TestModelAllowBlankBigDecimal + include Mongoid::Document + field :amount, type: BigDecimal + validates_numericality_of :amount, allow_blank: true + end + end + + after(:all) do + Object.send(:remove_const, :TestModelAllowBlankBigDecimal) + end + + context "when the value is a nonempty string" do + + let(:model) do + TestModelAllowBlankBigDecimal.new(amount: "A non-numeric string") end it "returns false" do - puts model.inspect expect(model).to_not be_valid end end From 9a0a845aa7188bebc6aef555d98430fd8834916f Mon Sep 17 00:00:00 2001 From: Kyle Burgess <90669224+kyleburgess2025@users.noreply.github.com> Date: Mon, 15 Dec 2025 09:40:14 -0500 Subject: [PATCH 4/5] Update lib/mongoid/validatable.rb Co-authored-by: Jamis Buck --- lib/mongoid/validatable.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/mongoid/validatable.rb b/lib/mongoid/validatable.rb index fbb7ef87af..29ecb496c2 100644 --- a/lib/mongoid/validatable.rb +++ b/lib/mongoid/validatable.rb @@ -80,7 +80,7 @@ def read_attribute_for_validation(attr) relation.try(:in_memory) || relation elsif fields[attribute].try(:localized?) attributes[attribute] - elsif fields[attribute]&.type == BigDecimal || fields[attribute]&.type == Float || fields[attribute]&.type == Integer + elsif fields[attribute]&.type <= Numeric send("#{attr}_before_type_cast") else send(attr) From a6b75e6821e9b869d7bcd43bf2d4abb4fd356e35 Mon Sep 17 00:00:00 2001 From: Kyle Burgess Date: Mon, 15 Dec 2025 09:54:37 -0500 Subject: [PATCH 5/5] adding another safe navigation check --- lib/mongoid/validatable.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/mongoid/validatable.rb b/lib/mongoid/validatable.rb index 29ecb496c2..e0f45a6440 100644 --- a/lib/mongoid/validatable.rb +++ b/lib/mongoid/validatable.rb @@ -80,7 +80,7 @@ def read_attribute_for_validation(attr) relation.try(:in_memory) || relation elsif fields[attribute].try(:localized?) attributes[attribute] - elsif fields[attribute]&.type <= Numeric + elsif fields[attribute]&.type&.<=(Numeric) send("#{attr}_before_type_cast") else send(attr)