为什么datamapper不更新记录/检测脏



我最近想写一个简单的迁移脚本。我写道:

@entries = Entries.all(:text => /test/)
@entries.each do |entry|
entry.update(:text => entry.text.gsub!(/test/, "no-test"))
end

它没有保存记录,即使update语句返回true。我错过了什么?

在1.x系列的数据映射程序中,通过对新属性值和旧属性值调用#==来检测脏跟踪。如果一个对象在原地发生突变(例如使用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

希望这能很好地解释语义差异,从而解释所有类似的情况。

BTW在datamapper 2.0中,我们有一种不同的机制,也可以捕获原位突变。免责声明,我是这个名为dm会话的组件的作者。

删除感叹号。

entry.update(:text => entry.text.gsub(/test/, "no-test"))

替换字符串内容时,记录不会变脏。你应该重新分配。

最新更新