rails_audit_log 0.7.0 → 0.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (37) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +88 -0
  3. data/app/assets/stylesheets/rails_audit_log/_01_base.css +32 -0
  4. data/app/assets/stylesheets/rails_audit_log/_02_layout.css +34 -0
  5. data/app/assets/stylesheets/rails_audit_log/_03_table.css +39 -0
  6. data/app/assets/stylesheets/rails_audit_log/_04_badges.css +13 -0
  7. data/app/assets/stylesheets/rails_audit_log/_05_diff.css +94 -0
  8. data/app/assets/stylesheets/rails_audit_log/_06_timeline.css +21 -0
  9. data/app/assets/stylesheets/rails_audit_log/_07_detail.css +15 -0
  10. data/app/assets/stylesheets/rails_audit_log/_08_pagination.css +56 -0
  11. data/app/assets/stylesheets/rails_audit_log/_09_filters.css +54 -0
  12. data/app/assets/stylesheets/rails_audit_log/application.css +1 -15
  13. data/app/concerns/rails_audit_log/auditable.rb +14 -0
  14. data/app/controllers/rails_audit_log/application_controller.rb +12 -0
  15. data/app/controllers/rails_audit_log/audit_log_entries_controller.rb +31 -0
  16. data/app/controllers/rails_audit_log/resources_controller.rb +13 -0
  17. data/app/helpers/rails_audit_log/application_helper.rb +13 -0
  18. data/app/javascript/rails_audit_log/application.js +8 -0
  19. data/app/javascript/rails_audit_log/diff_controller.js +20 -0
  20. data/app/javascript/rails_audit_log/search_controller.js +12 -0
  21. data/app/models/rails_audit_log/audit_log_entry.rb +5 -3
  22. data/app/views/layouts/rails_audit_log/application.html.erb +16 -10
  23. data/app/views/rails_audit_log/audit_log_entries/_diff.html.erb +55 -0
  24. data/app/views/rails_audit_log/audit_log_entries/index.html.erb +76 -0
  25. data/app/views/rails_audit_log/audit_log_entries/show.html.erb +50 -0
  26. data/app/views/rails_audit_log/resources/show.html.erb +35 -0
  27. data/config/importmap.rb +5 -0
  28. data/config/routes.rb +3 -0
  29. data/lib/generators/rails_audit_log/initializer/initializer_generator.rb +15 -0
  30. data/lib/generators/rails_audit_log/initializer/templates/rails_audit_log.rb +41 -0
  31. data/lib/rails_audit_log/engine.rb +28 -0
  32. data/lib/rails_audit_log/matchers.rb +103 -0
  33. data/lib/rails_audit_log/minitest_assertions.rb +31 -0
  34. data/lib/rails_audit_log/test_helpers.rb +7 -0
  35. data/lib/rails_audit_log/version.rb +1 -1
  36. data/lib/rails_audit_log.rb +10 -0
  37. metadata +67 -1
@@ -1,17 +1,23 @@
1
1
  <!DOCTYPE html>
2
- <html>
2
+ <html lang="en">
3
3
  <head>
4
- <title>Rails audit log</title>
4
+ <meta charset="utf-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1">
6
+ <title>Audit Log</title>
7
+ <link rel="icon" href="data:,">
5
8
  <%= csrf_meta_tags %>
6
9
  <%= csp_meta_tag %>
7
-
8
- <%= yield :head %>
9
-
10
- <%= stylesheet_link_tag "rails_audit_log/application", media: "all" %>
10
+ <%= dashboard_stylesheets %>
11
+ <%= javascript_importmap_tags "rails_audit_log" %>
11
12
  </head>
12
13
  <body>
13
-
14
- <%= yield %>
15
-
14
+ <header class="ral-header">
15
+ <div class="ral-header__inner">
16
+ <%= link_to "Audit Log", root_path, class: "ral-header__logo" %>
17
+ </div>
18
+ </header>
19
+ <main class="ral-main">
20
+ <%= yield %>
21
+ </main>
16
22
  </body>
