我最近注意到ActiveRecord对象上的方法changed?
在Rails 3.2.13和Rails 4.0.1之间发生了变化。问题是连接到数据库中整数字段的字段。假设我有模型Model
和number
整数字段:
# Rails 3.2.13
m = Model.last
m.number #=> 5
m.number = '5hello'
m.number #=> 5
m.number_changed? #=> true
m.changed? #=> true
m.changes #=> {:number => [5,5]}
# Rails 4.0.1
m = Model.last
m.number #=> 5
m.number = '5hello'
m.number #=> 5
m.number_changed? #=> false
m.changed? #=> false
m.changes #=> {}
这会导致表单验证出现许多非常恼人的问题——如果用户试图将整数值更改为具有无效字符(但类型转换将导致与初始值相同的值),rails将不会调用save
方法,并且不会运行任何验证(包括numericality: { only_integer: true }
)。
我已经设法通过将number_changed?
方法重写为super || number.to_s != number_before_type_cast
来解决这个问题,但是这非常难看。
问题是:为什么要改变?这是一个错误还是有意更改?如何在不覆盖整数列的所有元方法的情况下修复它?
我不确定你是如何运行验证的,但我的rails应用程序上有一个名为ExtraField的模型,它具有以下验证:
class ExtraField < ActiveRecord::Base
# stuff
validates :display_order, numericality: { only_integer: true }
# more stuff
end
我使用的是轨道4.0.5,我可以做以下事情:
e = ExtraField.first
e.display_order #=> 1
e.valid? #=> true
e.errors.messages #=> {}
e.display_order = '1banana'
e.display_order #=> 1
e.display_order_changed? #=> false
e.changed? #=> false
e.valid? #=> false
e.errors.messages #=> {:display_order=>["is not a number"]}
因此,尽管记录确实没有标记为已更改(这似乎是正确的IMHO),但我仍然可以运行验证并检查模型是否无效。对我来说,这并不是一个bug,只是一个有意的改进。
如果您的表单仅在模型对changed?
的响应为true时进行验证,那么您可能应该检查控制器代码。或者,如果你使用一个gem来帮助构建表单,我想这可能是该gem中的一个bug。