Provides a way to track changes in your records.
my_book = Book['bookid'] my_book.changed? #=> false my_book.title #=> "My Book" my_book.title = "My Awesome Book" my_book.changed? #=> true
You can inspect further and get a list of changed attributes
my_book.changed #=> ['title']
Or you can get a more detailed description of the changes. {#changes} returns a hash of changed attributes (keys) with their old and new values.
my_book.changes #=> { 'title' => ['My Book', 'My Awesome Book']
For every configured attribute you also get a handful of methods for inspecting changes on that attribute. Given the following attribute:
string_attr :title
You can now call any of the following methods:
* title_changed? * title_change * title_was * reset_title! * title_will_change!
Given the title change from above:
my_book.title_changed? #=> true my_book.title_change #=> ['My Book', 'My Awesome Book'] my_book.title_was #=> ['My Book'] my_book.reset_title! my_book.title #=> 'My Book'
Dirty tracking works by comparing incoming attribute values upon assignment against the value that was there previously. If you use functions against the value that modify it (like gsub!) you must notify your record about the coming change.
my_book.title #=> 'My Book' my_book.title_will_change! my_book.title.gsub!(/My/, 'Your') my_book.title_change #=> ['My Book', 'Your Book']
Dirty tracking makes it possible to only persist those attributes that have changed since they were loaded. This speeds up requests against AWS when saving data.
Returns an array of attribute names that have changes.
book.changed #=> [] person.title = 'New Title' book.changed #=> ['title']
@return [Array] Returns an array of attribute names that have
unsaved changes.
# File lib/aws/record/dirty_tracking.rb, line 108 def changed orig_values.keys end
Returns true if this model has unsaved changes.
b = Book.new(:title => 'My Book') b.changed? #=> true
New objects and objects freshly loaded should not have any changes:
b = Book.new b.changed? #=> false b = Book.first b.changed? #=> false
@return [Boolean] Returns true if any of the attributes have
unsaved changes.
# File lib/aws/record/dirty_tracking.rb, line 96 def changed? !orig_values.empty? end
Returns the changed attributes in a hash. Keys are attribute names, values are two value arrays. The first value is the previous attribute value, the second is the current attribute value.
book.title = 'New Title' book.changes #=> { 'title' => ['Old Title', 'New Title'] }
@return [Hash] Returns a hash of attribute changes.
# File lib/aws/record/dirty_tracking.rb, line 121 def changes changed.inject({}) do |changes, attr_name| changes[attr_name] = attribute_change(attr_name) changes end end
Returns an array of the old value and the new value for attributes that have unsaved changes, returns nil otherwise.
This is an attribute method. The following two expressions are equivilent:
book.title_change book.attribute_change(:title)
@example Asking for changes on an unchanged attribute
book = Book.new book.title_change #=> nil
@example Getting changed attributes on a new object
book = Book.new(:title => 'My Book') book.title_change #=> [nil, 'My Book']
@example Getting changed attributes on a loaded object
book = Book.first book.title = 'New Title' book.title_change #=> ['Old Title', 'New Title']
@param [String] attribute_name Name of the attribute to fetch
a change for.
@return [Boolean] Returns true if the named attribute
has unsaved changes.
@private
# File lib/aws/record/dirty_tracking.rb, line 178 def attribute_change attribute_name self.class.attribute_for(attribute_name) do |attribute| if orig_values.has_key?(attribute.name) [orig_values[attribute.name], __send__(attribute.name)] else nil end end end
Returns true if the named attribute has unsaved changes.
This is an attribute method. The following two expressions are equivilent:
book.title_changed? book.attribute_changed?(:title)
@param [String] attribute_name Name of the attribute to check
for changes.
@return [Boolean] Returns true if the named attribute
has unsaved changes.
@private
# File lib/aws/record/dirty_tracking.rb, line 143 def attribute_changed? attribute_name orig_values.keys.include?(attribute_name) end
Returns the previous value for changed attributes, or the current value for unchanged attributes.
This is an attribute method. The following two expressions are equivilent:
book.title_was book.attribute_was(:title)
@example Returns the previous value for changed attributes:
book = Book.where(:title => 'My Book').first book.title = 'New Title' book.title_was #=> 'My Book'
@example Returns the current value for unchanged attributes:
book = Book.where(:title => 'My Book').first book.title_was #=> 'My Book'
@return Returns the previous value for changed attributes
or the current value for unchanged attributes.
@private
# File lib/aws/record/dirty_tracking.rb, line 212 def attribute_was attribute_name self.class.attribute_for(attribute_name) do |attribute| name = attribute.name orig_values.has_key?(name) ? orig_values[name] : __send__(name) end end
Indicate to the record that you are about to edit an attribute in place. @param [String] attribute_name Name of the attribute that will
be changed.
@return [nil] @private
# File lib/aws/record/dirty_tracking.rb, line 236 def attribute_will_change! attribute_name self.class.attribute_for(attribute_name) do |attribute| name = attribute.name unless orig_values.has_key?(name) was = __send__(name) begin # booleans, nil, etc all #respond_to?(:clone), but they raise # a TypeError when you attempt to dup them. orig_values[name] = was.clone rescue TypeError orig_values[name] = was end end end nil end
# File lib/aws/record/dirty_tracking.rb, line 259 def clear_change! attribute_name orig_values.delete(attribute_name) end
# File lib/aws/record/dirty_tracking.rb, line 279 def clear_changes! orig_values.clear end
# File lib/aws/record/dirty_tracking.rb, line 274 def if_tracking_changes &block yield unless @_ignore_changes end
# File lib/aws/record/dirty_tracking.rb, line 264 def ignore_changes &block begin @_ignore_changes = true yield ensure @_ignore_changes = false end end
# File lib/aws/record/dirty_tracking.rb, line 254 def orig_values @_orig_values ||= {} end
Reverts any changes to the attribute, restoring its original value. @param [String] attribute_name Name of the attribute to reset. @return [nil] @private
# File lib/aws/record/dirty_tracking.rb, line 224 def reset_attribute! attribute_name __send__("#{attribute_name}=", attribute_was(attribute_name)) nil end