Skip to content

Instantly share code, notes, and snippets.

@kares
Created March 31, 2010 13:46
Show Gist options
  • Save kares/350326 to your computer and use it in GitHub Desktop.
Save kares/350326 to your computer and use it in GitHub Desktop.
ActiveRecord::Dirty memoized
# Extension of the ActiveRecord's Dirty module to enable
# tracking changes even after the record has been saved
# (as ActiveRecord's dirty changes are emptied on save).
#
# User.send :include, DirtyMemento
#
# user = User.find_by_name 'kares'
#
# assert ! user.name_changed?
# assert ! user.name_previously_changed?
# user.name = 'kares7'
# assert user.name_changed?
# assert ! user.name_previously_changed?
# user.save
# assert ! user.name_changed?
# assert user.name_previously_changed?
#
module DirtyMemento
def self.included(base)
base.attribute_method_suffix '_previously_changed?', '_was_previously'
base.alias_method_chain :save, :dirty_memento
base.alias_method_chain :save!, :dirty_memento
base.alias_method_chain :update, :dirty_memento
base.alias_method_chain :reload, :dirty_memento
end
# Do any attributes have unsaved changes?
# person.previously_changed? # => false
def previously_changed?
! previously_changed_attributes.empty?
end
# List of attributes with unsaved changes.
# person.previously_changed # => ['name']
def previously_changed
previously_changed_attributes.keys
end
def save_with_dirty_memento(*args) #:nodoc:
set_previously_changed_attributes
save_without_dirty_memento(*args)
end
def save_with_dirty_memento!(*args) #:nodoc:
set_previously_changed_attributes
save_without_dirty_memento!(*args)
end
def update_with_dirty_memento(*args) #:nodoc:
set_previously_changed_attributes
update_without_dirty_memento(*args)
end
def reload_with_dirty_memento(*args) #:nodoc:
set_previously_changed_attributes
reload_without_dirty_memento(*args)
end
private
# Map of change attr => original value.
def previously_changed_attributes
@_previously_changed_attributes ||= {}
end
def set_previously_changed_attributes
@_previously_changed_attributes = changed_attributes.clone
end
# Handle *_previously_changed? for method_missing.
def attribute_previously_changed?(attr)
previously_changed_attributes.include?(attr)
end
# Handle *_was_previously for method_missing.
def attribute_was_previously(attr)
attribute_previously_changed?(attr) ? previously_changed_attributes[attr] : __send__(attr)
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment