Преобразование ввода пользователем в целое число

Итак, у меня есть форма, в которой пользователи могут вводить цену. Я пытаюсь сделать before_validation, который нормализует данные, обрезая $, если пользователь ставит его.

before_validation do
 unless self.price.blank? then self.price= self.price.to_s.gsub(/\D/, '').to_i end
end

Если пользователь вводит $50, этот код дает мне 0. Если пользователь вводит 50 $, этот код дает мне 50. Я думаю, так как тип данных является целым числом, что rails работает .to_i до моего before_validation и отсекает все после $. Этот же код отлично работает, если тип данных является строкой.

У кого-нибудь есть решение, которое позволит мне сохранить целочисленный тип данных?

Ответ 1

Один из способов - переопределить механизм модели, задающей цену, например:

def price=(val)
    write_attribute :price, val.to_s.gsub(/\D/, '').to_i
end

Итак, когда вы делаете @model.price = whatever, он перейдет к этому методу вместо атрибута атрибута атрибутов rails. Затем вы можете преобразовать номер и использовать write_attribute для выполнения собственно записи (вы должны сделать это так, потому что стандартный price= теперь этот метод!).

Мне нравится этот метод лучше всего, но для справки другой способ сделать это находится в вашем контроллере, прежде чем назначать его модели. Параметр вводится как строка, но модель преобразует эту строку в число, поэтому работайте с параметром напрямую. Что-то вроде этого (просто адаптируйте его к вашему коду контроллера):

def create
    @model = Model.new(params[:model])
    @model.price = params[:model][:price].gsub(/\D/, '').to_i
    @model.save
end

Для любого решения удалите это before_validation.

Ответ 2

Я бы определил виртуальный атрибут и сделаю свою манипуляцию там, позволяя вам форматировать и изменять как getter, так и setter по своему усмотрению:

class Model < ActiveRecord::Base

  def foo_price=(price)
    self.price = price... #=> Mods to string here
  end

  def foo_price
    "$#{price}"
  end

Вы также можете заметить, что:

"$50.00".gsub(/\D/, '').to_i #=> 5000

Ответ 3

Мое решение colum тип цены десятичный

t.decimal :price, precision: 12, scale: 6

# app/concern/sanitize_fields.rb
    module SanitizeFields
      extend ActiveSupport::Concern

      def clear_decimal(field)
        return (field.to_s.gsub(/[^\d]/, '').to_d / 100.to_d) unless field.blank?

      end

      def clear_integer(field)
        field.to_s.strip.gsub(/[^\d]/, '') unless field.blank?
      end

      # module ClassMethods
      #   def filter(filtering_params)
      #     results = self.where(nil)
      #     filtering_params.each do |key, value|
      #       results = results.public_send(key, value) if value.present?
      #     end
      #     results
      #   end
      #
      #   #use
      #   #def index
      #   #  @products = Product.filter(params.slice(:status, :location, :starts_with))
      #   #end
      #
      # end

    end

#app/controllers/products_controller.rb

include SanitizeFields

params[:product][:price] = clear_decimal(params[:product][:price])