Keeping track of attribute changes over time in Ruby
For a recent project, we wanted to send a daily email with the recent changes to certain records. It was wanted by email so that they had an email trail of all changes of interest. It could have been a full blown web based thing but this gave us the opportunity to keep it simple.
The approach
There was no need for persistent record of the changes. So the plan was to store a snapshot of the data we’re interested in and work out the diff.
It certainly has limitations such as no being able to quickly find out which records had been changed, but it worked nicely for us.
Storing the current state
We serialised a hash of the interesting attributes and stored it.
Every night, we ran a background job which would diff the stored hash with the current attributes. The result would be a hash of all the relevant changes.
Diffing a hash in Ruby
The hash diff function was removed in Rails 4.1. I needed something simple and this solution from SO provided what I needed.
class Hash
def diff(other)
(self.keys + other.keys).uniq.inject({}) do |memo, key|
if self[key] != other[key] && self[key].to_s != other[key].to_s
if self[key].kind_of?(Hash) && other[key].kind_of?(Hash)
memo[key] = self[key].diff(other[key].to_s)
else
memo[key] = [self[key], other[key].to_s]
end
end
memo
end
end
end