From a0bb19fbfa590a3a773a24bc018b92fd5ba93b4d Mon Sep 17 00:00:00 2001 From: David Heinemeier Hansson Date: Thu, 1 Aug 2019 15:38:03 -0700 Subject: [PATCH] Add *_previously_was attribute methods when dirty tracking (#36836) --- activemodel/CHANGELOG.md | 6 ++++++ activemodel/lib/active_model/dirty.rb | 8 +++++++- activerecord/test/cases/dirty_test.rb | 6 ++++++ 3 files changed, 19 insertions(+), 1 deletion(-) diff --git a/activemodel/CHANGELOG.md b/activemodel/CHANGELOG.md index 9d77564c61..c301f4766d 100644 --- a/activemodel/CHANGELOG.md +++ b/activemodel/CHANGELOG.md @@ -1,3 +1,9 @@ +* Add *_previously_was attribute methods when dirty tracking. Example: + pirate.update(catchphrase: "Ahoy!") + pirate.previous_changes["catchphrase"] # => ["Thar She Blows!", "Ahoy!"] + pirate.catchphrase_previously_was # => "Thar She Blows!" + + *DHH* Please check [6-0-stable](https://github.com/rails/rails/blob/6-0-stable/activemodel/CHANGELOG.md) for previous changes. diff --git a/activemodel/lib/active_model/dirty.rb b/activemodel/lib/active_model/dirty.rb index aaefe00c83..245616502d 100644 --- a/activemodel/lib/active_model/dirty.rb +++ b/activemodel/lib/active_model/dirty.rb @@ -84,6 +84,7 @@ module ActiveModel # person.previous_changes # => {"name" => [nil, "Bill"]} # person.name_previously_changed? # => true # person.name_previous_change # => [nil, "Bill"] + # person.name_previously_was # => nil # person.reload! # person.previous_changes # => {} # @@ -122,7 +123,7 @@ module ActiveModel included do attribute_method_suffix "_changed?", "_change", "_will_change!", "_was" - attribute_method_suffix "_previously_changed?", "_previous_change" + attribute_method_suffix "_previously_changed?", "_previous_change", "_previously_was" attribute_method_affix prefix: "restore_", suffix: "!" end @@ -180,6 +181,11 @@ module ActiveModel mutations_before_last_save.changed?(attr_name.to_s) end + # Dispatch target for *_previously_was attribute methods. + def attribute_previously_was(attr_name) # :nodoc: + mutations_before_last_save.original_value(attr_name.to_s) + end + # Restore all previous data of the provided attributes. def restore_attributes(attr_names = changed) attr_names.each { |attr_name| restore_attribute!(attr_name) } diff --git a/activerecord/test/cases/dirty_test.rb b/activerecord/test/cases/dirty_test.rb index a2a501a794..6aca7d93ad 100644 --- a/activerecord/test/cases/dirty_test.rb +++ b/activerecord/test/cases/dirty_test.rb @@ -491,6 +491,7 @@ class DirtyTest < ActiveRecord::TestCase assert_equal 4, pirate.previous_changes.size assert_equal [nil, "arrr"], pirate.previous_changes["catchphrase"] + assert_equal nil, pirate.catchphrase_previously_was assert_equal [nil, pirate.id], pirate.previous_changes["id"] assert_nil pirate.previous_changes["updated_on"][0] assert_not_nil pirate.previous_changes["updated_on"][1] @@ -507,6 +508,7 @@ class DirtyTest < ActiveRecord::TestCase assert_equal 4, pirate.previous_changes.size assert_equal [nil, "arrr"], pirate.previous_changes["catchphrase"] + assert_equal nil, pirate.catchphrase_previously_was assert_equal [nil, pirate.id], pirate.previous_changes["id"] assert_includes pirate.previous_changes, "updated_on" assert_includes pirate.previous_changes, "created_on" @@ -525,6 +527,7 @@ class DirtyTest < ActiveRecord::TestCase assert_equal 2, pirate.previous_changes.size assert_equal ["arrr", "Me Maties!"], pirate.previous_changes["catchphrase"] + assert_equal "arrr", pirate.catchphrase_previously_was assert_not_nil pirate.previous_changes["updated_on"][0] assert_not_nil pirate.previous_changes["updated_on"][1] assert_not pirate.previous_changes.key?("parrot_id") @@ -539,6 +542,7 @@ class DirtyTest < ActiveRecord::TestCase assert_equal 2, pirate.previous_changes.size assert_equal ["Me Maties!", "Thar She Blows!"], pirate.previous_changes["catchphrase"] + assert_equal "Me Maties!", pirate.catchphrase_previously_was assert_not_nil pirate.previous_changes["updated_on"][0] assert_not_nil pirate.previous_changes["updated_on"][1] assert_not pirate.previous_changes.key?("parrot_id") @@ -551,6 +555,7 @@ class DirtyTest < ActiveRecord::TestCase assert_equal 2, pirate.previous_changes.size assert_equal ["Thar She Blows!", "Ahoy!"], pirate.previous_changes["catchphrase"] + assert_equal "Thar She Blows!", pirate.catchphrase_previously_was assert_not_nil pirate.previous_changes["updated_on"][0] assert_not_nil pirate.previous_changes["updated_on"][1] assert_not pirate.previous_changes.key?("parrot_id") @@ -563,6 +568,7 @@ class DirtyTest < ActiveRecord::TestCase assert_equal 2, pirate.previous_changes.size assert_equal ["Ahoy!", "Ninjas suck!"], pirate.previous_changes["catchphrase"] + assert_equal "Ahoy!", pirate.catchphrase_previously_was assert_not_nil pirate.previous_changes["updated_on"][0] assert_not_nil pirate.previous_changes["updated_on"][1] assert_not pirate.previous_changes.key?("parrot_id")