From 02eefc088120c476750e36e8dd4ac4d6e2833881 Mon Sep 17 00:00:00 2001 From: Jamis Buck Date: Tue, 11 Mar 2025 08:46:32 -0600 Subject: [PATCH] MONGOID-5843 Ensure BSON::Decimal128 is considered to be numeric (#5961) * RUBY-5843 Ensure BSON::Decimal128 is considered to be numeric * bump drivers-evergreen-tools * let's see how this version of drivers-evergreen-tools does * Revert "let's see how this version of drivers-evergreen-tools does" This reverts commit 243fc495a5bdb6bb6009293a672c501882bf6d9e. * don't try to run `rails new` on rails < 7.1 concurrent-ruby gem removed a dependency on logger, which rails assumed was there. Installing those versions of Rails will install a too-new version of concurrent-ruby, which causes `rails new` to fail because it can't resolve Logger. --- .mod/drivers-evergreen-tools | 2 +- lib/mongoid/validatable.rb | 1 + lib/mongoid/validatable/macros.rb | 15 +++++++++++++++ lib/mongoid/validatable/numericality.rb | 19 +++++++++++++++++++ spec/integration/app_spec.rb | 6 ++++++ spec/mongoid/validatable/numericality_spec.rb | 16 ++++++++++++++++ 6 files changed, 58 insertions(+), 1 deletion(-) create mode 100644 lib/mongoid/validatable/numericality.rb diff --git a/.mod/drivers-evergreen-tools b/.mod/drivers-evergreen-tools index 1f018c7a24..14cc285a38 160000 --- a/.mod/drivers-evergreen-tools +++ b/.mod/drivers-evergreen-tools @@ -1 +1 @@ -Subproject commit 1f018c7a248c4fcda6cb7a77043fd673755e0986 +Subproject commit 14cc285a383f79eb2d0aec95e611192da9aa9dad diff --git a/lib/mongoid/validatable.rb b/lib/mongoid/validatable.rb index ce7f5c4c1d..921f417984 100644 --- a/lib/mongoid/validatable.rb +++ b/lib/mongoid/validatable.rb @@ -6,6 +6,7 @@ require "mongoid/validatable/associated" require "mongoid/validatable/format" require "mongoid/validatable/length" +require "mongoid/validatable/numericality" require "mongoid/validatable/queryable" require "mongoid/validatable/presence" require "mongoid/validatable/uniqueness" diff --git a/lib/mongoid/validatable/macros.rb b/lib/mongoid/validatable/macros.rb index 363af222d6..bb0a081ebe 100644 --- a/lib/mongoid/validatable/macros.rb +++ b/lib/mongoid/validatable/macros.rb @@ -89,6 +89,21 @@ def validates_length_of(*args) def validates_presence_of(*args) validates_with(PresenceValidator, _merge_attributes(args)) end + + # Validates whether or not a field contains a numeric value. + # + # @example + # class Person + # include Mongoid::Document + # field :cost + # + # validates_numericality_of :cost + # end + # + # @param [ Object... ] *args The names of the field(s) to validate. + def validates_numericality_of(*args) + validates_with(NumericalityValidator, _merge_attributes(args)) + end end end end diff --git a/lib/mongoid/validatable/numericality.rb b/lib/mongoid/validatable/numericality.rb new file mode 100644 index 0000000000..fa1bf276b3 --- /dev/null +++ b/lib/mongoid/validatable/numericality.rb @@ -0,0 +1,19 @@ +# frozen_string_literal: true + +module Mongoid + module Validatable + # A specialization of the ActiveModel numericality validator, which adds + # logic to recognize and accept BSON::Decimal128 as a number. + class NumericalityValidator < ActiveModel::Validations::NumericalityValidator + private + + # Ensure that BSON::Decimal128 is treated as a BigDecimal during the + # validation step. + def prepare_value_for_validation(value, record, attr_name) + result = super + + result.is_a?(BSON::Decimal128) ? result.to_big_decimal : result + end + end + end +end diff --git a/spec/integration/app_spec.rb b/spec/integration/app_spec.rb index 59cdb6d7b3..4112115fa5 100644 --- a/spec/integration/app_spec.rb +++ b/spec/integration/app_spec.rb @@ -127,6 +127,12 @@ def prepare_new_rails_app(name) end context 'new application - rails' do + before(:all) do + if SpecConfig.instance.rails_version < '7.1' + skip '`rails new` with rails < 7.1 fails because modern concurrent-ruby removed logger dependency' + end + end + it 'creates' do prepare_new_rails_app 'mongoid-test' do check_call(%w(rails g model post), env: clean_env) diff --git a/spec/mongoid/validatable/numericality_spec.rb b/spec/mongoid/validatable/numericality_spec.rb index ea89608d08..87b8c91740 100644 --- a/spec/mongoid/validatable/numericality_spec.rb +++ b/spec/mongoid/validatable/numericality_spec.rb @@ -29,5 +29,21 @@ class TestModel expect(model).to_not be_valid end end + + 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 + let(:model) { TestModel.new(amount: BSON::Decimal128.new('15.0')) } + + it 'returns true' do + expect(model).to be_valid + end + end end end