17
- </html>
23
+ </html>
@@ -0,0 +1,55 @@
1
+ <% changes = entry.object_changes.presence %>
2
+ <% if changes %>
3
+ <div class="ral-diff-wrap" data-controller="diff">
4
+ <div class="ral-diff-toggle">
5
+ <button class="ral-diff-btn ral-diff-btn--active"
6
+ data-diff-target="inlineBtn"
7
+ data-action="click->diff#setInline">Inline</button>
8
+ <button class="ral-diff-btn"
9
+ data-diff-target="sideBtn"
10
+ data-action="click->diff#setSide">Side by side</button>
11
+ </div>
12
+
13
+ <table class="ral-diff" data-diff-target="inline">
14
+ <thead>
15
+ <tr>
16
+ <th>Attribute</th>
17
+ <th>Before</th>
18
+ <th>After</th>
19
+ </tr>
20
+ </thead>
21
+ <tbody>
22
+ <% changes.each do |attr, (before, after)| %>
23
+ <tr>
24
+ <td class="ral-diff__attr"><%= attr %></td>
25
+ <td class="ral-diff__before"><%= format_diff_value(before) %></td>
26
+ <td class="ral-diff__after"><%= format_diff_value(after) %></td>
27
+ </tr>
28
+ <% end %>
29
+ </tbody>
30
+ </table>
31
+
32
+ <div class="ral-diff-side" data-diff-target="side" hidden>
33
+ <div class="ral-diff-side__panel ral-diff-side__panel--before">
34
+ <div class="ral-diff-side__header">Before</div>
35
+ <% changes.each do |attr, (before, _after)| %>
36
+ <div class="ral-diff-side__row">
37
+ <span class="ral-diff-side__attr"><%= attr %></span>
38
+ <span class="ral-diff-side__value"><%= format_diff_value(before) %></span>
39
+ </div>
40
+ <% end %>
41
+ </div>
42
+ <div class="ral-diff-side__panel ral-diff-side__panel--after">
43
+ <div class="ral-diff-side__header">After</div>
44
+ <% changes.each do |attr, (_before, after)| %>
45
+ <div class="ral-diff-side__row">
46
+ <span class="ral-diff-side__attr"><%= attr %></span>
47
+ <span class="ral-diff-side__value"><%= format_diff_value(after) %></span>
48
+ </div>
49
+ <% end %>
50
+ </div>
51
+ </div>
52
+ </div>
53
+ <% else %>
54
+ <p class="ral-muted">No changes recorded.</p>
55
+ <% end %>
@@ -0,0 +1,76 @@
1
+ <div class="ral-page-header">
2
+ <h1 class="ral-page-header__title">Audit Entries</h1>
3
+ <span class="ral-page-header__meta"><%= @pagy.count %> <%= "entry".pluralize(@pagy.count) %></span>
4
+ </div>
5
+
6
+ <%= turbo_frame_tag "ral-entries", data: { turbo_action: "advance" } do %>
7
+ <form class="ral-filters" action="<%= audit_log_entries_path %>" method="get"
8
+ data-controller="search">
9
+ <%= hidden_field_tag :period, @period if @period %>
10
+
11
+ <input type="search" name="q" value="<%= @q %>"
12
+ class="ral-filter-input" placeholder="Filter by actor…"
13
+ autocomplete="off" aria-label="Filter by actor"
14
+ data-action="input->search#filter">
15
+
16
+ <select name="event" class="ral-filter-select" aria-label="Filter by event"
17
+ data-action="change->search#select">
18
+ <option value="">All events</option>
19
+ <% RailsAuditLog::AuditLogEntry::EVENTS.each do |event| %>
20
+ <option value="<%= event %>" <%= "selected" if @event == event %>><%= event.capitalize %></option>
21
+ <% end %>
22
+ </select>
23
+
24
+ <% if @item_types.size > 1 %>
25
+ <select name="item_type" class="ral-filter-select" aria-label="Filter by resource"
26
+ data-action="change->search#select">
27
+ <option value="">All resources</option>
28
+ <% @item_types.each do |type| %>
29
+ <option value="<%= type %>" <%= "selected" if @item_type == type %>><%= type %></option>
30
+ <% end %>
31
+ </select>
32
+ <% end %>
33
+
34
+ <div class="ral-period-filter" role="group" aria-label="Time period">
35
+ <%= link_to "All", audit_log_entries_path(event: @event, item_type: @item_type, q: @q),
36
+ class: "ral-period-btn#{" ral-period-btn--active" if @period.blank?}" %>
37
+ <% RailsAuditLog::AuditLogEntry::PERIODS.each_key do |p| %>
38
+ <%= link_to p, audit_log_entries_path(event: @event, item_type: @item_type, q: @q, period: p),
39
+ class: "ral-period-btn#{" ral-period-btn--active" if @period == p}" %>
40
+ <% end %>
41
+ </div>
42
+
43
+ <% if @event || @item_type || @period || @q %>
44
+ <%= link_to "Clear", audit_log_entries_path, class: "ral-link ral-filters__clear" %>
45
+ <% end %>
46
+ </form>
47
+
48
+ <% if @entries.any? %>
49
+ <div class="ral-table-wrap">
50
+ <table class="ral-table">
51
+ <thead>
52
+ <tr>
53
+ <th>Event</th>
54
+ <th>Resource</th>
55
+ <th>Actor</th>
56
+ <th>When</th>
57
+ </tr>
58
+ </thead>
59
+ <tbody>
60
+ <% @entries.each do |entry| %>
61
+ <tr>
62
+ <td><span class="ral-badge ral-badge--<%= entry.event %>"><%= entry.event %></span></td>
63
+ <td><%= link_to "#{entry.item_type} ##{entry.item_id}", resource_path(item_type: entry.item_type, item_id: entry.item_id), class: "ral-link", data: { turbo_frame: "_top" } %></td>
64
+ <td><%= entry.whodunnit_snapshot.presence || (entry.actor_type ? "#{entry.actor_type} \##{entry.actor_id}" : "—") %></td>
65
+ <td class="ral-timestamp"><%= entry.created_at.utc.strftime("%Y-%m-%d %H:%M UTC") %></td>
66
+ </tr>
67
+ <% end %>
68
+ </tbody>
69
+ </table>
70
+ </div>
71
+
72
+ <%== @pagy.series_nav(aria_label: "Pagination") if @pagy.pages > 1 %>
73
+ <% else %>
74
+ <p class="ral-empty">No audit entries found.</p>
75
+ <% end %>
76
+ <% end %>
@@ -0,0 +1,50 @@
1
+ <div class="ral-page-header">
2
+ <div>
3
+ <p class="ral-breadcrumb">
4
+ <%= link_to "Audit Entries", audit_log_entries_path, class: "ral-link" %> /
5
+ <%= link_to "#{@entry.item_type} ##{@entry.item_id}", resource_path(item_type: @entry.item_type, item_id: @entry.item_id), class: "ral-link" %>
6
+ </p>
7
+ <h1 class="ral-page-header__title">Entry #<%= @entry.id %></h1>
8
+ </div>
9
+ <nav class="ral-entry-nav" aria-label="Entry navigation">
10
+ <% if (prev_entry = @entry.previous) %>
11
+ <%= link_to "← Previous", audit_log_entry_path(prev_entry), class: "ral-pagination__link" %>
12
+ <% end %>
13
+ <% if (next_entry = @entry.next) %>
14
+ <%= link_to "Next →", audit_log_entry_path(next_entry), class: "ral-pagination__link" %>
15
+ <% end %>
16
+ </nav>
17
+ </div>
18
+
19
+ <div class="ral-card">
20
+ <dl class="ral-meta">
21
+ <div class="ral-meta__row">
22
+ <dt>Event</dt>
23
+ <dd><span class="ral-badge ral-badge--<%= @entry.event %>"><%= @entry.event %></span></dd>
24
+ </div>
25
+ <div class="ral-meta__row">
26
+ <dt>Resource</dt>
27
+ <dd><%= link_to "#{@entry.item_type} ##{@entry.item_id}", resource_path(item_type: @entry.item_type, item_id: @entry.item_id), class: "ral-link" %></dd>
28
+ </div>
29
+ <% actor = @entry.whodunnit_snapshot.presence || (@entry.actor_type ? "#{@entry.actor_type} \##{@entry.actor_id}" : "—") %>
30
+ <div class="ral-meta__row">
31
+ <dt>Actor</dt>
32
+ <dd><%= actor %></dd>
33
+ </div>
34
+ <div class="ral-meta__row">
35
+ <dt>When</dt>
36
+ <dd class="ral-timestamp"><%= @entry.created_at.utc.strftime("%Y-%m-%d %H:%M:%S UTC") %></dd>
37
+ </div>
38
+ <% if @entry.reason.present? %>
39
+ <div class="ral-meta__row">
40
+ <dt>Reason</dt>
41
+ <dd><%= @entry.reason %></dd>
42
+ </div>
43
+ <% end %>
44
+ </dl>
45
+ </div>
46
+
47
+ <h2 class="ral-section-title">Changes</h2>
48
+ <div class="ral-card">
49
+ <%= render "diff", entry: @entry %>
50
+ </div>
@@ -0,0 +1,35 @@
1
+ <div class="ral-page-header">
2
+ <div>
3
+ <p class="ral-breadcrumb"><%= link_to "Audit Entries", audit_log_entries_path, class: "ral-link" %></p>
4
+ <h1 class="ral-page-header__title"><%= @item_type %> #<%= @item_id %></h1>
5
+ </div>
6
+ <span class="ral-page-header__meta"><%= @pagy.count %> <%= "entry".pluralize(@pagy.count) %></span>
7
+ </div>
8
+
9
+ <%= turbo_frame_tag "ral-resource-entries", data: { turbo_action: "advance" } do %>
10
+ <% if @entries.any? %>
11
+ <div class="ral-timeline">
12
+ <% @entries.each do |entry| %>
13
+ <div class="ral-timeline__entry">
14
+ <div class="ral-timeline__header">
15
+ <span class="ral-badge ral-badge--<%= entry.event %>"><%= entry.event %></span>
16
+ <span class="ral-timestamp"><%= entry.created_at.utc.strftime("%Y-%m-%d %H:%M UTC") %></span>
17
+ <% actor = entry.whodunnit_snapshot.presence || (entry.actor_type ? "#{entry.actor_type} \##{entry.actor_id}" : nil) %>
18
+ <% if actor %>
19
+ <span class="ral-muted">by <%= actor %></span>
20
+ <% end %>
21
+ <% if entry.reason.present? %>
22
+ <span class="ral-reason">"<%= entry.reason %>"</span>
23
+ <% end %>
24
+ <%= link_to "Details →", audit_log_entry_path(entry), class: "ral-link ral-timeline__detail-link", data: { turbo_frame: "_top" } %>
25
+ </div>
26
+ <%= render "rails_audit_log/audit_log_entries/diff", entry: entry %>
27
+ </div>
28
+ <% end %>
29
+ </div>
30
+
31
+ <%== @pagy.series_nav(aria_label: "Pagination") if @pagy.pages > 1 %>
32
+ <% else %>
33
+ <p class="ral-empty">No audit entries for this record.</p>
34
+ <% end %>
35
+ <% end %>
@@ -0,0 +1,5 @@
1
+ pin "@hotwired/turbo", to: "https://cdn.jsdelivr.net/npm/@hotwired/turbo@8.0.23/dist/turbo.es2017-esm.js"
2
+ pin "@hotwired/stimulus", to: "https://cdn.jsdelivr.net/npm/@hotwired/stimulus@3.2.2/dist/stimulus.js"
3
+ pin "rails_audit_log", to: "rails_audit_log/application.js"
4
+ pin "rails_audit_log/search_controller", to: "rails_audit_log/search_controller.js"
5
+ pin "rails_audit_log/diff_controller", to: "rails_audit_log/diff_controller.js"
data/config/routes.rb CHANGED
@@ -1,2 +1,5 @@
1
1
  RailsAuditLog::Engine.routes.draw do
2
+ root to: "audit_log_entries#index"
3
+ resources :audit_log_entries, only: [:index, :show]
4
+ get "resources/:item_type/:item_id", to: "resources#show", as: :resource
2
5
  end
@@ -0,0 +1,15 @@
1
+ require "rails/generators"
2
+
3
+ module RailsAuditLog
4
+ module Generators
5
+ class InitializerGenerator < Rails::Generators::Base
6
+ source_root File.expand_path("templates", __dir__)
7
+
8
+ desc "Creates a commented RailsAuditLog initializer in config/initializers."
9
+
10
+ def create_initializer_file
11
+ template "rails_audit_log.rb", "config/initializers/rails_audit_log.rb"
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,41 @@
1
+ # config/initializers/rails_audit_log.rb
2
+ # Generated by `bin/rails generate rails_audit_log:initializer`
3
+ #
4
+ # All settings are optional. Remove the comments around any line you want to activate.
5
+
6
+ RailsAuditLog.configure do |config|
7
+ # Global columns excluded from all audited models. Default: ["updated_at"]
8
+ # config.ignored_attributes = %w[updated_at cached_at]
9
+
10
+ # Store a full attribute snapshot alongside object_changes. Default: true
11
+ # Disable to save storage; reify and version_at fall back to diff-only reconstruction.
12
+ # config.store_snapshot = false
13
+
14
+ # Capture remote_ip and user_agent into each entry's metadata column. Default: false
15
+ # Requires including RailsAuditLog::Controller in ApplicationController.
16
+ # config.capture_request_metadata = true
17
+
18
+ # Customise how the actor's display name is stored at write time. Default: actor.name
19
+ # config.whodunnit_display = ->(actor) { actor.email }
20
+
21
+ # Global cap on entries retained per tracked record. Default: nil (no limit)
22
+ # Per-model `audit_log version_limit: N` takes precedence.
23
+ # config.version_limit = 100
24
+
25
+ # Write all audit entries asynchronously via WriteAuditLogJob. Default: false
26
+ # Per-model `audit_log async: true` also works.
27
+ # config.async = true
28
+
29
+ # Route AuditLogEntry to a dedicated database (Rails multi-DB). Default: nil
30
+ # config.connects_to = { database: { writing: :audit_log, reading: :audit_log } }
31
+
32
+ # Number of entries per page in the web dashboard. Default: 25
33
+ # config.page_size = 50
34
+
35
+ # Gate web dashboard access. Block runs in controller context — controller
36
+ # methods like current_user are available directly, or accept the controller
37
+ # as an argument. Falls back to HTTP Basic auth if the block returns falsy.
38
+ # Leave unset to allow unauthenticated access (development default).
39
+ # config.authenticate { current_user&.admin? }
40
+ # config.authenticate { |c| c.current_user&.admin? }
41
+ end
@@ -1,7 +1,35 @@
1
+ require "turbo-rails"
2
+ require "importmap-rails"
3
+ require "pagy"
4
+ require "pagy/toolbox/paginators/method"
5
+
1
6
  module RailsAuditLog
