0.0
No release in over 3 years
ActionTrace glues together public_activity, ahoy_matey, paper_trail, and discard to provide a unified interface for activity tracking, visit analytics, model versioning, and soft deletes in Rails applications.
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
2025
2026
 Project Readme

ActionTrace

Gem Version

ActionTrace is a Rails engine that consolidates user interaction tracking into a single integration point. Instead of configuring public_activity, ahoy_matey, paper_trail, and discard individually, ActionTrace wires them together and exposes a unified activity log with a ready-to-use UI.

Source Description Backed by
data_create Model created public_activity
data_change Model updated public_activity + paper_trail
data_destroy Model destroyed public_activity
page_visit Controller action visited ahoy_matey
session_start User session begun ahoy_matey (visit)
session_end User logged out ahoy_matey (event)

Installation

Add to your Gemfile:

gem "action_trace"

Then run:

bundle install
rails generate action_trace:install
rails db:migrate

The installer runs the setup generators for all four underlying gems and creates config/initializers/action_trace.rb.

Skipping already-installed gems

If one or more of the underlying gems is already configured, pass --skip-* flags:

rails generate action_trace:install --skip-ahoy --skip-paper-trail
Flag Skips
--skip-ahoy ahoy:install
--skip-paper-trail paper_trail:install
--skip-public-activity public_activity:migration
--skip-discard discard initializer entry

Mount the engine

In config/routes.rb:

mount ActionTrace::Engine, at: '/action_trace'

This exposes:

GET  /action_trace/activity_logs
POST /action_trace/activity_logs/filter

Copy views and controller (optional)

ActionTrace ships minimal default views that work out of the box. Copy them into your app to customise the UI:

# Copy views only
rails generate action_trace:views

# Copy views and controller
rails generate action_trace:views --controller

Views are placed in app/views/action_trace/activity_logs/. Rails will use your copies instead of the engine defaults.

The --controller flag also copies ActivityLogsController to app/controllers/action_trace/activity_logs_controller.rb. The file includes commented-out lines for Devise and CanCanCan authentication — uncomment what applies to your setup or replace with your own auth logic.

Note: once you copy the controller, the engine's version is no longer used. Future updates to the engine's controller will not be applied automatically — keep that in mind when upgrading.


Usage

Models — tracking data changes

Include ActionTrace::DataTrackable in any ActiveRecord model you want to track:

class Document < ApplicationRecord
  include ActionTrace::DataTrackable
end

This records a public_activity event on every create, update, and destroy, linked to the current user (via PublicActivity.get_controller) and, when paper_trail is active, to the corresponding version.

For paper_trail versioning to work, the model also needs has_paper_trail:

class Document < ApplicationRecord
  include ActionTrace::DataTrackable
  has_paper_trail
end

For soft-delete tracking with discard, add include Discard::Model alongside DataTrackable. The data_destroy event is still recorded via the before_destroy callback.

Controllers — tracking page visits and sessions

Include ActivityTrackable in any controller (or ApplicationController) to track page visits:

class ApplicationController < ActionController::Base
  include ActivityTrackable
end

This adds an after_action :track_action that records a page_visit event via Ahoy for every successful request made by a logged-in user. It also includes PublicActivity::StoreController, which makes the current controller available to model callbacks so that data events can be linked to the right user.

To skip tracking on a specific controller that inherits from ApplicationController:

class HealthChecksController < ApplicationController
  skip_after_action :track_action
end

To record a session end on logout, call track_session_end before clearing the session:

class SessionsController < Devise::SessionsController
  def destroy
    track_session_end
    super
  end
end

The engine's ActivityLogsController inherits from the host app's ApplicationController. Authentication and authorization are not enforced by default — copy the controller with the generator and uncomment the relevant lines for your setup (e.g. Devise's authenticate_user!, CanCanCan's load_and_authorize_resource).

Querying activity logs directly

Use ActionTrace::FetchActivityLogs to fetch and paginate the unified activity log programmatically:

result = ActionTrace::FetchActivityLogs.call(
  current_user: current_user,
  filters: {
    'source'     => 'data_change',  # optional — one of the sources listed above
    'company_id' => 5,              # optional — overrides current_user.company_id
    'user_id'    => 12,             # optional
    'start_date' => '2026-01-01',   # optional — YYYY-MM-DD
    'end_date'   => '2026-03-31'    # optional — YYYY-MM-DD
  },
  range: 0  # offset for pagination (increments of 50)
)

result.activity_logs  # => Array of ActionTrace::ActivityLog
result.total_count    # => Integer

Each ActionTrace::ActivityLog exposes:

Attribute Type Description
id String Prefixed ID e.g. act_42, visit_7, evt_3
source String One of the sources in the table above
occurred_at DateTime When the event happened
user String Display name of the user
subject String Human-readable description
details Hash Raw event payload
paper_trail_version PaperTrail::Version Associated version (data events only)
trackable ActiveRecord object The changed record (data events only)
trackable_type String Class name of the changed record

Presenter helpers are also available on each log:

log.icon           # => 'fas fa-pencil-alt'
log.color          # => 'text-primary'
log.data_change?   # => true / false
log.page_visit?    # => true / false
# data_create?, data_destroy?, session_start?, session_end?

Configuration

config/initializers/action_trace.rb is generated automatically. Available options:

ActionTrace.configure do |config|
  # Controller names to exclude from page_visit tracking (default: [])
  config.excluded_controllers = %w[health_checks status]

  # Action names to exclude from page_visit tracking (default: [])
  config.excluded_actions = %w[ping]

  # The user model class name used to resolve company filtering (default: 'User')
  config.user_class = 'User'

  # How long to retain activity records before purging (default: 1.year)
  config.log_retention_period = 6.months
end

user_class must have a company_id column. ActionTrace uses it to filter activity records by company (since Ahoy and PublicActivity store the user reference rather than a direct company_id).

Purging old records

ActionTrace::PurgeActivityLogJob removes all PublicActivity::Activity, Ahoy::Event, and Ahoy::Visit records older than log_retention_period (default: 1 year). Schedule it with your preferred job scheduler:

# e.g. with whenever or Sidekiq-cron
ActionTrace::PurgeActivityLogJob.perform_later

License

The gem is available as open source under the terms of the MIT License.