paper_trail-actor 0.5.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 +4 -4
- data/CHANGELOG.md +14 -0
- data/README.md +122 -63
- data/lib/paper_trail-actor/version.rb +1 -1
- metadata +7 -7
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 8d8d84d52637e0114f5ab6c64b3caf0d10b2a94d6049d1e4c1ec0826d4dd94f4
|
|
4
|
+
data.tar.gz: fdabf9efe06ee201f706b17fc47fc75ffe590c57657c479b6b4bb1a26428eb94
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 50b13f56e781102f2c2da25054ea6530feff8d544a8320bc912157f4cb639f9a559ee6edc2166f58295aac8e7f7c716f06ea8f1abddc1fcf873a92f1e17ab3fd
|
|
7
|
+
data.tar.gz: ceec6f0626b24475afb00c413607491cb9456bab684a4ad835dc77798fbb3cf910a007c97e51ce5eb884dc176a2d03eb8828849704e5f5b3e342d5a6c054b8c2
|
data/CHANGELOG.md
CHANGED
|
@@ -70,3 +70,17 @@
|
|
|
70
70
|
|
|
71
71
|
- [#10](https://github.com/tttffff/paper_trail-actor/pull/10) Allow other object types.
|
|
72
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,26 +1,41 @@
|
|
|
1
1
|
# PaperTrail-Actor
|
|
2
2
|
|
|
3
|
-
|
|
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
|
-
|
|
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
|
+
|
|
7
|
+
## Table of Contents
|
|
6
8
|
|
|
7
|
-
-
|
|
8
|
-
-
|
|
9
|
-
-
|
|
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
|
|
10
20
|
|
|
11
|
-
|
|
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
|
|
12
25
|
|
|
13
|
-
|
|
26
|
+
## Requirements
|
|
14
27
|
|
|
15
|
-
|
|
28
|
+
- Ruby 2.7+
|
|
29
|
+
- Rails 6.0+
|
|
30
|
+
- PaperTrail 11.0+
|
|
16
31
|
|
|
17
32
|
## Installation
|
|
18
33
|
|
|
19
|
-
1. Add
|
|
34
|
+
1. Add to your Gemfile:
|
|
20
35
|
```ruby
|
|
21
36
|
gem "paper_trail-actor"
|
|
22
37
|
```
|
|
23
|
-
2.
|
|
38
|
+
2. Install the gem:
|
|
24
39
|
```sh
|
|
25
40
|
bundle install
|
|
26
41
|
```
|
|
@@ -29,95 +44,139 @@ For example, if you have both `Admin` objects and `User` objects that are capabl
|
|
|
29
44
|
|
|
30
45
|
### Basic Setup
|
|
31
46
|
|
|
32
|
-
|
|
47
|
+
Set any ActiveRecord object as the actor responsible for changes:
|
|
33
48
|
|
|
34
49
|
```ruby
|
|
35
|
-
product = Product.find(42)
|
|
36
50
|
admin = Admin.find(1)
|
|
37
|
-
|
|
38
51
|
PaperTrail.request.whodunnit = admin
|
|
39
|
-
PaperTrail.request.whodunnit # "gid://app/Admin/1"
|
|
40
|
-
PaperTrail.request.actor # Returns the `Admin` object with id 1
|
|
41
|
-
```
|
|
42
52
|
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
```ruby
|
|
46
|
-
product.update(name: "Ice cream")
|
|
47
|
-
product.versions.last.whodunnit # "gid://app/Admin/1"
|
|
48
|
-
product.versions.last.actor # Returns the `Admin` object with id 1
|
|
53
|
+
# Now all changes will be attributed to this admin
|
|
54
|
+
# See Supported Object Types section below for detailed examples
|
|
49
55
|
```
|
|
50
56
|
|
|
51
|
-
###
|
|
57
|
+
### Supported Object Types
|
|
52
58
|
|
|
53
|
-
The gem
|
|
59
|
+
The gem handles various object types gracefully:
|
|
54
60
|
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
61
|
+
**Persisted ActiveRecord objects:**
|
|
62
|
+
```ruby
|
|
63
|
+
admin = Admin.find(1)
|
|
64
|
+
product = Product.find(42)
|
|
59
65
|
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
```
|
|
66
|
+
PaperTrail.request.whodunnit = admin
|
|
67
|
+
PaperTrail.request.whodunnit # => "gid://app/Admin/1"
|
|
68
|
+
PaperTrail.request.actor # => #<Admin id: 1>
|
|
64
69
|
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
end
|
|
71
|
-
end
|
|
70
|
+
# Make changes - PaperTrail will track the actor
|
|
71
|
+
product.update(name: "Ice cream")
|
|
72
|
+
product.versions.last.whodunnit # => "gid://app/Admin/1"
|
|
73
|
+
product.versions.last.actor # => #<Admin id: 1>
|
|
74
|
+
```
|
|
72
75
|
|
|
73
|
-
|
|
74
|
-
|
|
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
|
+
```
|
|
75
82
|
|
|
76
|
-
|
|
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
|
+
```
|
|
77
90
|
|
|
91
|
+
**Non-ActiveRecord objects:**
|
|
78
92
|
```ruby
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
93
|
+
class BackgroundJob
|
|
94
|
+
def to_s
|
|
95
|
+
"BackgroundJob-#{object_id}"
|
|
96
|
+
end
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
PaperTrail.request.whodunnit = BackgroundJob.new
|
|
100
|
+
PaperTrail.request.whodunnit # => "BackgroundJob-12345"
|
|
101
|
+
PaperTrail.request.actor # => "BackgroundJob-12345"
|
|
82
102
|
```
|
|
83
103
|
|
|
84
|
-
###
|
|
104
|
+
### Controller Integration
|
|
85
105
|
|
|
86
|
-
|
|
106
|
+
Set the actor automatically in your controllers using PaperTrail's built-in callback:
|
|
87
107
|
|
|
88
108
|
```ruby
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
admin = Admin.find_by(id: admin_id)
|
|
92
|
-
|
|
93
|
-
if admin.present?
|
|
94
|
-
first_product_version.whodunnit = admin
|
|
95
|
-
first_product_version.save
|
|
109
|
+
class ApplicationController < ActionController::Base
|
|
110
|
+
before_action :set_paper_trail_whodunnit
|
|
96
111
|
end
|
|
97
112
|
```
|
|
98
113
|
|
|
99
|
-
|
|
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.
|
|
100
115
|
|
|
101
|
-
|
|
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
|
+
```
|
|
102
124
|
|
|
103
|
-
|
|
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
|
+
```
|
|
104
131
|
|
|
105
|
-
|
|
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
|
+
```
|
|
106
139
|
|
|
107
|
-
|
|
140
|
+
Override `#user_for_paper_trail` to customize the actor selection logic:
|
|
108
141
|
|
|
109
142
|
```ruby
|
|
110
143
|
class ApplicationController < ActionController::Base
|
|
111
144
|
before_action :set_paper_trail_whodunnit
|
|
112
145
|
|
|
146
|
+
private
|
|
147
|
+
|
|
113
148
|
def user_for_paper_trail
|
|
114
149
|
logged_in? ? current_admin : "Public user"
|
|
115
150
|
end
|
|
116
151
|
end
|
|
117
152
|
```
|
|
118
153
|
|
|
119
|
-
|
|
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
|
|
120
181
|
|
|
121
|
-
|
|
122
|
-
2. Run the tests `bundle exec rake spec` to ensure that they all pass.
|
|
123
|
-
3. Lint the code `bundle exec rake standard:fix` to ensure that convention is maintained.
|
|
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.
|
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.5.
|
|
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-
|
|
11
|
+
date: 2025-11-15 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: paper_trail
|
|
@@ -108,8 +108,9 @@ dependencies:
|
|
|
108
108
|
- - ">="
|
|
109
109
|
- !ruby/object:Gem::Version
|
|
110
110
|
version: '0'
|
|
111
|
-
description: An extension to PaperTrail
|
|
112
|
-
object that was responsible for
|
|
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.
|
|
113
114
|
email:
|
|
114
115
|
- tristanfellows@icloud.com
|
|
115
116
|
executables: []
|
|
@@ -141,7 +142,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
|
141
142
|
requirements:
|
|
142
143
|
- - ">="
|
|
143
144
|
- !ruby/object:Gem::Version
|
|
144
|
-
version: '
|
|
145
|
+
version: '2.7'
|
|
145
146
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
146
147
|
requirements:
|
|
147
148
|
- - ">="
|
|
@@ -151,6 +152,5 @@ requirements: []
|
|
|
151
152
|
rubygems_version: 3.5.22
|
|
152
153
|
signing_key:
|
|
153
154
|
specification_version: 4
|
|
154
|
-
summary:
|
|
155
|
-
object that was responsible for changes
|
|
155
|
+
summary: Fetch the ActiveRecord object responsible for PaperTrail changes
|
|
156
156
|
test_files: []
|