我有一个带有价格字段的预订模型。我选择了一个Integer数据类型来存储便士的价格,并在我的预订模型中有一个before_create调用,将用户输入的价格换算成磅数到便士:
before_create { self.price = price * 100 } #convert to pence
但是,我注意到在我的终端中,如果我在表单上输入一个十进制数字(例如22.75),它将被输入我的模型2200而不是2275.
我认为这是因为价格字段是一个整数,因此它会将22.75转换为22然后再将转换应用于便士。
我是否应该在我的控制器中解决这个问题?您认为或模型是正确的方法吗?
编辑我决定使用DECIMAL而不是INTEGER来避免潜在的头痛。关于这个主题有很多争论,但大多数人似乎都建议使用DECIMAL。感谢大家的建议。
答案 0 :(得分:1)
我会去转换模型之外的值。如果您从模型转换,很快或以后,将会发生棘手的事情。例如,您可以提供便士值,它仍然会增加100倍。
始终以正确的单位设置值可以避免任何错误:如果价格是便士,请始终将其设置为便士。从磅到便士的转换更像是帮助者或自由人应该做的事情。
答案 1 :(得分: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进行十进制显示。
答案 2 :(得分:0)
最好不要谈论过滤器。问题不在那里。
我对你的问题做了一个实验。
在我的一个演示应用程序中,我有一个模型任务。然后我在整数类型中添加了一个price字段,并复制了你的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])