Keeping track of attribute changes over time in Ruby

  • ruby, rails, technical

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