From 63ff495bdf90e0ab20114a49db5cffe3cb9ef2fd Mon Sep 17 00:00:00 2001 From: Ryuta Kamizono Date: Sat, 19 May 2018 11:46:03 +0900 Subject: Fix dirty tracking after rollback. Currently the rollback only restores primary key value, `new_record?`, `destroyed?`, and `frozen?`. Since the `save` clears current dirty attribute states, retrying save after rollback will causes no change saved if partial writes is enabled (by default). This makes `remember_transaction_record_state` remembers original values then restores dirty attribute states after rollback. Fixes #15018. Fixes #30167. Fixes #33868. Fixes #33443. Closes #33444. Closes #34504. --- activerecord/lib/active_record/transactions.rb | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) (limited to 'activerecord/lib/active_record/transactions.rb') diff --git a/activerecord/lib/active_record/transactions.rb b/activerecord/lib/active_record/transactions.rb index 03a373f0af..ea288456b9 100644 --- a/activerecord/lib/active_record/transactions.rb +++ b/activerecord/lib/active_record/transactions.rb @@ -390,6 +390,7 @@ module ActiveRecord id: id, new_record: @new_record, destroyed: @destroyed, + attributes: @attributes, frozen?: frozen?, ) @_start_transaction_state[:level] = (@_start_transaction_state[:level] || 0) + 1 @@ -422,12 +423,18 @@ module ActiveRecord transaction_level = (@_start_transaction_state[:level] || 0) - 1 if transaction_level < 1 || force_restore_state restore_state = @_start_transaction_state - thaw @new_record = restore_state[:new_record] @destroyed = restore_state[:destroyed] + @attributes = restore_state[:attributes].map do |attr| + value = @attributes.fetch_value(attr.name) + attr = attr.with_value_from_user(value) if attr.value != value + attr + end + @mutations_from_database = nil + @mutations_before_last_save = nil pk = self.class.primary_key - if pk && _read_attribute(pk) != restore_state[:id] - _write_attribute(pk, restore_state[:id]) + if pk && @attributes.fetch_value(pk) != restore_state[:id] + @attributes.write_from_user(pk, restore_state[:id]) end freeze if restore_state[:frozen?] end -- cgit v1.2.3