2
7
  class Engine < ::Rails::Engine
3
8
  isolate_namespace RailsAuditLog
4
9
 
10
+ config.i18n.load_path += Gem.find_files("pagy/locales/en.yml")
11
+
12
+ initializer "rails_audit_log.pagy" do |app|
13
+ app.config.after_initialize do
14
+ Pagy::OPTIONS[:limit] = RailsAuditLog.page_size
15
+ end
16
+ end
17
+
18
+ initializer "rails_audit_log.assets" do |app|
19
+ if app.config.respond_to?(:assets)
20
+ app.config.assets.paths << root.join("app/assets/stylesheets")
21
+ app.config.assets.paths << root.join("app/assets/images")
22
+ app.config.assets.paths << root.join("app/javascript")
23
+ end
24
+ end
25
+
26
+ initializer "rails_audit_log.importmap", before: "importmap" do |app|
27
+ if app.config.respond_to?(:importmap)
28
+ app.config.importmap.paths << root.join("config/importmap.rb")
29
+ app.config.importmap.cache_sweepers << root.join("app/javascript")
30
+ end
31
+ end
32
+
5
33
  initializer "rails_audit_log.connect_audit_db" do
6
34
  ActiveSupport.on_load(:active_record) do
7
35
  RailsAuditLog::AuditLogEntry.configure_connection!
@@ -0,0 +1,103 @@
1
+ module RailsAuditLog
2
+ module Matchers
3
+ def have_audit_log_entry(event = nil)
4
+ HaveAuditLogEntry.new(event)
5
+ end
6
+
7
+ def create_audit_log_entry(event: nil, touching: nil)
8
+ CreateAuditLogEntry.new(event: event, touching: touching)
9
+ end
10
+
11
+ class HaveAuditLogEntry
12
+ def initialize(event)
13
+ @event = event
14
+ @touching = nil
15
+ end
16
+
17
+ def touching(attribute)
18
+ @touching = attribute
19
+ self
20
+ end
21
+
22
+ def matches?(record)
23
+ @record = record
24
+ scope = record.audit_log_entries
25
+ scope = scope.where(event: @event.to_s) if @event
26
+ scope = scope.touching(@touching) if @touching
27
+ scope.exists?
28
+ end
29
+
30
+ def failure_message
31
+ "expected #{@record.class}##{@record.id} to have an audit log entry#{qualifier}"
32
+ end
33
+
34
+ def failure_message_when_negated
35
+ "expected #{@record.class}##{@record.id} not to have an audit log entry#{qualifier}"
36
+ end
37
+
38
+ def description
39
+ "have an audit log entry#{qualifier}"
40
+ end
41
+
42
+ private
43
+
44
+ def qualifier
45
+ parts = []
46
+ parts << " with event '#{@event}'" if @event
47
+ parts << " touching '#{@touching}'" if @touching
48
+ parts.join
49
+ end
50
+ end
51
+
52
+ class CreateAuditLogEntry
53
+ def initialize(event:, touching:)
54
+ @event = event
55
+ @touching = touching
56
+ end
57
+
58
+ def touching(attribute)
59
+ @touching = attribute
60
+ self
61
+ end
62
+
63
+ def supports_block_expectations?
64
+ true
65
+ end
66
+
67
+ def matches?(block)
68
+ @before = matching_scope.count
69
+ block.call
70
+ @after = matching_scope.count
71
+ @after > @before
72
+ end
73
+
74
+ def failure_message
75
+ "expected block to create an audit log entry#{qualifier}, but none was created"
76
+ end
77
+
78
+ def failure_message_when_negated
79
+ "expected block not to create an audit log entry#{qualifier}, but one was created"
80
+ end
81
+
82
+ def description
83
+ "create an audit log entry#{qualifier}"
84
+ end
85
+
86
+ private
87
+
88
+ def matching_scope
89
+ scope = RailsAuditLog::AuditLogEntry.all
90
+ scope = scope.where(event: @event.to_s) if @event
91
+ scope = scope.touching(@touching) if @touching
92
+ scope
93
+ end
94
+
95
+ def qualifier
96
+ parts = []
97
+ parts << " with event '#{@event}'" if @event
98
+ parts << " touching '#{@touching}'" if @touching
99
+ parts.join
100
+ end
101
+ end
102
+ end
103
+ end
@@ -0,0 +1,31 @@
1
+ module RailsAuditLog
2
+ module MinitestAssertions
3
+ def assert_audit_log_entry(record, event: nil, touching: nil, message: nil)
4
+ scope = build_scope(record, event, touching)
5
+ msg = message || default_message("to have", record, event, touching)
6
+ assert scope.exists?, msg
7
+ end
8
+
9
+ def refute_audit_log_entry(record, event: nil, touching: nil, message: nil)
10
+ scope = build_scope(record, event, touching)
11
+ msg = message || default_message("not to have", record, event, touching)
12
+ refute scope.exists?, msg
13
+ end
14
+
15
+ private
16
+
17
+ def build_scope(record, event, touching)
18
+ scope = record.audit_log_entries
19
+ scope = scope.where(event: event.to_s) if event
20
+ scope = scope.touching(touching) if touching
21
+ scope
22
+ end
23
+
24
+ def default_message(polarity, record, event, touching)
25
+ parts = []
26
+ parts << " with event '#{event}'" if event
27
+ parts << " touching '#{touching}'" if touching
28
+ "Expected #{record.class}##{record.id} #{polarity} an audit log entry#{parts.join}"
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,7 @@
1
+ module RailsAuditLog
2
+ module TestHelpers
3
+ def without_audit_log(&block)
4
+ RailsAuditLog.disable(&block)
5
+ end
6
+ end
7
+ end
@@ -1,3 +1,3 @@
1
1
  module RailsAuditLog
2
- VERSION = "0.7.0"
2
+ VERSION = "0.9.0"
3
3
  end
@@ -5,11 +5,21 @@ module RailsAuditLog
5
5
  # Global default columns to ignore across all audited models.
6
6
  # Override in an initializer: RailsAuditLog.ignored_attributes = %w[updated_at cached_at]
7
7
  mattr_accessor :ignored_attributes, default: %w[updated_at]
8
+
9
+ def self.configure
10
+ yield self
11
+ end
8
12
  mattr_accessor :store_snapshot, default: true
9
13
  mattr_accessor :capture_request_metadata, default: false
10
14
  mattr_accessor :version_limit, default: nil
11
15
  mattr_accessor :async, default: false
12
16
  mattr_accessor :connects_to, default: nil
17
+ mattr_accessor :page_size, default: 25
18
+
19
+ def self.authenticate(&block)
20
+ @authenticate = block if block_given?
21
+ @authenticate
22
+ end
13
23
  mattr_accessor :whodunnit_display, default: ->(actor) {
14
24
  actor.respond_to?(:name) ? actor.name.to_s : actor.to_s
15
25
  }
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rails_audit_log
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.7.0
4
+ version: 0.9.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Chuck Smith
@@ -23,6 +23,48 @@ dependencies:
23
23
  - - ">="
24
24
  - !ruby/object:Gem::Version
25
25
  version: '7.2'
26
+ - !ruby/object:Gem::Dependency
27
+ name: turbo-rails
28
+ requirement: !ruby/object:Gem::Requirement
29
+ requirements:
30
+ - - ">="
31
+ - !ruby/object:Gem::Version
32
+ version: '2.0'
33
+ type: :runtime
34
+ prerelease: false
35
+ version_requirements: !ruby/object:Gem::Requirement
36
+ requirements:
37
+ - - ">="
38
+ - !ruby/object:Gem::Version
39
+ version: '2.0'
40
+ - !ruby/object:Gem::Dependency
41
+ name: importmap-rails
42
+ requirement: !ruby/object:Gem::Requirement
43
+ requirements:
44
+ - - ">="
45
+ - !ruby/object:Gem::Version
46
+ version: '1.2'
47
+ type: :runtime
48
+ prerelease: false
49
+ version_requirements: !ruby/object:Gem::Requirement
50
+ requirements:
51
+ - - ">="
52
+ - !ruby/object:Gem::Version
53
+ version: '1.2'
54
+ - !ruby/object:Gem::Dependency
55
+ name: pagy
56
+ requirement: !ruby/object:Gem::Requirement
57
+ requirements:
58
+ - - ">="
59
+ - !ruby/object:Gem::Version
60
+ version: '43.0'
61
+ type: :runtime
62
+ prerelease: false
63
+ version_requirements: !ruby/object:Gem::Requirement
64
+ requirements:
65
+ - - ">="
66
+ - !ruby/object:Gem::Version
67
+ version: '43.0'
26
68
  description: A modern Rails engine that tracks ActiveRecord create, update, and destroy
