Last active
December 5, 2018 12:36
-
-
Save ryenski/50a09f09e6cc2cc3d7d102fec0b71cd6 to your computer and use it in GitHub Desktop.
Audit trail activity tracker, similar to PaperTrail, but without undo.
This file contains hidden or 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
# == Schema Information | |
# | |
# Table name: activities | |
# | |
# id :uuid not null, primary key | |
# user_id :uuid | |
# tenant_id :uuid | |
# trackable_type :string | |
# trackable_id :uuid | |
# action :string | |
# tracked_changes :json | |
# detail :string | |
# visibility :integer default("report") | |
# created_at :datetime not null | |
# updated_at :datetime not null | |
# | |
class Activity < ApplicationRecord | |
belongs_to :tenant | |
belongs_to :user # who did it | |
belongs_to :trackable, -> { unscope(where: :trashed_at) }, polymorphic: true # the tracked object | |
scope :archived, -> {where(action: 'archived')} | |
scope :archived_or_trashed, -> {where(action: %w(archived trashed))} | |
store_accessor :tracked_changes | |
scope :created, -> {where(action: 'create')} | |
after_initialize :set_defaults | |
def set_defaults | |
if self.new_record? | |
self.tenant_id ||= Current.tenant_id | |
self.user_id ||= Current.user_id | |
end | |
end | |
# visibility | |
# * report: (default) Only shows up in system reports (e.g. login activity, etc. ) | |
# * member: Only the member can see | |
# * members_only: (default) Only logged in members can see | |
# * everyone: anyone can see, logged in or not | |
enum visibility: [:report, :member, :members_only, :everyone] | |
def summary | |
[action, trackable_type].join(' ') | |
end | |
alias_method :to_s, :summary | |
end |
This file contains hidden or 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
class ActivityCreator | |
def initialize(action, trackable, comment=nil) | |
@trackable = trackable # the affected object | |
@action = action # what was done | |
@comment = comment | |
@changes = collect_changes | |
end | |
def call | |
attrs = { | |
tenant_id: Current.tenant_id, | |
user_id: Current.user_id, | |
trackable: trackable, | |
action: action, | |
tracked_changes: changes | |
} | |
# trackable.run_callbacks(:track) { self.activities.create(attrs) } | |
unless changes.empty? && action == 'update' | |
Activity.create!(attrs) | |
end | |
end | |
attr_accessor :user, :action, :trackable, :comment, :changes | |
private | |
IGNORE_ATTRS = [ | |
:created_at, | |
:password_digest, | |
:registration_token, | |
:auth_token, | |
:tenant_id, | |
:updated_at, | |
] | |
# Collect & flatten out custom field attributes so we can treat them as if they were attributes on this object. | |
CUSTOM_FIELD_ATTRS = CustomField.field_types.collect{|k,v| "value_#{k}"} | |
def collect_custom_fields(changes) | |
if trackable.respond_to?(:custom_field_values) | |
for cfv in trackable.custom_field_values | |
if cfv.previous_changes.any? | |
changes.update("#{cfv.name}" => cfv.previous_changes.detect{|k,v| CUSTOM_FIELD_ATTRS.include?(k) }.try('[]', 1)) | |
end | |
end | |
end | |
return changes | |
end | |
def collect_referenced_objects(changes) | |
if values = changes.delete("plan_id") | |
from = Plan.where(id: values[0]).first.try(:to_param) | |
to = Plan.where(id: values[1]).first.try(:to_param) | |
changes["plan"] = [from, to] | |
end | |
return changes | |
end | |
def remove_empty(changes) | |
changes.delete_if{|k,v| v[0].blank? and v[1].blank?} | |
end | |
def collect_changes | |
if action == 'create' | |
IGNORE_ATTRS.push(:id) | |
end | |
changes = trackable.previous_changes.except(*IGNORE_ATTRS) | |
changes = collect_custom_fields(changes) | |
changes = collect_referenced_objects(changes) | |
changes = remove_empty(changes) | |
changes = changes | |
end | |
end |
This file contains hidden or 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
class Message < ApplicationRecord | |
# ... | |
include Trackable | |
# ... | |
end |
This file contains hidden or 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
module Trackable | |
extend ActiveSupport::Concern | |
included do | |
has_many :activities, -> {order("created_at DESC")}, as: :trackable, dependent: :nullify | |
after_commit :track_activity | |
before_destroy :track_destroy | |
end | |
def track_destroy | |
ActivityCreator.new('destroy', self).call | |
end | |
def track_activity | |
action = previous_changes.include?('id') ? 'create' : 'update' | |
ActivityCreator.new(action, self).call | |
end | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment