paper_trail-actor 0.4.0 → 0.5.1

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 5feb0e3bd1d5d354acc67d9da8ce59737cd5f9d2003aac8a06d6d97abe9a964d
4
- data.tar.gz: 4c539f383eff32c652da404f3bf8edcc215cf3e1b1357b6d1566d0ad8abc37c0
3
+ metadata.gz: 8d8d84d52637e0114f5ab6c64b3caf0d10b2a94d6049d1e4c1ec0826d4dd94f4
4
+ data.tar.gz: fdabf9efe06ee201f706b17fc47fc75ffe590c57657c479b6b4bb1a26428eb94
5
5
  SHA512:
6
- metadata.gz: 396ac19a6b0ec27b2bddbc46c58e34819d6a1761fc2acee5cff4b3e9143b939c3a0f0dda67c4463d8581d44ef9fbc79ba492326ba8d66ba2c0cb8e5e2ca357ce
7
- data.tar.gz: e8077674949aa3d963b543d74c495edb6ccf975fb86821c8dc97ecc9db0527702ca5f412ee28b12849b8edf2701319cf89dee9dc3354415ffc9830ed46cf5912
6
+ metadata.gz: 50b13f56e781102f2c2da25054ea6530feff8d544a8320bc912157f4cb639f9a559ee6edc2166f58295aac8e7f7c716f06ea8f1abddc1fcf873a92f1e17ab3fd
7
+ data.tar.gz: ceec6f0626b24475afb00c413607491cb9456bab684a4ad835dc77798fbb3cf910a007c97e51ce5eb884dc176a2d03eb8828849704e5f5b3e342d5a6c054b8c2
data/CHANGELOG.md CHANGED
@@ -52,3 +52,35 @@
52
52
  ### Fixed
53
53
 
54
54
  - None
