@@ -68,7 +68,9 @@ def changes
6868 # @example Move the changes to previous.
6969 # person.move_changes
7070 def move_changes
71+ @changes_before_last_save = @previous_changes
7172 @previous_changes = changes
73+ @attributes_before_last_save = @previous_attributes
7274 @previous_attributes = attributes . dup
7375 Atomic ::UPDATES . each do |update |
7476 send ( update ) . clear
@@ -133,6 +135,72 @@ def setters
133135 mods
134136 end
135137
138+ # Returns the original value of an attribute before the last save.
139+ #
140+ # This method is useful in after callbacks to get the original value of
141+ # an attribute before the save that triggered the callbacks to run.
142+ #
143+ # @param [ Symbol | String ] attr The name of the attribute.
144+ #
145+ # @return [ Object ] Value of the attribute before the last save.
146+ def attribute_before_last_save ( attr )
147+ attr = database_field_name ( attr )
148+ attributes_before_last_save [ attr ]
149+ end
150+
151+ # Returns the change to an attribute during the last save.
152+ #
153+ # @param [ Symbol | String ] attr The name of the attribute.
154+ #
155+ # @return [ Array<Object> | nil ] If the attribute was changed, returns
156+ # an array containing the original value and the saved value, otherwise nil.
157+ def saved_change_to_attribute ( attr )
158+ attr = database_field_name ( attr )
159+ previous_changes [ attr ]
160+ end
161+
162+ # Returns whether this attribute changed during the last save.
163+ #
164+ # This method is useful in after callbacks, to see the change
165+ # in an attribute during the save that triggered the callbacks to run.
166+ #
167+ # @param [ String ] attr The name of the attribute.
168+ # @param **kwargs The optional keyword arguments.
169+ #
170+ # @option **kwargs [ Object ] :from The object the attribute was changed from.
171+ # @option **kwargs [ Object ] :to The object the attribute was changed to.
172+ #
173+ # @return [ true | false ] Whether the attribute has changed during the last save.
174+ def saved_change_to_attribute? ( attr , **kwargs )
175+ changes = saved_change_to_attribute ( attr )
176+ return false unless changes . is_a? ( Array )
177+ if kwargs . key? ( :from ) && kwargs . key? ( :to )
178+ changes . first == kwargs [ :from ] && changes . last == kwargs [ :to ]
179+ elsif kwargs . key? ( :from )
180+ changes . first == kwargs [ :from ]
181+ elsif kwargs . key? ( :to )
182+ changes . last == kwargs [ :to ]
183+ else
184+ true
185+ end
186+ end
187+
188+ # Returns whether this attribute change the next time we save.
189+ #
190+ # This method is useful in validations and before callbacks to determine
191+ # if the next call to save will change a particular attribute.
192+ #
193+ # @param [ String ] attr The name of the attribute.
194+ # @param **kwargs The optional keyword arguments.
195+ #
196+ # @option **kwargs [ Object ] :from The object the attribute was changed from.
197+ # @option **kwargs [ Object ] :to The object the attribute was changed to.
198+ #
199+ # @return [ true | false ] Whether the attribute change the next time we save.
200+ def will_save_change_to_attribute? ( attr , **kwargs )
201+ attribute_changed? ( attr , **kwargs )
202+ end
203+
136204 private
137205
138206 # Get attributes of the document before the document was saved.
@@ -142,6 +210,14 @@ def previous_attributes
142210 @previous_attributes ||= { }
143211 end
144212
213+ def changes_before_last_save
214+ @changes_before_last_save ||= { }
215+ end
216+
217+ def attributes_before_last_save
218+ @attributes_before_last_save ||= { }
219+ end
220+
145221 # Get the old and new value for the provided attribute.
146222 #
147223 # @example Get the attribute change.
@@ -317,6 +393,9 @@ def create_dirty_change_check(name, meth)
317393 re_define_method ( "#{ meth } _changed?" ) do |**kwargs |
318394 attribute_changed? ( name , **kwargs )
319395 end
396+ re_define_method ( "will_save_change_to_#{ meth } ?" ) do |**kwargs |
397+ will_save_change_to_attribute? ( name , **kwargs )
398+ end
320399 end
321400 end
322401
@@ -350,6 +429,15 @@ def create_dirty_previous_value_accessor(name, meth)
350429 re_define_method ( "#{ meth } _previously_was" ) do
351430 attribute_previously_was ( name )
352431 end
432+ re_define_method ( "#{ meth } _before_last_save" ) do
433+ attribute_before_last_save ( name )
434+ end
435+ re_define_method ( "saved_change_to_#{ meth } " ) do
436+ saved_change_to_attribute ( name )
437+ end
438+ re_define_method ( "saved_change_to_#{ meth } ?" ) do |**kwargs |
439+ saved_change_to_attribute? ( name , **kwargs )
440+ end
353441 end
354442 end
355443
0 commit comments