0

我有一个带有价格字段的预订模型。我选择了整数数据类型来存储以便士为单位的价格,并在我的 Booking 模型中调用 before_create 将用户输入的英镑价格转换为便士:

before_create { self.price = price * 100 } #convert to pence

但是,我在终端中注意到,如果我在表单上输入一个十进制数(例如 22.75),它将作为 2200 而不是 2275 输入到我的模型中。

我认为这是因为价格字段是一个整数,所以它会在将转换应用于便士之前将 22.75 转换为 22。

你认为我应该在我的控制器中解决这个问题还是模型是正确的方法?

编辑我决定使用 DECIMAL 而不是 INTEGER 来避免潜在的头痛。关于这个话题有很多争论,但大多数人似乎都推荐 DECIMAL。谢谢大家的建议。

4

3 回答 3

1

我会去转换模型之外的值。如果您从模型转换,迟早会发生棘手的事情。例如,您可能提供便士值,它仍然会乘以 100 倍。

始终以正确的单位设置值肯定会避免任何错误:如果价格以便士为单位,请始终以便士为单位设置。从英镑到便士的转换更像是一个助手或一个库应该做的事情。

于 2013-09-15T13:40:24.993 回答
0

最好不要谈论过滤器。问题不存在。

我对你的问题做了一个实验。

在我的一个演示应用程序中,我有一个模型任务。然后我添加了一个整数类型的价格字段,并复制了你的 before_create 过滤器。

结果?无需触摸过滤器即可获得相同的结果。

task = Task.new(title: 'foo', price: 22.75)
task.title
#=> 'foo'
task.price
#=> 22
task.price.to_f
#=> 22.0

看,在对象初始化时,该值已转换为整数。过滤器甚至还没有生效。

因此,对于您的情况,我认为最好的解决方案是使其保持一致,将所有价格保存为便士,并在需要时进行转换。

模型中的另一个考虑因素

当然,对于当前的修复,在控制器中处理数据是可行的。

另一种可能的方法是基于#new 编写另一种方法

class Booking < ActiveRecord::Base
  # ....
  # Remove that callback

  def new_with_price_format(*args)
    if args[:price].is_a?(Float)
       args[:price] *= 100
    end
    new(*args)
  end

然后在控制器中

  @booking = Booking.new_with_price_format(params[:booking])
于 2013-09-15T14:10:18.923 回答
0

尝试添加一些辅助方法。

class Booking < ActiveRecord::Base
  def price_dollars
    self.price / 100
  end

  def price_dollars=(val)
    self.price = val * 100
  end
end

这应该会有所帮助,以便在设置时它将 * 100 并且在显示时仅使用 booking1.price_dollars 进行小数显示。

于 2013-09-15T13:47:52.650 回答