此代码不寻常。
我正在编程长期运行的交易(使用Web API)。
所以,我需要棘手的程序。
我想重新放置回滚对象(piyo2
)。
piyo2 = nil
ActiveRecord::Base.transaction do
piyo1 = Piyo.find_by(id: 1)
piyo1.name = 'hoge'
piyo1.save!
piyo2 = Piyo.find_by(id: 2)
piyo2.name = 'foo'
piyo2.save!
raise ActiveRecord::Rollback
end
piyo2.save! # log show BEGIN COMMIT. But Not show execute SQL.
piyo2.name # keep foo. But DB no change.
我的解决方案。
piyo2 = nil
ActiveRecord::Base.transaction do
piyo1 = Piyo.find_by(id: 1)
piyo1.name = 'hoge'
piyo1.save!
piyo2 = Piyo.find_by(id: 2)
piyo2.name = 'foo'
piyo2.save!
raise ActiveRecord::Rollback
end
piyo2_retry = Piyo.find_by(id: piyo2.id) # one more find_by
piyo2_retry.update!(name: piyo2.name)
这是最好的解决方案?
为什么piyo2.save! # log show BEGIN COMMIT. But No execute SQL.
此代码不锅?
您基本上是在做正确的事,尽管您的示例会使我感到困惑。
这是您所看到的为什么。
您必须刷新您手头的实例的状态。
即使您将交易滚回去,您的手中的实例仍然认为 它持续存在并具有新名称。您可以通过致电:
来证明这一点puts piyo2.name # foo
puts piyo2.persisted? # true
puts piyo2.changed? # falses
Rails足够聪明,如果对象当前持续存在并且没有更改,则不会实际运行SQL。您可以通过加载任何对象并立即尝试保存它来向自己证明这一点。您将在日志/输出中看到没有其他SQL的开始/提交。
有效地,您的对象不再与数据库同步。为了使实例的状态与DB同步,您必须重新加载它:
piyo2.reload
这是您正在有效地做的事情。Piyo.find piyo2.id
生成与重新加载相同的精确SQL。重新加载在语义上更清晰。