55
+
56
+ ## [0.5.0] - 2025-04-29
57
+
58
+ - Small improvements.
59
+
60
+ ### Breaking Changes
61
+
62
+ - None
63
+
64
+ ### Added
65
+
66
+ - [#12](https://github.com/tttffff/paper_trail-actor/pull/12) Default user for paper trail.
67
+ When using `#set_paper_trail_whodunnit`, the default `#user_for_paper_trail` is now the `#current_user` object, not it's `id`.
68
+
69
+ ### Fixed
70
+
71
+ - [#10](https://github.com/tttffff/paper_trail-actor/pull/10) Allow other object types.
72
+ Can now use any object that implements globalid, not just ActiveRecord objects.
73
+
74
+ ## [0.5.1] - 2025-11-15
75
+
76
+ ### Breaking Changes
77
+
78
+ - None
79
+
80
+ ### Added
81
+
82
+ - None
83
+
84
+ ### Fixed
85
+
86
+ - Explicitly set required ruby version.
data/README.md CHANGED
@@ -1,82 +1,182 @@
1
1
  # PaperTrail-Actor
2
2
 
3
- Originally forked from the now unmaintained [paper_trail-globalid](https://github.com/ankit1910/paper_trail-globalid).
3
+ Track changes in your Rails application with precision. PaperTrail-Actor extends [PaperTrail](https://github.com/paper-trail-gem/paper_trail) to store full ActiveRecord objects (not just IDs) as the actor responsible for changes.
4
4
 
5
- This gem is an extension to the [PaperTrail](https://github.com/paper-trail-gem/paper_trail) gem.
5
+ **Problem it solves:** When both `Admin` and `User` models can modify records, storing only an ID makes it impossible to know which model type made the change. PaperTrail-Actor stores GlobalIDs to uniquely identify actors across different model types.
6
6
 
7
- - Allows setting an `ActiveRecord` object for the whodunnit field on the PaperTrail request object and version objects.
8
- - Adds the method `#actor` to the PaperTrail request object which returns the `ActiveRecord` object that will be responsible for subsequent changes.
9
- - Adds the method `#actor` to PaperTrail version objects which returns the `ActiveRecord` object that was responsible for change.
7
+ ## Table of Contents
8
+
9
+ - [Features](#features)
10
+ - [Requirements](#requirements)
11
+ - [Installation](#installation)
12
+ - [Usage](#usage)
13
+ - [Basic Setup](#basic-setup)
14
+ - [Supported Object Types](#supported-object-types)
15
+ - [Controller Integration](#controller-integration)
16
+ - [Migrating Existing Data](#migrating-existing-data)
17
+ - [How It Works](#how-it-works)
18
+
19
+ ## Features
20
+
21
+ - **Store any ActiveRecord object** as the actor who made changes
22
+ - **Retrieve the full object** with a simple `#actor` method
23
+ - **Backward compatible** with existing PaperTrail versions
24
+ - **Flexible** - works with strings, unpersisted records, and non-ActiveRecord objects
25
+
26
+ ## Requirements
27
+
28
+ - Ruby 2.7+
29
+ - Rails 6.0+
30
+ - PaperTrail 11.0+
10
31
 
11
32
  ## Installation
12
33
 
13
- 1. Add PaperTrail-Actor to your `Gemfile`.
34
+ 1. Add to your Gemfile:
14
35
  ```ruby
15
36
  gem "paper_trail-actor"
16
37
  ```
17
- 2. And then execute:
38
+ 2. Install the gem:
18
39
  ```sh
19
40
  bundle install
20
41
  ```
21
42
 
22
- ## Basic Usage
43
+ ## Usage
44
+
45
+ ### Basic Setup
23
46
 
24
- This gem works by storing the [globalid](https://github.com/rails/globalid) to the whodunnit field of PaperTrail version tables.
25
- - It is designed not to hinder or break existing PaperTrail functionalities.
26
- - PaperTrail versions with and without a globalid can live side by side (e.g. versions created before installing this gem.)
47
+ Set any ActiveRecord object as the actor responsible for changes:
27
48
 
28
49
  ```ruby
50
+ admin = Admin.find(1)
51
+ PaperTrail.request.whodunnit = admin
52
+
53
+ # Now all changes will be attributed to this admin
54
+ # See Supported Object Types section below for detailed examples
55
+ ```
56
+
57
+ ### Supported Object Types
58
+
59
+ The gem handles various object types gracefully:
60
+
61
+ **Persisted ActiveRecord objects:**
62
+ ```ruby
63
+ admin = Admin.find(1)
29
64
  product = Product.find(42)
30
- admin = Admin.find(1) # <Admin:0x007fa2df9a5590>
31
65
 
32
66
  PaperTrail.request.whodunnit = admin
33
- PaperTrail.request.whodunnit # "gid://app/Admin/1"
34
- PaperTrail.request.actor # <Admin:0x007fa2df9a5590> returns the actual object
67
+ PaperTrail.request.whodunnit # => "gid://app/Admin/1"
68
+ PaperTrail.request.actor # => #<Admin id: 1>
35
69
 
70
+ # Make changes - PaperTrail will track the actor
36
71
  product.update(name: "Ice cream")
37
- product.versions.last.whodunnit # "gid://app/Admin/1"
38
- product.versions.last.actor # <Admin:0x007fa2df9a5590> returns the actual object
72
+ product.versions.last.whodunnit # => "gid://app/Admin/1"
73
+ product.versions.last.actor # => #<Admin id: 1>
39
74
  ```
40
75
 
41
- ### Setting whodunnit to something other than an ActiveRecord object
76
+ **Strings:**
77
+ ```ruby
78
+ PaperTrail.request.whodunnit = "Alex the admin"
79
+ PaperTrail.request.whodunnit # => "Alex the admin"
80
+ PaperTrail.request.actor # => "Alex the admin"
81
+ ```
42
82
 
43
- You can continue to set whodunnit to something other than an `ActiveRecord` object.
44
- - It follows standard PaperTrail functionality and adds the raw value to the whodunnit field.
45
- - The `#actor` method will return the raw value.
83
+ **New/unpersisted ActiveRecord objects:**
84
+ ```ruby
85
+ PaperTrail.request.whodunnit = Admin.new(name: "New Admin")
86
+ # Cannot get a globalid for an unpersisted object. So we use the `#to_s` for the object.
87
+ PaperTrail.request.whodunnit # => "#<Admin:0x00007f8e8c0a0b80>"
88
+ PaperTrail.request.actor # => "#<Admin:0x00007f8e8c0a0b80>"
89
+ ```
46
90
 
91
+ **Non-ActiveRecord objects:**
47
92
  ```ruby
48
- PaperTrail.request.whodunnit = "Alex the admin"
49
- PaperTrail.request.whodunnit # "Alex the admin"
50
- PaperTrail.request.actor # "Alex the admin"
93
+ class BackgroundJob
94
+ def to_s
95
+ "BackgroundJob-#{object_id}"
96
+ end
97
+ end
51
98
 
52
- product.update(name: "99 Flake")
53
- product.versions.last.whodunnit # "Alex the admin"
54
- product.versions.last.actor # "Alex the admin"
99
+ PaperTrail.request.whodunnit = BackgroundJob.new
100
+ PaperTrail.request.whodunnit # => "BackgroundJob-12345"
101
+ PaperTrail.request.actor # => "BackgroundJob-12345"
55
102
  ```
56
103
 
57
- ### Updating whodunnit on existing PaperTrail versions
104
+ ### Controller Integration
58
105
 
59
- You can retrospectivly update PaperTrail versions to have a new actor.
106
+ Set the actor automatically in your controllers using PaperTrail's built-in callback:
60
107
 
61
108
  ```ruby
62
- most_recent_product_version = product.versions.last
63
- admin_name = most_recent_product_version.actor # "Alex the admin"
64
- alex_the_admin = Admin.find_by(name: admin_name) # Do check for `nil` before updating the whodunit field
65
- most_recent_product_version.whodunnit = alex_the_admin
66
- most_recent_product_version.save
67
- most_recent_product_version.actor # <Admin:0x00000120fbb7d0>
109
+ class ApplicationController < ActionController::Base
110
+ before_action :set_paper_trail_whodunnit
111
+ end
68
112
  ```
69
113
 
70
- ### Setting whodunnit with a controller callback
114
+ If your controller has a `#current_user` method, PaperTrail-Actor will automatically use it and attribute all changes within the request cycle to that user.
71
115
 
72
- Similar to how you can configure the PaperTrail gem, as described in [Setting Whodunnit with a Controller Callback](https://github.com/paper-trail-gem/paper_trail/?tab=readme-ov-file#setting-whodunnit-with-a-controller-callback), you can now set this to an ActiveRecord object. This allows storing the global ID and retrieving the actor using the `#actor` methods.
116
+ ```ruby
117
+ # In your CRUD actions
118
+ def update
119
+ # Nothing else required here to attribute the user as the actor.
120
+ @product.update(product_params)
121
+ @product.versions.last.actor # => #<User id: 42> (full User object)
122
+ end
123
+ ```
73
124
 
74
- Here’s an example in your `ApplicationController`:
125
+ **Before PaperTrail-Actor:**
126
+ ```ruby
127
+ # whodunnit was just a string like "42"
128
+ version.whodunnit # => "42"
129
+ # You couldn't tell if this was User 42 or Admin 42
130
+ ```
131
+
132
+ **After PaperTrail-Actor:**
133
+ ```ruby
134
+ # whodunnit stores the full GlobalID
135
+ version.whodunnit # => "gid://app/User/42"
136
+ version.actor # => #<User id: 42>
137
+ # Now you know exactly who to attribute the change to
138
+ ```
139
+
140
+ Override `#user_for_paper_trail` to customize the actor selection logic:
75
141
 
76
142
  ```ruby
77
143
  class ApplicationController < ActionController::Base
144
+ before_action :set_paper_trail_whodunnit
145
+
146
+ private
147
+
78
148
  def user_for_paper_trail
79
- logged_in? ? current_user : "Public user"
149
+ logged_in? ? current_admin : "Public user"
80
150
  end
81
151
  end
82
152
  ```
153
+
154
+ ### Migrating Existing Data
155
+
156
+ **When to migrate:** Install PaperTrail-Actor on an existing app with PaperTrail data.
157
+
158
+ **How to migrate:** Convert existing string IDs to GlobalIDs:
159
+
160
+ ```ruby
161
+ # Find a version with a plain ID
162
+ version = product.versions.first
163
+ # => #<PaperTrail::Version id: 1, whodunnit: "123">
164
+
165
+ # Convert to GlobalID
166
+ admin = Admin.find_by(id: version.whodunnit)
167
+ if admin.present?
168
+ version.update!(whodunnit: admin)
169
+ version.whodunnit # => "gid://app/Admin/123"
170
+ version.actor # => #<Admin id: 123>
171
+ end
172
+ ```
173
+
174
+ ## How It Works
175
+
176
+ PaperTrail-Actor serializes ActiveRecord objects using [GlobalID](https://github.com/rails/globalid) and stores them in PaperTrail's `whodunnit` column. This enables:
177
+
178
+ - **Type-safe actor identification**: `gid://app/Admin/1` vs `gid://app/User/1`
179
+ - **Automatic deserialization**: Call `#actor` to get back the original ActiveRecord object
180
+ - **Graceful fallback**: Non-ActiveRecord objects are stored as strings
181
+
182
+ For example, if you have both `Admin` and `User` models that can make changes, this gem ensures you can clearly identify who made the change instead of using only an ID without knowing the model type.
@@ -0,0 +1,16 @@
1
+ module PaperTrailActor
2
+ module ActorMixin
3
+ # Used for #whodunnit= methods
4
+ def global_id_string_or_fallback(input_value)
5
+ if input_value.respond_to?(:to_global_id) && input_value.id
6
+ input_value.to_global_id.to_s
7
+ else
8
+ input_value.to_s
9
+ end
10
+ end
11
+
12
+ def actor
13
+ ::GlobalID::Locator.locate(whodunnit) || whodunnit
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,9 @@
1
+ module PaperTrailActor
2
+ module Rails
3
+ module Controller
4
+ def user_for_paper_trail
5
+ current_user if defined?(current_user)
6
+ end
7
+ end
8
+ end
9
+ end
@@ -1,15 +1,11 @@
1
+ require_relative "actor_mixin"
2
+
1
3
  module PaperTrailActor
2
4
  module Request
3
- def whodunnit=(value)
4
- if value.is_a? ActiveRecord::Base
5
- super(value.to_gid)
6
- else
7
- super
8
- end
9
- end
5
+ include ActorMixin
10
6
 
11
- def actor
12
- ::GlobalID::Locator.locate(store[:whodunnit]) || whodunnit
7
+ def whodunnit=(input_value)
8
+ super(global_id_string_or_fallback(input_value))
13
9
  end
14
10
  end
15
11
  end
@@ -1,3 +1,3 @@
1
1
  module PaperTrailActor
2
- VERSION = "0.4.0"
2
+ VERSION = "0.5.1"
3
3
  end
@@ -1,20 +1,12 @@
1
+ require_relative "actor_mixin"
2
+
1
3
  module PaperTrailActor
2
4
  module VersionConcern
5
+ include ActorMixin
6
+
3
7
  def whodunnit=(input_value)
4
- whodunnit_value = if input_value.is_a?(ActiveRecord::Base)
5
- input_value.to_gid
6
- else
7
- input_value
8
- end
8
+ whodunnit_value = global_id_string_or_fallback(input_value)
9
9
  _write_attribute("whodunnit", whodunnit_value)
10
10
  end
11
-
12
- # Returns an object which was responsible for a change
13
- # you need to store global_id to whodunnit field to make this method return the object(who was responsible)
14
- # for example, whodunnit => "gid://app/Order/1" then
15
- # whodunnit_user will return Order.find_by(id: 1) in application scope.
16
- def actor
17
- ::GlobalID::Locator.locate(whodunnit) || whodunnit
18
- end
19
11
  end
20
12
  end
@@ -1,6 +1,7 @@
1
1
  require "paper_trail-actor/version"
2
2
  require "paper_trail-actor/request"
3
3
  require "paper_trail-actor/version_concern"
4
+ require "paper_trail-actor/rails/controller"
4
5
 
5
6
  module ::PaperTrail
6
7
  module Request
@@ -8,10 +9,14 @@ module ::PaperTrail
8
9
  prepend ::PaperTrailActor::Request
9
10
  end
10
11
  end
11
- end
12
12
 
13
- module ::PaperTrail
14
13
  module VersionConcern
15
14
  include ::PaperTrailActor::VersionConcern
16
15
  end
16
+
17
+ module Rails
18
+ module Controller
19
+ prepend ::PaperTrailActor::Rails::Controller
20
+ end
21
+ end
17
22
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: paper_trail-actor
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.0
4
+ version: 0.5.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - tttffff
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2025-04-20 00:00:00.000000000 Z
11
+ date: 2025-11-15 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: paper_trail
@@ -53,35 +53,7 @@ dependencies:
53
53
  - !ruby/object:Gem::Version
54
54
  version: '0'
55
55
  - !ruby/object:Gem::Dependency
56
- name: rspec
57
- requirement: !ruby/object:Gem::Requirement
58
- requirements:
59
- - - ">="
60
- - !ruby/object:Gem::Version
61
- version: '0'
62
- type: :development
63
- prerelease: false
64
- version_requirements: !ruby/object:Gem::Requirement
65
- requirements:
66
- - - ">="
67
- - !ruby/object:Gem::Version
68
- version: '0'
69
- - !ruby/object:Gem::Dependency
70
- name: activerecord
71
- requirement: !ruby/object:Gem::Requirement
72
- requirements:
73
- - - ">="
74
- - !ruby/object:Gem::Version
75
- version: '0'
76
- type: :development
77
- prerelease: false
78
- version_requirements: !ruby/object:Gem::Requirement
79
- requirements:
80
- - - ">="
81
- - !ruby/object:Gem::Version
82
- version: '0'
83
- - !ruby/object:Gem::Dependency
84
- name: activesupport
56
+ name: rspec-rails
85
57
  requirement: !ruby/object:Gem::Requirement
86
58
  requirements:
87
59
  - - ">="
@@ -136,8 +108,9 @@ dependencies:
136
108
  - - ">="
137
109
  - !ruby/object:Gem::Version
138
110
  version: '0'
139
- description: An extension to PaperTrail. Using this gem, you can fetch the ActiveRecord
140
- object that was responsible for changes
111
+ description: An extension to PaperTrail that allows you to retrieve the ActiveRecord
112
+ object (actor) that was responsible for creating or modifying records, enabling
113
+ better audit trails and change attribution.
141
114
  email:
142
115
  - tristanfellows@icloud.com
143
116
  executables: []
@@ -149,6 +122,8 @@ files:
149
122
  - README.md
150
123
  - Rakefile
151
124
  - lib/paper_trail-actor.rb
125
+ - lib/paper_trail-actor/actor_mixin.rb
126
+ - lib/paper_trail-actor/rails/controller.rb
152
127
  - lib/paper_trail-actor/request.rb
153
128
  - lib/paper_trail-actor/version.rb
154
129
  - lib/paper_trail-actor/version_concern.rb
@@ -158,7 +133,7 @@ licenses:
158
133
  metadata:
159
134
  homepage_uri: https://github.com/tttffff/paper_trail-actor
160
135
  source_code_uri: https://github.com/tttffff/paper_trail-actor
161
- changelog_uri: https://github.com/tttffff/paper_trail-actor/blob/master/CHANGELOG.md
136
+ changelog_uri: https://github.com/tttffff/paper_trail-actor/blob/main/CHANGELOG.md
162
137
  post_install_message:
163
138
  rdoc_options: []
164
139
  require_paths:
@@ -167,7 +142,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
167
142
  requirements:
168
143
  - - ">="
169
144
  - !ruby/object:Gem::Version
170
- version: '0'
145
+ version: '2.7'
171
146
  required_rubygems_version: !ruby/object:Gem::Requirement
172
147
  requirements:
173
148
  - - ">="
@@ -177,6 +152,5 @@ requirements: []
177
152
  rubygems_version: 3.5.22
178
153
  signing_key:
179
154
  specification_version: 4
180
- summary: An extension to PaperTrail. Using this gem, you can fetch the ActiveRecord
181
- object that was responsible for changes
155
+ summary: Fetch the ActiveRecord object responsible for PaperTrail changes
182
156
  test_files: []