自定义小数类型为使用Rails 5的属性API本地化输入

问题描述 投票:1回答:2

我试图创建一个使用的Rails 5的属性API来接受本地化的用户输入自定义小数类型。它看起来象下面这样:

  class Decimal < ActiveRecord::Type::Decimal

    def cast(value)
      return unless value
      cast_value(value.is_a?(String) ? parse_from_string(value) : value)
    end

    def changed_in_place?(raw_old_value, new_value)
      raw_old_value != serialize(new_value)
    end

    def parse_from_string(value)
      delimiter = I18n.t('number.format.delimiter')
      separator = I18n.t('number.format.separator')
      value.gsub(delimiter, '_').gsub(separator, '.')
    end
  end

我也有一个自定义表单生成器显示一个格式化的值给用户。当提交表单创建资源(模型实体),它工作正常。然而,提交表单更新资源时,在validates_numericality_of验证,标志着我的自定义属性为无效(not_a_number)。在主动模式的源代码经过一番研究,我达到了这段代码在NumericalityValidator

https://github.com/rails/rails/blob/6a1b7985602c5bfab4c8875ca9bf0d598e063a65/activemodel/lib/active_model/validations/numericality.rb#L26-L49

但我不明白我可以改变,使这个作品。有任何想法吗?!

ruby-on-rails ruby-on-rails-5
2个回答
1
投票

验证程序使用一个名为raw_value变量。它试图从你的对象,它的原始值,检查线路35至38。

我想你可以使用你的属性的名称以“_before_type_cast”返回一个数值,验证可以使用你的模型中定义的方法。

如果你的属性被调用,可以说,amount,你可以这样做:

def amount_before_type_cast
  amount.to_number
end

然后,你必须确定你的自定义类型的方法把它变成一个数字,也许是这样的:

def to_number
  value.gsub(/\D/,'').to_i #remove all non-digit and turn it into an integer
end

1
投票

我做了改变我的自定义小数类型的工作。

      class Decimal < ActiveRecord::Type::Decimal

        def cast(value)
          return unless value

          if value.is_a?(String)
            if numeric_string?(value)
              value = value.to_s.to_numeric
            else
              return value
            end
          end
          cast_value(value)
        end

        def value_constructed_by_mass_assignment?(value)
          if value.is_a?(String)
            numeric_string?(value)
          else
            super
          end
        end

        def numeric_string?(value)
          number = value.to_s.gsub(/[.,]/, '.' => '', ',' => '.')
          /\A[-+]?\d+/.match?(number)
        end

      end
© www.soinside.com 2019 - 2024. All rights reserved.