Created
September 28, 2010 09:18
-
-
Save sumskyi/600667 to your computer and use it in GitHub Desktop.
model change tracker
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# Usage: | |
# | |
# class SomeModel < ActiveRecord::Base | |
# include ModelChange::Tracker | |
# will_track_changes_of :field_1, :field_2, ... field_n | |
# end | |
# | |
# Now, if we update a record, it will generate a new ModelChange record for every column (field_1, field_2...) that has changed. | |
# | |
# Also it will add a has_many relationship between SomeModel and ModelChange, so we can now use | |
# some_model.model_changes to get a list of changes in this particular object | |
# | |
# Additionalyly, it adds two new methods for each tracked column: has_column_changes? and column_changes, wich are self-explanatory I guess. | |
# They work like ActiveRecord::Dirty but for saved records on db, not 'on the fly changes' that are not yet commited to db. | |
# | |
class ModelChange < ActiveRecord::Base | |
belongs_to :object, :polymorphic => true | |
named_scope :on_attribute, lambda {|attribute| { :conditions => { :attribute => attribute }}} | |
module Tracker | |
def self.included(base) | |
base.send(:extend, ClassMethods) | |
base.send(:after_update, :check_for_model_change) | |
end | |
def check_for_model_change | |
self.class.read_inheritable_attribute(:fields_to_check_for_changes).each do |field| | |
if changes.keys.include?(field) | |
self.model_changes.create!(:attribute => field, :old_value => changes[field].first, :new_value => changes[field].last) | |
changes.delete(field) rescue nil | |
end | |
end | |
end | |
module ClassMethods | |
def will_track_changes_of(*fields) | |
fields_to_track = [fields].flatten.compact.map(&:to_s) | |
write_inheritable_attribute :fields_to_check_for_changes, fields_to_track | |
has_many :model_changes, :as => :object, :dependent => :destroy, :order => 'id ASC' | |
changes_module = Module.new | |
fields_to_track.each do |field_name| | |
changes_module.module_eval <<-EOF | |
def has_#{field_name}_changes? | |
model_changes.on_attribute('#{field_name}').count > 0 | |
end | |
def #{field_name}_changes | |
model_changes.on_attribute('#{field_name}').all(:order => 'created_at ASC') | |
end | |
def #{field_name}_restore | |
if last_row = model_changes.on_attribute('#{field_name}').last | |
self.#{field_name} = last_row.old_value | |
end | |
#rescue | |
end | |
def #{field_name}_clear | |
model_changes.reload.on_attribute('#{field_name}').each {|r| r.destroy } | |
end | |
EOF | |
end | |
include changes_module | |
end | |
end | |
end | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment