Git Product home page Git Product logo

history_tracker's Introduction

HistoryTracker Build Status Code Climate Dependency Status Coverage Status

HistoryTracker is inspired by mongoid-history and audited. HistoryTracker tracks historical changes for any active record models, including its associations, and stores in MongoDB. It achieves this by storing all history tracks in a single collection that you define. Association models are referenced by storing an association path, which is an array of model_name and model_id fields starting from the top most parent and down to the assoication that should track history.

Installation

This gem depends on ActiveRecord 3.x/4.x and Mongoid 3.x/4x.

gem 'history_tracker', github: 'yoolk/history_tracker'

Usage

Tracker class name

By default, an active record model will have history_tracker_class pointed to eg. ListingHistoryTracker.

# app/models/listing.rb
class Listing < ActiveRecord::Base
  track_history
end

>> Listing.history_tracker_class # => ListingHistoryTracker

However, you can specify the history class name with :class_name options. All histories related to this model are stored in this tracker class.

# app/models/listing.rb
class Listing < ActiveRecord::Base
  track_history class_name: 'Listing::HistoryTracker'
end

# app/models/listing/history_tracker.rb
class Listing::HistoryTracker
  include HistoryTracker::Mongoid::Tracker
end

>> Listing.history_tracker_class # => Listing::HistoryTracker

#current_user method name

By default, this gem will invoke current_user method and save its attributes on each change. However, you can change it by sets the current_user_method and current_user_fields using a Rails initializer.

# config/initializers/history_tracker.rb
HistoryTracker.current_user_method = :authenticated_user

# Assume that authenticated_user returns #<User id: 1, email: '[email protected]'>
>> listing = Listing.first
>> listing.update_attributes!(name: 'New Name')

>> listing.history_tracks.last.modifier_id #=> 1

Simple Model

HistoryTracker is simple to use. Just call track_history to a model to track changes on every create, update, and destroy.

# app/models/listing.rb
class Listing < ActiveRecord::Base

  track_history   class_name:     'ListingHistoryTracker'          # specify the tracker class name, default is the newly mongoid class with "HistoryTracker" suffix
                  only:           [:name],                         # track only the specified fields
                  except:         [],                              # track all fields except the specified fields
                  on:             [:create, :update, :destroy],    # by default, it tracks all events
                  changes_method: :changes,                        # alternate changes method
                  parent:         nil,                             # it's for nested relation
                  inverse_of:     nil
end

This gives you a history_tracks method which returns historical changes to your model.

# Assume that current_user returns #<User id: 1, email: '[email protected]'>
>> listing = Listing.create(name: 'Listing 1')
>> track = listing.history_tracks.last
>> track.action       #=> create
>> track.modifier_id  #=> 1
>> track.original     #=> {}
>> track.modified     #=> {"name": "Listing 1"}

>> listing.update_attributes(name: 'New Listing 1')
>> track = listing.history_tracks.last
>> track.action       #=> update
>> track.modifier     #=> 1
>> track.original     #=> {"id" => 1, "name" => "Listing 1", "created_at"=>2013-03-12 06:25:51 UTC, "updated_at"=>2013-03-12 06:44:37 UTC}
>> track.modified     #=> {"name" => "New Listing 1"}

>> listing.destroy
>> track = listing.history_tracks.last
>> track.action     #=> destroy
>> track.modifier   #=> 1
>> track.original   #=> {"id" => 1, "name" => "Listing 1", "created_at"=>2013-03-12 06:25:51 UTC, "updated_at"=>2013-03-12 06:44:37 UTC}
>> track.modified   #=> {}

Examples

# app/models/location.rb
class Location < ActiveRecord::Base
end

# app/models/listing.rb
class Listing < ActiveRecord::Base
  belongs_to :location
  has_many   :comments, dependent: :destroy

  track_history
end

# app/models/comment.rb
class Comment < ActiveRecord::Base
  belongs_to :listing

  track_history  class_name: 'Listing::History'
end

>> phnom_penh = Location.create(name: 'Phnom Penh')
>> siem_reap  = Location.create(name: 'Siem Reap')
>> listing = Listing.create(name: 'Listing 1', location: phnom_penh)
>> comment = listing.comments.create(body: 'Good listing')

>> comment.history_tracks.count #=> 1
>> listing.history_tracks.count #=> 2, including :comments

>> listing.update_attributes(location: siem_reap)
>> track = listing.history_tracks.last
>> track.original  # {"id" => 1, "name" => "Listing 1", "created_at"=>2013-03-12 06:25:51 UTC, "updated_at"=>2013-03-12 06:44:37 UTC, "location"=>{"id"=>1, "name"=>"Phnom Penh"}}
>> track.modified  # {"location"=>{"id"=>2, "name"=>"Siem Reap"}}

Enable/Disable Tracking

Sometimes you don't want to store changes. Perhaps you are only interested in changes made by your users and don't need to store changes you make yourself in, say, a migration -- or when testing your application.

You can enable or disable tracking in three ways: globally, per class, or per method call.

Globally

On a global level you can disable tracking like this:

>> HistoryTracker.enabled = false

For example, you might want to disable tracking in your Rails application's test environment to speed up your tests. This will do it:

# in config/environments/test.rb
config.after_initialize do
  HistoryTracker.enabled = false
end

If you want to disable tracking inside rails console or rake script, add this:

if defined?(Rails::Console) or File.basename($0) == "rake"
  HistoryTracker.enabled = false
end

Per class

If you are about change some widgets and you don't want to track your changes, you can disable/enable tracking like this:

>> Listing.disable_tracking
>> Listing.enable_tracking

Per method call

You can call a method without tracking changes using without_tracking. It takes either a method name as a symbol:

@listing.without_tracking(:destroy)

Or a block:

@listing.without_tracking do
  @listing.update_attributes :name => 'New Listing 1'
end

Rails Controller

If your ApplicationController has a current_user method, HistoryTracker will invoke this method and store in the modifier field. Note that this column is a hash.

You may want HistoryTracker to call a different method to find out who is responsible. To do so, override the user_for_history_tracker method in your controller like this:

class ApplicationController
  def user_for_history_tracker
    logged_in? ? current_member : {}  # or whatever
  end
end

You may want to disable HistoryTracker in some controllers. To do that, override the set_history_tracker_enabled_for_controller method in your controller like this:

class ListingController
  def set_history_tracker_enabled_for_controller
    false
  end
end

It's possible to track custom operation with write_history_track!. It's good for complex relation or custom attributes.

class ListingController
  def upload_logo
    logo_url = @listing.logo_url
    if @listing.upload_logo(params)
      @portal.write_history_track!(:update, logo_url: [logo_url, @listing.logo_url])
    end
  end
end

Authors

history_tracker's People

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

history_tracker's Issues

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.