module Dynamoid::Dirty
Support interface of Rails’ ActiveModel::Dirty module
The reason why not just include ActiveModel::Dirty - ActiveModel::Dirty conflicts either with @attributes or attributes in different Rails versions.
Separate implementation (or copy-pasting) is the best way to avoid endless monkey-patching
Documentation: api.rubyonrails.org/v4.2/classes/ActiveModel/Dirty.html
Public Instance Methods
Handle *_changed?
for method_missing
.
person.attribute_changed?(:name) # => true person.attribute_changed?(:name, from: 'Alice') person.attribute_changed?(:name, to: 'Bob') person.attribute_changed?(:name, from: 'Alice', to: 'Bod')
@private @param name [Symbol] attribute name @param options [Hash] conditions on from
and to
value (optional) @option options [Symbol] :from previous attribute value @option options [Symbol] :to current attribute value
# File lib/dynamoid/dirty.rb, line 169 def attribute_changed?(name, options = {}) result = changes_include?(name) result &&= options[:to] == read_attribute(name) if options.key?(:to) result &&= options[:from] == changed_attributes[name] if options.key?(:from) result end
Handles *_previous_change
for method_missing
.
person = Person.create(name: 'Alice') person.name = 'Bob' person.save person.attribute_previously_changed(:name) # => ["Alice", "Bob"]
@private @param name [Symbol] @return [Array]
# File lib/dynamoid/dirty.rb, line 219 def attribute_previous_change(name) previous_changes[name] if attribute_previously_changed?(name) end
Handles *_previously_changed?
for method_missing
.
person = Person.create(name: 'Alice') person.name = 'Bob' person.save person.attribute_changed?(:name) # => true
@private @param name [Symbol] attribute name @return [true|false]
# File lib/dynamoid/dirty.rb, line 205 def attribute_previously_changed?(name) previous_changes_include?(name) end
Handle *_was
for method_missing
.
person = Person.create(name: 'Alice') person.name = 'Bob' person.attribute_was(:name) # => "Alice"
@private @param name [Symbol] attribute name
# File lib/dynamoid/dirty.rb, line 184 def attribute_was(name) attribute_changed?(name) ? changed_attributes[name] : read_attribute(name) end
Returns an array with names of the attributes with unsaved changes.
person = Person.new person.changed # => [] person.name = 'Bob' person.changed # => ["name"]
@return [Array]
# File lib/dynamoid/dirty.rb, line 98 def changed changed_attributes.keys end
Returns true
if any attribute have unsaved changes, false
otherwise.
person.changed? # => false person.name = 'Bob' person.changed? # => true
@return [true|false]
# File lib/dynamoid/dirty.rb, line 86 def changed? changed_attributes.present? end
Returns a hash of the attributes with unsaved changes indicating their original values like attr => original value
.
person.name # => "Bob" person.name = 'Robert' person.changed_attributes # => {"name" => "Bob"}
@return [ActiveSupport::HashWithIndifferentAccess]
# File lib/dynamoid/dirty.rb, line 134 def changed_attributes @changed_attributes ||= ActiveSupport::HashWithIndifferentAccess.new end
Returns a hash of changed attributes indicating their original and new values like attr => [original value, new value]
.
person.changes # => {} person.name = 'Bob' person.changes # => { "name" => ["Bill", "Bob"] }
@return [ActiveSupport::HashWithIndifferentAccess]
# File lib/dynamoid/dirty.rb, line 110 def changes ActiveSupport::HashWithIndifferentAccess[changed.map { |name| [name, attribute_change(name)] }] end
Clears dirty data and moves changes
to previous_changes
.
# File lib/dynamoid/dirty.rb, line 145 def changes_applied @previously_changed = changes @changed_attributes = ActiveSupport::HashWithIndifferentAccess.new end
Remove changes information for the provided attributes.
@param attributes [Array] - a list of attributes to clear changes for
# File lib/dynamoid/dirty.rb, line 153 def clear_attribute_changes(names) attributes_changed_by_setter.except!(*names) end
Clear all dirty data: current changes and previous changes.
# File lib/dynamoid/dirty.rb, line 139 def clear_changes_information @previously_changed = ActiveSupport::HashWithIndifferentAccess.new @changed_attributes = ActiveSupport::HashWithIndifferentAccess.new end
Returns a hash of attributes that were changed before the model was saved.
person.name # => "Bob" person.name = 'Robert' person.save person.previous_changes # => {"name" => ["Bob", "Robert"]}
@return [ActiveSupport::HashWithIndifferentAccess]
# File lib/dynamoid/dirty.rb, line 122 def previous_changes @previously_changed ||= ActiveSupport::HashWithIndifferentAccess.new end
@private
# File lib/dynamoid/dirty.rb, line 73 def reload(*) super.tap do clear_changes_information end end
Restore all previous data of the provided attributes.
@param attributes [Array] a list of attribute names
# File lib/dynamoid/dirty.rb, line 191 def restore_attributes(names = changed) names.each { |name| restore_attribute! name } end
@private
# File lib/dynamoid/dirty.rb, line 45 def save(*) super.tap do |status| changes_applied if status end end
@private
# File lib/dynamoid/dirty.rb, line 52 def save!(*) super.tap do changes_applied end end
@private
# File lib/dynamoid/dirty.rb, line 59 def update(*) super.tap do clear_changes_information end end
@private
# File lib/dynamoid/dirty.rb, line 66 def update!(*) super.tap do clear_changes_information end end
Private Instance Methods
Handle *_change
for method_missing
.
# File lib/dynamoid/dirty.rb, line 231 def attribute_change(name) [changed_attributes[name], read_attribute(name)] if attribute_changed?(name) end
Handle *_will_change!
for method_missing
.
# File lib/dynamoid/dirty.rb, line 236 def attribute_will_change!(name) return if attribute_changed?(name) begin value = read_attribute(name) value = value.duplicable? ? value.clone : value rescue TypeError, NoMethodError end set_attribute_was(name, value) end
This is necessary because ‘changed_attributes` might be overridden in other implemntations (e.g. in `ActiveRecord`)
# File lib/dynamoid/dirty.rb, line 225 def changes_include?(name) attributes_changed_by_setter.include?(name) end
Returns true
if name were changed before the model was saved, false
otherwise.
# File lib/dynamoid/dirty.rb, line 258 def previous_changes_include?(name) previous_changes.include?(name) end
Handle restore_*!
for method_missing
.
# File lib/dynamoid/dirty.rb, line 249 def restore_attribute!(name) if attribute_changed?(name) write_attribute(name, changed_attributes[name]) clear_attribute_changes([name]) end end
Force an attribute to have a particular “before” value
# File lib/dynamoid/dirty.rb, line 267 def set_attribute_was(name, old_value) attributes_changed_by_setter[name] = old_value end