27
69
  events with JSON-first storage, whodunnit actor context, and a clean query API.
28
70
  Drop-in replacement for PaperTrail with no legacy baggage.
@@ -35,21 +77,45 @@ files:
35
77
  - MIT-LICENSE
36
78
  - README.md
37
79
  - Rakefile
80
+ - app/assets/stylesheets/rails_audit_log/_01_base.css
81
+ - app/assets/stylesheets/rails_audit_log/_02_layout.css
82
+ - app/assets/stylesheets/rails_audit_log/_03_table.css
83
+ - app/assets/stylesheets/rails_audit_log/_04_badges.css
84
+ - app/assets/stylesheets/rails_audit_log/_05_diff.css
85
+ - app/assets/stylesheets/rails_audit_log/_06_timeline.css
86
+ - app/assets/stylesheets/rails_audit_log/_07_detail.css
87
+ - app/assets/stylesheets/rails_audit_log/_08_pagination.css
88
+ - app/assets/stylesheets/rails_audit_log/_09_filters.css
38
89
  - app/assets/stylesheets/rails_audit_log/application.css
39
90
  - app/concerns/rails_audit_log/auditable.rb
40
91
  - app/concerns/rails_audit_log/controller.rb
41
92
  - app/controllers/rails_audit_log/application_controller.rb
93
+ - app/controllers/rails_audit_log/audit_log_entries_controller.rb
94
+ - app/controllers/rails_audit_log/resources_controller.rb
42
95
  - app/helpers/rails_audit_log/application_helper.rb
96
+ - app/javascript/rails_audit_log/application.js
97
+ - app/javascript/rails_audit_log/diff_controller.js
98
+ - app/javascript/rails_audit_log/search_controller.js
43
99
  - app/jobs/rails_audit_log/application_job.rb
44
100
  - app/jobs/rails_audit_log/write_audit_log_job.rb
45
101
  - app/models/rails_audit_log/application_record.rb
46
102
  - app/models/rails_audit_log/audit_log_entry.rb
47
103
  - app/views/layouts/rails_audit_log/application.html.erb
104
+ - app/views/rails_audit_log/audit_log_entries/_diff.html.erb
105
+ - app/views/rails_audit_log/audit_log_entries/index.html.erb
106
+ - app/views/rails_audit_log/audit_log_entries/show.html.erb
107
+ - app/views/rails_audit_log/resources/show.html.erb
108
+ - config/importmap.rb
48
109
  - config/routes.rb
110
+ - lib/generators/rails_audit_log/initializer/initializer_generator.rb
111
+ - lib/generators/rails_audit_log/initializer/templates/rails_audit_log.rb
49
112
  - lib/generators/rails_audit_log/install/install_generator.rb
50
113
  - lib/generators/rails_audit_log/install/templates/create_audit_log_entries.rb
51
114
  - lib/rails_audit_log.rb
52
115
  - lib/rails_audit_log/engine.rb
116
+ - lib/rails_audit_log/matchers.rb
117
+ - lib/rails_audit_log/minitest_assertions.rb
118
+ - lib/rails_audit_log/test_helpers.rb
53
119
  - lib/rails_audit_log/version.rb
54
120
  - lib/tasks/rails_audit_log_tasks.rake
55
121
  homepage: https://github.com/eclectic-coding/rails_audit_log