根据the Rails docs for update_attributes,它是update的别名。其来源如下:
# File activerecord/lib/active_record/persistence.rb, line 247
def update(attributes)
# The following transaction covers any possible database side-effects of the
# attributes assignment. For example, setting the IDs of a child collection.
with_transaction_returning_status do
assign_attributes(attributes)
save
end
end
所以,它被包装在一个数据库事务中,这就是发生回滚的原因。不过,让我们看看assign_attributes。根据its source:
# File activerecord/lib/active_record/attribute_assignment.rb, line 23
def assign_attributes(new_attributes)
...
_assign_attribute(k, v)
...
end
那个is defined as:
# File activerecord/lib/active_record/attribute_assignment.rb, line 53
def _assign_attribute(k, v)
public_send("#{k}=", v)
rescue NoMethodError
if respond_to?("#{k}=")
raise
else
raise UnknownAttributeError.new(self, k)
end
end
所以,当您拨打test.update_attributes prop1: 'test', prop2: 'test' 时,基本上可以归结为:
test.prop1 = 'test'
test.prop2 = 'test'
test.save
如果save 验证失败,我们的test 内存副本仍然具有修改后的prop1 和prop2 值。因此,我们需要使用test.reload,问题就解决了(即我们的数据库和内存版本都没有改变)。
tl;dr 在update_attributes 调用失败后使用test.reload。