允许在数字字段中使用逗号

时间:2022-11-01 21:49:06

This is such a dumb question that I feel like I must be missing something simple. I have a form with a quantity field. People keep typing commas when they enter the quantity (for example, they type 12,000 to indicate twelve thousand) so I would like to strip out the commas before saving the quantity (12000 in the example) into an integer column in the database.

这是一个如此愚蠢的问题,我觉得我必须错过一些简单的事情。我有一个带有数量字段的表单。人们在输入数量时会继续输入逗号(例如,他们键入12,000表示一万二千),因此我想在将数量(示例中为12000)保存到数据库中的整数列之前删除逗号。

So far I have tried two methods. Overriding the setter method as suggested in this SO question

到目前为止,我尝试了两种方法。按照此SO问题中的建议覆盖setter方法

  def quantity=(num)
    num.gsub!(',', '') if num.is_a?(String)
    self[:quantity] = num.to_i
  end

This works in a sense. If I type 12,000 in the quantity field and submit the form, I get 12000 in the database. The problem is that it also bypasses all quantity validations. No longer can I validate the presence of a value for quantity for example. This is not good.

这在某种意义上是有效的。如果我在数量字段中键入12,000并提交表单,我会在数据库中获得12000。问题是它还绕过了所有数量验证。例如,我不再能够验证数量值的存在。不是很好。

I have also tried to use a before validation callback (instead of overriding the setter):

我也尝试使用before验证回调(而不是覆盖setter):

  before_validation :sanitize_quantity

  def sanitize_quantity
    # Doesn't wok because quantity.to_i already called by this point.
  end

This doesn't work because by the time the quantity has reached the callback method, Rails has already called to_i on it. This means that 12,000 will be truncated to 12 by the time it reaches the callback. Once again, not good.

这不起作用,因为当数量到达回调方法时,Rails已经调用了to_i。这意味着12,000将在到达回调时被截断为12。再次,不好。

What else can I try aside from stripping the commas on the client-side?

除了剥离客户端的逗号外,我还能尝试什么?

As a final note, I am aware that this is essentially a dumb thing to do because certain countries use periods and commas in different ways. I still need to do it anyway.

作为最后一点,我知道这实际上是一件愚蠢的事情,因为某些国家以不同的方式使用句号和逗号。无论如何我仍然需要这样做。

3 个解决方案

#1


10  

Use Type Coercions

If I understand your question correctly, you're trying to coerce strings into numbers. If so, you can just use an explicit cast like so:

如果我正确理解你的问题,那你就是想把字符串强制转换成数字。如果是这样,您可以像这样使用显式转换:

validates :quantity, presence: true, numericality: true

def quantity=(num)
  self[:quantity] = num.to_s.scan(/\b-?[\d.]+/).join.to_f
end

Tests and Examples

See see how this works, you can try the following at the console.

看看它是如何工作的,您可以在控制台上尝试以下操作。

# String as input.
number = '12,956.05'
number.to_s.scan(/\b-?[\d.]+/).join.to_f
=> 12956.05

# Float as input.
number = 12956.05
number.to_s.scan(/\b-?[\d.]+/).join.to_f
=> 12956.05

# Using an ActiveRecord object.
q = Quantity.new quantity: '12,956.05'
=> #<Quantity id: nil, quantity: 12956.05, created_at: nil, updated_at: nil>
q.save
=> true

#2


8  

I actually figured this out just as I was reading over my question.

事实上,当我正在阅读我的问题时,我确实想到了这一点。

The key is to use a virtual attribute.

关键是使用虚拟属性。

class Job < ActiveRecord::Base
  def flexible_quantity
    quantity
  end

  def flexible_quantity=(quantity)
    self.quantity = quantity.gsub(',', '') unless quantity.blank?
  end
 end

Then in the form, use the virtual attribute.

然后在表单中,使用虚拟属性。

<%= f.text_field :flexible_quantity %>

Now validate the presence of the flexible_quantity value instead.

现在验证flex_quantity值的存在。

class Job < ActiveRecord::Base
  validates :flexible_quantity, presence: true

  # The cool this is that we can leave the numericality validation on the quantity field.
  validates :quantity, presence: true, numericality: { only_integer: true }
end

#3


0  

You'll get the quantity in params[:quanity]. You can just call a helper method (defined in your controller, for instance) to fix the String, and then pass that along to your model.

您将获得params [:quanity]中的数量。您可以调用辅助方法(例如在控制器中定义)来修复String,然后将其传递给模型。

# YourController.rb
def create # or whatever
    quantity = sanitize_quantity(params[:quantity])
    YourModel.create!(:quantity => quantity)
end

private

    def sanitize_quantity(num)
        num.gsub!(',', '') if num.is_a?(String)
        return num.to_i
    end

So you sanitize it before it goes to your model, so it can still have validations done on it.

所以你在它进入模型之前对它进行消毒,因此它仍然可以对其进行验证。

#1


10  

Use Type Coercions

If I understand your question correctly, you're trying to coerce strings into numbers. If so, you can just use an explicit cast like so:

如果我正确理解你的问题,那你就是想把字符串强制转换成数字。如果是这样,您可以像这样使用显式转换:

validates :quantity, presence: true, numericality: true

def quantity=(num)
  self[:quantity] = num.to_s.scan(/\b-?[\d.]+/).join.to_f
end

Tests and Examples

See see how this works, you can try the following at the console.

看看它是如何工作的,您可以在控制台上尝试以下操作。

# String as input.
number = '12,956.05'
number.to_s.scan(/\b-?[\d.]+/).join.to_f
=> 12956.05

# Float as input.
number = 12956.05
number.to_s.scan(/\b-?[\d.]+/).join.to_f
=> 12956.05

# Using an ActiveRecord object.
q = Quantity.new quantity: '12,956.05'
=> #<Quantity id: nil, quantity: 12956.05, created_at: nil, updated_at: nil>
q.save
=> true

#2


8  

I actually figured this out just as I was reading over my question.

事实上,当我正在阅读我的问题时,我确实想到了这一点。

The key is to use a virtual attribute.

关键是使用虚拟属性。

class Job < ActiveRecord::Base
  def flexible_quantity
    quantity
  end

  def flexible_quantity=(quantity)
    self.quantity = quantity.gsub(',', '') unless quantity.blank?
  end
 end

Then in the form, use the virtual attribute.

然后在表单中,使用虚拟属性。

<%= f.text_field :flexible_quantity %>

Now validate the presence of the flexible_quantity value instead.

现在验证flex_quantity值的存在。

class Job < ActiveRecord::Base
  validates :flexible_quantity, presence: true

  # The cool this is that we can leave the numericality validation on the quantity field.
  validates :quantity, presence: true, numericality: { only_integer: true }
end

#3


0  

You'll get the quantity in params[:quanity]. You can just call a helper method (defined in your controller, for instance) to fix the String, and then pass that along to your model.

您将获得params [:quanity]中的数量。您可以调用辅助方法(例如在控制器中定义)来修复String,然后将其传递给模型。

# YourController.rb
def create # or whatever
    quantity = sanitize_quantity(params[:quantity])
    YourModel.create!(:quantity => quantity)
end

private

    def sanitize_quantity(num)
        num.gsub!(',', '') if num.is_a?(String)
        return num.to_i
    end

So you sanitize it before it goes to your model, so it can still have validations done on it.

所以你在它进入模型之前对它进行消毒,因此它仍然可以对其进行验证。