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.
所以你在它进入模型之前对它进行消毒,因此它仍然可以对其进行验证。