Track the Activity History of Your Embedded Mongoid 3 Documents with the mongoid-history Gem

Recently on my Rails 3 project, we had to keep track of all the updates made to our mongoid documents. There are multiple gems out there to help with this, but the best ones were only compatible with Mongoid 4 (and Rails 4), not functioning with embedded documents, or only recording that something was updated without keeping track of the previous values. We had to settle for the most basic gem for the job: the mongoid-history gem. The biggest struggle was figuring out how to get the gem to keep track of history of embedded documents. This is why I would like to share the solution.

To set up history tracking for your embedded (and the embedders), follow the these steps:

  1. Add the following to your Gemfile:

    gem 'mongoid-history', '~> 0.4'
    gem 'mongoid_userstamp', '~> 0.4'
    

    The mongoid_userstamp gem is for letting mongoid-history track the users who made the changes.

  2. Run bundle install in the command line to install your gems.

  3. Create an initializer under config/initializers called mongoid_history.rb and add the following to it:

    Mongoid::History.tracker_class_name = :history_tracker
    Mongoid::History.current_user_method = :current_user
    
    Rails.env == 'development' and require_dependency(Mongoid::History.tracker_class_name.to_s)
    

    The reason you must add that last line about requiring the history track dependency, is because the development environment doesn't necessarily load all of the classes; you must make sure the history tracker gets loaded. And with Mongoid::History.current_user_method you're letting the mongoid_userstamp know where to get the user for the change. In this case, I'm using Devise in my app, so the current_user method will do the job.

  4. Add the tracker to your parent model, and setup its children (the embedded documents) to get tracked as well:

    class Parent
      include Mongoid::Document
      include Mongoid::History::Trackable
    
      field :name, type: String
    
      embeds_many :children, cascade_callbacks: true
      accepts_nested_attributes_for :children
    
      track_history on: [:name]
    end
    
  5. Add the tracker to your child model:

    class Child
      include Mongoid::Document
      include Mongoid::History::Trackable
    
      field :name, type: String
    
      embedded_in :parent
    
      track_history 
    end
    
  6. Now try updating a parent instance's name, then go to your console and you should be able to view that parent's update history with parent.history_tracks.to_a.

  7. Next, update a child instance's name, and you should be able to view that child's update history through its parent with child.history_tracks.to_a.