Пользовательский десятичный тип для локализованного ввода с использованием API-атрибутов Rails 5 - PullRequest
0 голосов
/ 01 февраля 2019

Я пытаюсь создать пользовательский десятичный тип, используя API атрибутов Rails 5 для принятия локализованного пользовательского ввода.Это выглядит следующим образом:

  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

Но я не понимаю, что я мог бы изменить, чтобы это работало.Есть идеи?!

Ответы [ 2 ]

0 голосов
/ 04 февраля 2019

Я заставил это работать, изменив мой пользовательский тип десятичного числа.

      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
0 голосов
/ 01 февраля 2019

В валидаторе используется переменная с именем 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
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...