{"id":49666849,"url":"https://github.com/engim-eu/action_trace","last_synced_at":"2026-05-06T17:04:41.556Z","repository":{"id":347299962,"uuid":"1191854164","full_name":"Engim-eu/action_trace","owner":"Engim-eu","description":"ActionTrace is a Rails engine that consolidates user interaction tracking into a single integration point","archived":false,"fork":false,"pushed_at":"2026-04-14T15:30:34.000Z","size":147,"stargazers_count":0,"open_issues_count":3,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-04-14T17:23:36.148Z","etag":null,"topics":["ruby","ruby-on-rails","user-interaction"],"latest_commit_sha":null,"homepage":"","language":"Ruby","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Engim-eu.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"MIT-LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-03-25T16:44:36.000Z","updated_at":"2026-04-14T15:30:38.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/Engim-eu/action_trace","commit_stats":null,"previous_names":["engim-eu/action_trace"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/Engim-eu/action_trace","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Engim-eu%2Faction_trace","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Engim-eu%2Faction_trace/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Engim-eu%2Faction_trace/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Engim-eu%2Faction_trace/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Engim-eu","download_url":"https://codeload.github.com/Engim-eu/action_trace/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Engim-eu%2Faction_trace/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":32703533,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-06T08:33:17.875Z","status":"ssl_error","status_checked_at":"2026-05-06T08:33:17.221Z","response_time":117,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.6:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["ruby","ruby-on-rails","user-interaction"],"created_at":"2026-05-06T17:04:31.718Z","updated_at":"2026-05-06T17:04:41.543Z","avatar_url":"https://github.com/Engim-eu.png","language":"Ruby","funding_links":[],"categories":[],"sub_categories":[],"readme":"# ActionTrace\n\n[![Gem Version](https://badge.fury.io/rb/action_trace.svg)](https://rubygems.org/gems/action_trace)\n\nActionTrace is a Rails engine that consolidates user interaction tracking into a single integration point. Instead of configuring [public_activity](https://github.com/chaps-io/public_activity), [ahoy_matey](https://github.com/ankane/ahoy), [paper_trail](https://github.com/paper-trail-gem/paper_trail), and [discard](https://github.com/jhawthorn/discard) individually, ActionTrace wires them together and exposes a unified activity log with a ready-to-use UI.\n\n| Source | Description | Backed by |\n|---|---|---|\n| `data_create` | Model created | public_activity |\n| `data_change` | Model updated | public_activity + paper_trail |\n| `data_destroy` | Model destroyed | public_activity |\n| `page_visit` | Controller action visited | ahoy_matey |\n| `session_start` | User session begun | ahoy_matey (visit) |\n| `session_end` | User logged out | ahoy_matey (event) |\n\n---\n\n## Installation\n\nAdd to your Gemfile:\n\n```ruby\ngem \"action_trace\"\n```\n\nThen run:\n\n```bash\nbundle install\nrails generate action_trace:install\nrails db:migrate\n```\n\nThe installer runs the setup generators for all four underlying gems and creates `config/initializers/action_trace.rb`.\n\n### Skipping already-installed gems\n\nIf one or more of the underlying gems is already configured, pass `--skip-*` flags:\n\n```bash\nrails generate action_trace:install --skip-ahoy --skip-paper-trail\n```\n\n| Flag | Skips |\n|---|---|\n| `--skip-ahoy` | `ahoy:install` |\n| `--skip-paper-trail` | `paper_trail:install` |\n| `--skip-public-activity` | `public_activity:migration` |\n| `--skip-discard` | discard initializer entry |\n\n### Mount the engine\n\nIn `config/routes.rb`:\n\n```ruby\nmount ActionTrace::Engine, at: '/action_trace'\n```\n\nThis exposes:\n\n```\nGET  /action_trace/activity_logs\nPOST /action_trace/activity_logs/filter\n```\n\n### Copy views and controller (optional)\n\nActionTrace ships minimal default views that work out of the box. Copy them into your app to customise the UI:\n\n```bash\n# Copy views only\nrails generate action_trace:views\n\n# Copy views and controller\nrails generate action_trace:views --controller\n```\n\nViews are placed in `app/views/action_trace/activity_logs/`. Rails will use your copies instead of the engine defaults.\n\nThe `--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.\n\n\u003e **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.\n\n---\n\n## Usage\n\n### Models — tracking data changes\n\nInclude `ActionTrace::DataTrackable` in any ActiveRecord model you want to track:\n\n```ruby\nclass Document \u003c ApplicationRecord\n  include ActionTrace::DataTrackable\nend\n```\n\nThis 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.\n\nFor paper_trail versioning to work, the model also needs `has_paper_trail`:\n\n```ruby\nclass Document \u003c ApplicationRecord\n  include ActionTrace::DataTrackable\n  has_paper_trail\nend\n```\n\nFor soft-delete tracking with discard, add `include Discard::Model` alongside `DataTrackable`. The `data_destroy` event is still recorded via the `before_destroy` callback.\n\n### JavaScript — client-side page visit tracking\n\nThe installer copies `app/javascript/action_trace.js` and imports it from `application.js`. The script reads data attributes from the `\u003cbody\u003e` tag on every Turbo page load and fires an Ahoy `page_visit` event.\n\nYou must add those attributes to your layout manually:\n\n```erb\n\u003cbody\n  data-track-controller=\"\u003c%= controller_name %\u003e\"\n  data-track-action=\"\u003c%= action_name %\u003e\"\n  data-track-company-id=\"\u003c%= current_user.company_id %\u003e\"\n  data-track-method=\"\u003c%= request.method %\u003e\"\u003e\n```\n\nIf the `data-track-controller` attribute is absent the script exits early and no event is sent, so pages where the user is not logged in (and `current_user` is nil) are safe as long as you omit the attributes conditionally:\n\n```erb\n\u003cbody \u003c%= current_user ? %(data-track-controller=\"#{controller_name}\" data-track-action=\"#{action_name}\" data-track-company-id=\"#{current_user.company_id}\" data-track-method=\"#{request.method}\") : \"\" %\u003e\u003e\n```\n\n### Controllers — tracking page visits and sessions\n\nInclude `ActivityTrackable` in any controller (or `ApplicationController`) to track page visits:\n\n```ruby\nclass ApplicationController \u003c ActionController::Base\n  include ActivityTrackable\nend\n```\n\nThis 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.\n\nTo skip tracking on a specific controller that inherits from `ApplicationController`:\n\n```ruby\nclass HealthChecksController \u003c ApplicationController\n  skip_after_action :track_action\nend\n```\n\nTo record a session end on logout, call `track_session_end` before clearing the session:\n\n```ruby\nclass SessionsController \u003c Devise::SessionsController\n  def destroy\n    track_session_end\n    super\n  end\nend\n```\n\nThe 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`).\n\n### Querying activity logs directly\n\nUse `ActionTrace::FetchActivityLogs` to fetch and paginate the unified activity log programmatically:\n\n```ruby\nresult = ActionTrace::FetchActivityLogs.call(\n  current_user: current_user,\n  filters: {\n    'source'     =\u003e 'data_change',  # optional — one of the sources listed above\n    'company_id' =\u003e 5,              # optional — overrides current_user.company_id\n    'user_id'    =\u003e 12,             # optional\n    'start_date' =\u003e '2026-01-01',   # optional — YYYY-MM-DD\n    'end_date'   =\u003e '2026-03-31'    # optional — YYYY-MM-DD\n  },\n  range: 0  # offset for pagination (increments of 50)\n)\n\nresult.activity_logs  # =\u003e Array of ActionTrace::ActivityLog\nresult.total_count    # =\u003e Integer\n```\n\nEach `ActionTrace::ActivityLog` exposes:\n\n| Attribute | Type | Description |\n|---|---|---|\n| `id` | String | Prefixed ID e.g. `act_42`, `visit_7`, `evt_3` |\n| `source` | String | One of the sources in the table above |\n| `occurred_at` | DateTime | When the event happened |\n| `user` | String | Display name of the user |\n| `subject` | String | Human-readable description |\n| `details` | Hash | Raw event payload |\n| `paper_trail_version` | PaperTrail::Version | Associated version (data events only) |\n| `trackable` | ActiveRecord object | The changed record (data events only) |\n| `trackable_type` | String | Class name of the changed record |\n\nPresenter helpers are also available on each log:\n\n```ruby\nlog.icon           # =\u003e 'fas fa-pencil-alt'\nlog.color          # =\u003e 'text-primary'\nlog.data_change?   # =\u003e true / false\nlog.page_visit?    # =\u003e true / false\n# data_create?, data_destroy?, session_start?, session_end?\n```\n\n### Configuration\n\n`config/initializers/action_trace.rb` is generated automatically. Available options:\n\n```ruby\nActionTrace.configure do |config|\n  # Controller names to exclude from page_visit tracking (default: [])\n  config.excluded_controllers = %w[health_checks status]\n\n  # Action names to exclude from page_visit tracking (default: [])\n  config.excluded_actions = %w[ping]\n\n  # The user model class name used to resolve company filtering (default: 'User')\n  config.user_class = 'User'\n\n  # How long to retain activity records before purging (default: 1.year)\n  config.log_retention_period = 6.months\nend\n```\n\n\u003e `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`).\n\n### Purging old records\n\n`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:\n\n```ruby\n# e.g. with whenever or Sidekiq-cron\nActionTrace::PurgeActivityLogJob.perform_later\n```\n\n---\n\n## License\n\nThe gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fengim-eu%2Faction_trace","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fengim-eu%2Faction_trace","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fengim-eu%2Faction_trace/lists"}