# Add tracking of last changed attributes. Models including this module will be able to track attribute changes like: # record.last_changed[:backup_created] #=> timestamp or nil # record.last_changed.backup_created #=> timestamp or nil module Dunlop::AttributeChangesTracking extend ActiveSupport::Concern included do attr_accessor :attribute_change_time # add ability to synchronize changed_at time for collections has_many :last_attribute_changes, as: :target, class_name: 'Dunlop::LastAttributeChange' after_update :update_last_attribute_changed_at end def update_last_attribute_changed_at changed_at = attribute_change_time || Time.now (saved_changes.keys - self.class.ignore_attributes_for_last_change).each do |attr| if existing = last_attribute_changes.find{|changed| changed.attribute_name == attr } existing.update(changed_at: changed_at) else last_attribute_changes.create(changed_at: changed_at, attribute_name: attr) end end end def last_changed @last_changed ||= LastChanged.new(self) end module ClassMethods def with_last_attribute_changes includes(:last_attribute_changes) end def ignore_attributes_for_last_change %w[id sti_type created_at updated_at notes] end end class LastChanged attr_reader :target def initialize(target) @target = target end def method_missing(m, *args) raise "#{target.class.name} has no attribute #{m}" unless target.has_attribute?(m) self[m] end def [](val) target.last_attribute_changes.find{|changed| changed.attribute_name == val.to_s }.try(:changed_at) end end end # owner_initialization.last_changed[attr]