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

时间:2012-12-17 15:30:30

标签: ruby database migration datamapper ruby-datamapper

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

@entries = Entries.all(:text => /test/)

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

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

2 个答案:

答案 0 :(得分:6)

在1.x系列数据映射器中,通过在新旧属性值上调用#==来检测脏污,从而完成脏跟踪。如果对象在场内变异(例如使用String bang方法),则无法将变化检测为" orignal"国家也变异了。

基本上内部会发生以下情况:

a = "foo"
b = a.gsub!("foo", "bar")
a == b     # => true both a and b refer to the same mutated object
a.equal?(b) # => true

在您的示例中,您将原始的mutated属性分配回对象,没有身份更改=>没有检测到更新。

如果您通过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-session

答案 1 :(得分:1)

删除感叹号。

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

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