lib/virtus/dirty_attribute.rb
require_relative 'dirty_attribute/session'
# @source: https://github.com/ahawkins/virtus-dirty_attribute
#
# The above gem works great for the majority of Virtus use cases, but is
# not activly maintained.
#
# Here is a diff of the changes that have been made.
# https://gist.github.com/forest/40d3244acb00bb7a0322
#
# We use instance_variable_get instead of the attribute getter
# method to get the original value. This is because in TrackerApi we
# often override the attribute getter to implement lazy loading of
# associated data from the API (e.g. Project#epics). Making an API
# request just get the original value is not what we want. Another thing
# that must be done is being careful to mark the Resource as clean
# when new data is loaded from the server (e.g. Endpoints::Epic#update).
module Virtus
# == Dirty Tracking
#
# Dirty Tracking is an optional module that you include only if you need it.
module DirtyAttribute
module ClassMethods
def attribute(name, type, options = {})
_create_writer_with_dirty_tracking(name)
super
end
private
def _create_writer_with_dirty_tracking(name)
class_eval <<-RUBY, __FILE__, __LINE__ + 1
def #{name}=(new_regular_object)
prev_object = instance_variable_get(:@#{name})
new_virtus_object = super
if attribute_dirty?(:#{name}) && original_attributes[:#{name}] == new_virtus_object
attribute_clean!(:#{name})
elsif prev_object != new_virtus_object
unless original_attributes.key?(:#{name})
original_attributes[:#{name}] = prev_object
end
attribute_dirty!(:#{name}, new_regular_object)
end
new_virtus_object
end
RUBY
end
end
module InitiallyClean
def initialize(*args)
super(*args)
clean!
end
end
def self.included(base)
base.extend ClassMethods
end
def dirty?
dirty_session.dirty?
end
def clean?
!dirty?
end
def attribute_dirty?(name, options = {})
result = dirty_session.dirty?(name)
result &&= options[:to] == dirty_attributes[name] if options.key?(:to)
result &&= options[:from] == original_attributes[name] if options.key?(:from)
result
end
def clean!
dirty_session.clean!
end
def dirty_attributes
dirty_session.dirty_attributes
end
def original_attributes
dirty_session.original_attributes
end
def attribute_dirty!(name, value)
dirty_session.dirty!(name, value)
end
def attribute_clean!(name)
dirty_session.attribute_clean!(name)
end
private
def dirty_session
@_dirty_session ||= Session.new(self)
end
end
end