Ruby on rails 在Rails中进行验证之前,如何从值中剥离美元符号?

Ruby on rails 在Rails中进行验证之前,如何从值中剥离美元符号?,ruby-on-rails,ruby,Ruby On Rails,Ruby,以下是我在模型中使用的内容: before_validation :strip_dollar_sign validates :amount_due, :format => { :with => /^\d+??(?:\.\d{0,2})?$/ }, :numericality => {:greater_than => 0} private def strip_dollar_sign self.amount_due = se

以下是我在模型中使用的内容:

before_validation :strip_dollar_sign

validates :amount_due,
          :format => { :with => /^\d+??(?:\.\d{0,2})?$/ }, 
          :numericality => {:greater_than => 0}

private

def strip_dollar_sign
  self.amount_due = self.amount_due.to_s.tr!('$,','').to_f
end

如果我在Rails控制台中手动运行strip_dollar_sign函数中的行,我会得到我想要的结果(即$400最终为400.0),但当我在应用程序中使用实际表单时,值始终为0.0。有人知道我做错了什么吗?

$
后面有一个逗号,所以你要删除
$,
而不是
$

这里有三个问题:

  • 正如Stefan in所指出的,您可能需要删除
    tr中的
    调用,但不会影响
    $
    的替换

  • 您正在使用
    tr,并且以不正确的方式使用其返回值<代码>tr
    (以及Ruby的大多数
    方法变体)对字符串进行适当的变异,如果未进行任何更改,则返回
    nil
    。由于
    nil.to_f
    0.0
    ,这就是为什么您会得到它(或者可能不是,请参见下文)。您应该改为使用
    tr

  • Rails会自动将赋值参数转换为与之关联的数据库列的正确类型,因此即使在验证之前,您的值也会被转换为浮点值,
    “$400”。to_f
    0.0
    ,这就是回调所看到的。解决方案是覆盖
    amount\u due=
    ,而不是使用回调:

    def amount_due=(value)
      value = value.to_s.tr('$', '').to_f
      write_attribute(:amount_due, value)
    end
    

我建议使用javascript执行此操作。Rails似乎在表单帮助器方面发挥了一些作用,它可以将数字数据库类型支持的字段中的任何非数字值转换为0.0。愚蠢,我知道。

抓得好!实际上,
tr
调用中的逗号很好(如果可能不需要的话):
“$500”。tr(“$,”,”)
。引用文档:“返回str副本,其中from_str中的字符替换为To_str中的相应字符。如果To_str比from_str短,则会用其最后一个字符填充,以保持对应关系。”@MichaelKohl Good point,经过编辑以注意它不会影响
$
的替换,虽然它可能仍然不需要,因为逗号在某些地区是一个分隔符(加上Stefan的回答中似乎暗示了OP是一个错误)。我认为您在这里了解到了一些东西,但其他一些东西仍然被破坏。如果我进入控制台并运行
amount\u due=“$400”
,然后运行
amount\u due.to_.tr('$','')。to _f
输出为
400.0
。但是,如果我创建一个对象并尝试将相同的
$400
分配给
.amount\u due
值,我仍然会得到
0.0
@richrad啊,我想我知道发生了什么,请查看我更新的答案。就是这样@richrad您应该将该列保存为具有固定精度和比例的
Decimal
。货币不应存储为浮点数,而应存储为数据库中的Decimal和ruby中的BigDecimal。浮动可能有舍入错误,这可能会导致意外的结果。OP正在Rails中寻求解决方案(正如您可能看到的标记),因此JS不是他的问题的答案。