我最近想写一个简单的迁移脚本。我写:
@entries = Entries.all(:text => /test/)
@entries.each do |entry|
entry.update(:text => entry.text.gsub!(/test/, "no-test"))
end
即使更新语句返回 true,它也没有保存记录。我错过了什么?
我最近想写一个简单的迁移脚本。我写:
@entries = Entries.all(:text => /test/)
@entries.each do |entry|
entry.update(:text => entry.text.gsub!(/test/, "no-test"))
end
即使更新语句返回 true,它也没有保存记录。我错过了什么?
在 1.x 系列的 datamapper 中,脏跟踪是通过调用#==
新旧属性值来检测脏的。如果一个对象在原地发生了变异(例如使用 String bang 方法),则无法检测到更改,因为“原始”状态也发生了变异。
基本上在内部发生以下情况:
a = "foo"
b = a.gsub!("foo", "bar")
a == b # => true both a and b refer to the same mutated object
a.equal?(b) # => true
在您的示例中,您将原始变异属性分配回对象,没有身份更改 => 没有检测到更新。
String#gsub
如果您通过而不是通过改变原始属性值来创建新对象,String#gsub!
最终会得到可检测的更改。
通过分配具有不同值的新对象,会发生以下情况:
a = "foo"
b = a.gsub("foo", "bar")
a == b # => false, loaded state does not equal resource state so change is detected
a.equal?(b) # => false
为了涵盖所有情况,分配一个具有相同值的新对象:
a = "foo"
b = "foo"
a == b # => true, no dirtyness detected.
a.equal?(b) # => false
希望这足以解释语义差异以解释所有类似情况。
顺便说一句,在 datamapper 2.0 中,我们有一个不同的机制,它也可以捕捉到位的突变。免责声明,我是这个名为dm-session的组件的作者。
去掉感叹号。
entry.update(:text => entry.text.gsub(/test/, "no-test"))
替换字符串内容时,记录不会变脏。你应该重新分配它。