Ruby-on-rails 将用户输入转换为整数

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/9679882/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-03 03:02:01  来源:igfitidea点击:

Convert User input to integer

ruby-on-railsruby

提问by Robert

So I have a form where users can input a price. I'm trying to make a before_validation that normalizes the data, clipping the $ if the user puts it.

所以我有一个用户可以输入价格的表单。我正在尝试制作一个 before_validation 来规范化数据,如果用户放置它,则剪裁 $ 。

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

If user inputs $50 This code is giving me 0. If user inputs 50$ this code gives me 50. I think since the data type is integer that rails is running .to_i prior to my before_validation and clipping everything after the $. This same code works fine if the data type is a string.

如果用户输入 $50 这段代码给我 0。如果用户输入 50$ 这段代码给我 50。我认为因为数据类型是整数,所以 rails 在我的 before_validation 之前运行 .to_i 并剪裁 $ 之后的所有内容。如果数据类型是字符串,同样的代码也能正常工作。

Anyone have a solution that will let me keep the integer datatype?

任何人都有可以让我保留整数数据类型的解决方案?

回答by Ben Lee

One way is to override the mechanism on the model that sets the price, like this:

一种方法是覆盖模型上设置价格的机制,如下所示:

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

So when you do @model.price = whatever, it will go to this method instead of the rails default attribute writer. Then you can convert the number and use write_attributeto do the actual writing (you have to do it this way because the standard price=is now this method!).

所以当你这样做时@model.price = whatever,它会转到这个方法而不是 rails 默认属性 writer。然后你可以转换数字并使用write_attribute它来做实际的写作(你必须这样做,因为price=现在标准是这种方法!)。

I like this method best, but for reference another way to do it is in your controller before assigning it to the model. The parameter comes in as a string, but the model is converting that string to a number, so work with the parameter directly. Something like this (just adapt it to your controller code):

我最喜欢这种方法,但作为参考,另一种方法是在将其分配给模型之前在您的控制器中。参数以字符串形式出现,但模型正在将该字符串转换为数字,因此直接使用该参数。像这样的东西(只需使其适应您的控制器代码):

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

For either solution, remove that before_validation.

对于任一解决方案,请删除该before_validation.

回答by offbyjuan

I would define a virtual attribute and do my manipulation there allowing you to format and modify both the getter and setter at will:

我会定义一个虚拟属性并在那里进行操作,允许您随意格式化和修改 getter 和 setter:

class Model < ActiveRecord::Base

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

  def foo_price
    "$#{price}"
  end

You also might want to note that:

您可能还想注意:

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

回答by gilcierweb

My soluction colum price type decimal

我的解决方案列价格类型小数

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])