diff options
author | Ryuta Kamizono <kamipo@gmail.com> | 2018-05-19 11:46:03 +0900 |
---|---|---|
committer | Ryuta Kamizono <kamipo@gmail.com> | 2019-04-16 12:30:45 +0900 |
commit | 63ff495bdf90e0ab20114a49db5cffe3cb9ef2fd (patch) | |
tree | 33d5e390a602ef7c77a2c675865b573802fdd35b /activerecord/lib/active_record/transactions.rb | |
parent | 20b94af9eb9305d19a343f72f0afb18eb49e2de7 (diff) | |
download | rails-63ff495bdf90e0ab20114a49db5cffe3cb9ef2fd.tar.gz rails-63ff495bdf90e0ab20114a49db5cffe3cb9ef2fd.tar.bz2 rails-63ff495bdf90e0ab20114a49db5cffe3cb9ef2fd.zip |
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.
Diffstat (limited to 'activerecord/lib/active_record/transactions.rb')
-rw-r--r-- | activerecord/lib/active_record/transactions.rb | 13 |
1 files changed, 10 insertions, 3 deletions
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 |