对已销毁的对象调用save将返回true,但不会保存

时间:2013-09-04 14:51:32

标签: ruby mongoid

尝试保存先前已销毁的Mongoid对象时出现奇怪的行为。鉴于此类定义:

class Foo
  include Mongoid::Document
end

保存实例后删除它,我无法再次保存:

Foo.count # => 0
f = Foo.create # => #<Foo _id: 522744a78d46b9b09f000001, >
Foo.count # => 1
f.destroy # => true
Foo.count # => 0
f.save # => true
# it lied - didn't actually save:
Foo.count # => 0
# these may be relevant:
f.persisted? # => false
f.destroyed? # => true
f.new_record? # => false
f.changed? # => false

这是一个我希望通过的失败的RSpec测试:

describe Foo do
  it 'should allow saving a Foo instance after destroying it' do
    expect(Foo.count).to eq(0)
    f = Foo.create
    expect(Foo.count).to eq(1)
    Foo.all.destroy
    expect(Foo.count).to eq(0)
    f.save # => true
    expect(Foo.count).to eq(1) # error - returns 0
  end
end

这是预期的行为吗?我的用例实际上是使用单例对象(虽然提到它但不想让问题更复杂); Foo.instance返回被Foo.all.destroy销毁的同一个对象,这会破坏事物。

1 个答案:

答案 0 :(得分:2)

  

<强>型号#保存

     

以原子方式将更改的属性保存到数据库,或者如果是新文件,则插入文档。会引发验证错误。

销毁后,文档不是新文档,并且没有更改的属性,因此save只返回没有错误。从严格意义上说,这似乎是预期的行为。

您可以使用Model#upsert

  

在文档上执行MongoDB upsert。如果文档存在于数据库中,它将被内存中文档的当前属性覆盖。如果数据库中不存在该文档,则会插入该文档。

这实际上会使用相同的ID保存文档,但它仍然是frozen?并标记为destroyed?。因此,根据评论中的疯狂-36的建议,仅仅clone文档可能会更好。