require "bigdecimal/util"

module ActiveModel
  module Type
    class Decimal < Value # :nodoc:
      include Helpers::Numeric

      def type
        :decimal
      end

      def type_cast_for_schema(value)
        value.to_s.inspect
      end

      private

        def cast_value(value)
          casted_value = \
            case value
            when ::Float
              convert_float_to_big_decimal(value)
            when ::Numeric, ::String
              BigDecimal(value, precision.to_i)
            else
              if value.respond_to?(:to_d)
                value.to_d
              else
                cast_value(value.to_s)
              end
            end

          apply_scale(casted_value)
        end

        def convert_float_to_big_decimal(value)
          if precision
            BigDecimal(apply_scale(value), float_precision)
          else
            value.to_d
          end
        end

        def float_precision
          if precision.to_i > ::Float::DIG + 1
            ::Float::DIG + 1
          else
            precision.to_i
          end
        end

        def apply_scale(value)
          if scale
            value.round(scale)
          else
            value
          end
        end
    end
  end
end

require "bigdecimal/util"

module ActiveModel
  module Type
    class Decimal < Value # :nodoc:
      include Helpers::Numeric
      BIGDECIMAL_PRECISION = 18

      def type
        :decimal
      end

      def type_cast_for_schema(value)
        value.to_s.inspect
      end

      private

        def cast_value(value)
          casted_value = \
            case value
            when ::Float
              convert_float_to_big_decimal(value)
            when ::Numeric, ::String
              BigDecimal(value, precision || BIGDECIMAL_PRECISION)
            else
              if value.respond_to?(:to_d)
                value.to_d
              else
                cast_value(value.to_s)
              end
            end

          apply_scale(casted_value)
        end

        def convert_float_to_big_decimal(value)
          if precision
            BigDecimal(apply_scale(value), float_precision)
          else
            value.to_d
          end
        end

        def float_precision
          if precision.to_i > ::Float::DIG + 1
            ::Float::DIG + 1
          else
            precision.to_i
          end
        end

        def apply_scale(value)
          if scale
            value.round(scale)
          else
            value
          end
        end
    end
  end
end

Make BigDecimal casting consistent on different platforms
Make BigDecimal casting consistent on different platforms

Right now it behaves differently on JRuby:

```
--- expected
+++ actual
@@ -1 +1 @@
-#<BigDecimal:5f3c866c,'0.333333333333333333',18(20)>
+#<BigDecimal:16e0afab,'0.3333333333333333',16(20)>
```

My initial PR (https://github.com/rails/rails/pull/27324)
offered to let the precision to be decided by the platform and
change the test expection, but other contributors suggested
that we should change the default precision in Rails
to be consistent of all platforms.

The value (18) comes from the max default precision that comes
from casting Rational(1/3) to BigDecimal.
