whodunit 0.3.1 → 0.4.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/.rubocop.yml +4 -3
- data/CHANGELOG.md +51 -1
- data/README.md +2 -2
- data/lib/whodunit/railtie.rb +6 -6
- data/lib/whodunit/stampable.rb +49 -6
- data/lib/whodunit/table_definition_extension.rb +15 -12
- data/lib/whodunit/version.rb +1 -1
- metadata +18 -4
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: ec3f89bd20ea577eb0a740137c86a7927500ccd189e9d9375d18b21c0b36ffdc
|
|
4
|
+
data.tar.gz: 20586d959bc0d25a47319f615f333021d1ebbec331d865c6a18400987f24ef39
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 5cca573bee0c6d0313d5adf4079e18996d4bc5ecf354b7de39f77e9537b078c67d6122d4a2a7c8c3314ec9da44f40a5ec262a573c06e12b092f86935a951b327
|
|
7
|
+
data.tar.gz: 810bd48aaf36a9605802c62d8f6616d0d68eb63b78a2f92c955c0f06b0cc609f0f6c729274bfc33d5caf42e8263ce8a49d4aa253480db7103dd0c0ea756ce5e1
|
data/.rubocop.yml
CHANGED
|
@@ -6,7 +6,7 @@ plugins:
|
|
|
6
6
|
|
|
7
7
|
AllCops:
|
|
8
8
|
NewCops: enable
|
|
9
|
-
TargetRubyVersion: 3.
|
|
9
|
+
TargetRubyVersion: 3.2
|
|
10
10
|
Exclude:
|
|
11
11
|
- 'vendor/**/*'
|
|
12
12
|
- 'tmp/**/*'
|
|
@@ -35,6 +35,7 @@ Metrics/BlockLength:
|
|
|
35
35
|
|
|
36
36
|
# Allow longer methods in specs and configuration
|
|
37
37
|
Metrics/MethodLength:
|
|
38
|
+
Max: 15
|
|
38
39
|
Exclude:
|
|
39
40
|
- 'spec/**/*'
|
|
40
41
|
|
|
@@ -114,12 +115,12 @@ Metrics/AbcSize:
|
|
|
114
115
|
- 'spec/**/*'
|
|
115
116
|
|
|
116
117
|
Metrics/CyclomaticComplexity:
|
|
117
|
-
Max:
|
|
118
|
+
Max: 10
|
|
118
119
|
Exclude:
|
|
119
120
|
- 'spec/**/*'
|
|
120
121
|
|
|
121
122
|
Metrics/PerceivedComplexity:
|
|
122
|
-
Max:
|
|
123
|
+
Max: 10
|
|
123
124
|
Exclude:
|
|
124
125
|
- 'spec/**/*'
|
|
125
126
|
Gemspec/DevelopmentDependencies:
|
data/CHANGELOG.md
CHANGED
|
@@ -5,7 +5,57 @@ All notable changes to this project will be documented in this file.
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
7
|
|
|
8
|
-
## [
|
|
8
|
+
## [0.4.1] - 2026-06-01
|
|
9
|
+
|
|
10
|
+
### Fixed
|
|
11
|
+
|
|
12
|
+
- Fixed `Whodunit::Stampable` when included on an abstract ActiveRecord base class, such as `ApplicationRecord`. Association setup and model registration are now deferred to concrete subclasses.
|
|
13
|
+
- Preserved existing `inherited` hooks by prepending an internal hook instead of replacing `self.inherited`.
|
|
14
|
+
- Supported multi-level abstract inheritance, such as `ApplicationRecord -> TenantRecord -> Post`, without registering abstract classes.
|
|
15
|
+
|
|
16
|
+
### Added
|
|
17
|
+
|
|
18
|
+
- Added RSpec regression coverage for abstract-base inclusion, inherited-hook preservation, abstract subclass exclusion, concrete subclass registration, multi-level abstract inheritance, and inherited callback stamping.
|
|
19
|
+
|
|
20
|
+
## [0.4.0] - 2025-05-20
|
|
21
|
+
|
|
22
|
+
### Breaking Changes
|
|
23
|
+
|
|
24
|
+
- Dropped support for Ruby 3.1. Minimum supported Ruby version is now **3.2**.
|
|
25
|
+
|
|
26
|
+
### Fixed
|
|
27
|
+
|
|
28
|
+
- `TableDefinitionExtension`: replaced `included { attr_accessor :_whodunit_stamps_added }` with
|
|
29
|
+
explicit reader/writer methods so the accessor is defined correctly when the module is **prepended**
|
|
30
|
+
(as the Railtie does) rather than included. Previously the accessor was silently missing in
|
|
31
|
+
production, causing `@_whodunit_stamps_added` to be inaccessible via the public API.
|
|
32
|
+
|
|
33
|
+
### Changed
|
|
34
|
+
|
|
35
|
+
- **Test suite**: eliminated all hand-rolled ActiveRecord and Railtie mocks in favour of genuine
|
|
36
|
+
infrastructure — real `ActiveRecord::Base` subclasses backed by an in-memory SQLite3 database,
|
|
37
|
+
and real `ActiveRecord::ConnectionAdapters::TableDefinition` instances for migration-helper tests.
|
|
38
|
+
Callbacks, dirty tracking, `belongs_to` reflections, and `column_names` now go through actual AR
|
|
39
|
+
code paths rather than no-op stubs.
|
|
40
|
+
- `spec/support/rails_mocks.rb` — emptied; `activesupport` is a runtime dependency and needs no
|
|
41
|
+
re-implementation in tests.
|
|
42
|
+
- `spec/support/test_models.rb` — replaced `MockActiveRecord` stub class with real AR models
|
|
43
|
+
(`WhodunitRecord`, `WhodunitSoftDeleteRecord`) on an in-memory SQLite3 schema; backward-compat
|
|
44
|
+
aliases preserved.
|
|
45
|
+
- `spec/spec_helper.rb` — added `rescue Bundler::GemNotFound` guard on `require "bundler/setup"`
|
|
46
|
+
to allow running specs directly without `bundle exec`; wrapped every example in an AR transaction
|
|
47
|
+
that rolls back on completion; added missing config keys to `ORIGINAL_WHODUNIT_CONFIG`.
|
|
48
|
+
- `spec/whodunit/table_definition_extension_spec.rb` — now tests the real
|
|
49
|
+
`ActiveRecord::ConnectionAdapters::TableDefinition` with `TableDefinitionExtension` prepended,
|
|
50
|
+
rather than an anonymous class that reimplemented the extension logic internally.
|
|
51
|
+
- `spec/whodunit/stampable_spec.rb` — `being_soft_deleted?` tests use real AR dirty tracking via
|
|
52
|
+
genuine attribute writes; callback-integration tests persist records and assert database values
|
|
53
|
+
after `reload`.
|
|
54
|
+
- `spec/whodunit/migration_helpers_spec.rb` — `whodunit_stamps(table_def)` path uses a real
|
|
55
|
+
`TableDefinitionExtension`-prepended `TableDefinition` instance instead of a double.
|
|
56
|
+
- `spec/whodunit/per_model_config_spec.rb`, `railtie_spec.rb`,
|
|
57
|
+
`reverse_associations_integration_spec.rb` — all converted to real AR anonymous subclasses;
|
|
58
|
+
removed stubs for `before_create`, `belongs_to`, and `column_names`.
|
|
9
59
|
|
|
10
60
|
## [0.3.0] - 2025-01-24
|
|
11
61
|
|
data/README.md
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
[](https://badge.fury.io/rb/whodunit)
|
|
4
4
|
[](https://github.com/kanutocd/whodunit/actions)
|
|
5
5
|
[](https://codecov.io/gh/kanutocd/whodunit)
|
|
6
|
-
[](https://www.ruby-lang.org/en/)
|
|
7
7
|
[](https://opensource.org/licenses/MIT)
|
|
8
8
|
|
|
9
9
|
Lightweight creator/updater/deleter tracking for Rails ActiveRecord models.
|
|
@@ -16,7 +16,7 @@ Whodunit provides simple auditing for Rails applications by tracking who created
|
|
|
16
16
|
|
|
17
17
|
## Requirements
|
|
18
18
|
|
|
19
|
-
- Ruby 3.
|
|
19
|
+
- Ruby 3.2+ (tested on 3.2, 3.3, 3.4, 4.0). See the [the ruby-version matrix strategy of the CI workflow](https://github.com/kanutocd/whodunit/blob/main/.github/workflows/ci.yml#L15).
|
|
20
20
|
- Rails 7.2+ (tested on 7.2, 8.2, and edge)
|
|
21
21
|
- ActiveRecord for database operations
|
|
22
22
|
|
data/lib/whodunit/railtie.rb
CHANGED
|
@@ -22,19 +22,19 @@ module Whodunit
|
|
|
22
22
|
|
|
23
23
|
# Extend ActiveRecord with migration helpers.
|
|
24
24
|
#
|
|
25
|
-
# This initializer adds the MigrationHelpers module to ActiveRecord,
|
|
25
|
+
# This initializer adds the MigrationHelpers module to ActiveRecord::Migration,
|
|
26
26
|
# making methods like add_whodunit_stamps available in migrations.
|
|
27
27
|
# It also extends TableDefinition for automatic whodunit_stamps injection.
|
|
28
28
|
#
|
|
29
29
|
# @api private
|
|
30
30
|
initializer "whodunit.extend_active_record" do |_app|
|
|
31
31
|
ActiveSupport.on_load(:active_record) do
|
|
32
|
-
|
|
32
|
+
ActiveRecord::Migration.include(Whodunit::MigrationHelpers)
|
|
33
33
|
|
|
34
|
-
#
|
|
35
|
-
ActiveRecord::ConnectionAdapters::TableDefinition.
|
|
36
|
-
|
|
37
|
-
)
|
|
34
|
+
# We use ActiveRecord::ConnectionAdapters::TableDefinition#timestamps to automatically inject whodunit_stamps
|
|
35
|
+
ActiveRecord::ConnectionAdapters::TableDefinition.prepend(Whodunit::TableDefinitionExtension)
|
|
36
|
+
# Reuse the `whodunit_stamps` flow in Whodunit::MigrationHelpers module
|
|
37
|
+
ActiveRecord::ConnectionAdapters::TableDefinition.extend(Whodunit::MigrationHelpers)
|
|
38
38
|
end
|
|
39
39
|
end
|
|
40
40
|
|
data/lib/whodunit/stampable.rb
CHANGED
|
@@ -50,12 +50,16 @@ module Whodunit
|
|
|
50
50
|
before_destroy :set_whodunit_deleter, if: :deleter_column?
|
|
51
51
|
before_update :set_whodunit_deleter, if: :being_soft_deleted?
|
|
52
52
|
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
53
|
+
if abstract_class?
|
|
54
|
+
install_whodunit_inherited_hook
|
|
55
|
+
else
|
|
56
|
+
# Set up associations - call on the including concrete class.
|
|
57
|
+
setup_whodunit_associations
|
|
58
|
+
|
|
59
|
+
# Register this including model for reverse association setup.
|
|
60
|
+
# This happens immediately, but the check for enabled status is done in register_model.
|
|
61
|
+
Whodunit.register_model(self)
|
|
62
|
+
end
|
|
59
63
|
end
|
|
60
64
|
|
|
61
65
|
class_methods do # rubocop:disable Metrics/BlockLength
|
|
@@ -144,7 +148,46 @@ module Whodunit
|
|
|
144
148
|
|
|
145
149
|
private
|
|
146
150
|
|
|
151
|
+
# Install an inherited hook when Stampable is included on an abstract ActiveRecord
|
|
152
|
+
# base class, such as ApplicationRecord. Associations require concrete table
|
|
153
|
+
# metadata, so setup must be deferred until concrete subclasses are defined.
|
|
154
|
+
#
|
|
155
|
+
# The hook is prepended instead of assigned with `def self.inherited` so existing
|
|
156
|
+
# inherited hooks on the application base class remain intact. When the subclass
|
|
157
|
+
# is also abstract, the same hook is propagated so multi-level abstract
|
|
158
|
+
# inheritance is supported.
|
|
159
|
+
#
|
|
160
|
+
# @return [void]
|
|
161
|
+
# @api private
|
|
162
|
+
def install_whodunit_inherited_hook
|
|
163
|
+
return if instance_variable_defined?(:@whodunit_inherited_hook_installed) &&
|
|
164
|
+
@whodunit_inherited_hook_installed
|
|
165
|
+
|
|
166
|
+
inherited_hook = Module.new do
|
|
167
|
+
def inherited(subclass)
|
|
168
|
+
super
|
|
169
|
+
|
|
170
|
+
subclass.send(:install_whodunit_inherited_hook)
|
|
171
|
+
|
|
172
|
+
return if subclass.abstract_class?
|
|
173
|
+
return if subclass.name.nil?
|
|
174
|
+
|
|
175
|
+
subclass.send(:setup_whodunit_associations)
|
|
176
|
+
Whodunit.register_model(subclass)
|
|
177
|
+
end
|
|
178
|
+
end
|
|
179
|
+
|
|
180
|
+
singleton_class.prepend(inherited_hook)
|
|
181
|
+
@whodunit_inherited_hook_installed = true
|
|
182
|
+
end
|
|
183
|
+
|
|
184
|
+
# Set up associations for concrete ActiveRecord models.
|
|
185
|
+
#
|
|
186
|
+
# @return [void]
|
|
187
|
+
# @api private
|
|
147
188
|
def setup_whodunit_associations
|
|
189
|
+
return if abstract_class?
|
|
190
|
+
|
|
148
191
|
setup_creator_association if creator_column_exists? && model_creator_enabled?
|
|
149
192
|
setup_updater_association if updater_column_exists? && model_updater_enabled?
|
|
150
193
|
setup_deleter_association if deleter_column_exists? && model_deleter_enabled? && soft_delete_enabled?
|
|
@@ -28,30 +28,33 @@ module Whodunit
|
|
|
28
28
|
module TableDefinitionExtension
|
|
29
29
|
extend ActiveSupport::Concern
|
|
30
30
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
31
|
+
def _whodunit_stamps_added
|
|
32
|
+
@_whodunit_stamps_added
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def _whodunit_stamps_added=(value)
|
|
36
|
+
@_whodunit_stamps_added = value
|
|
34
37
|
end
|
|
35
38
|
|
|
36
39
|
# Override timestamps to trigger automatic whodunit_stamps injection
|
|
37
40
|
def timestamps(**options)
|
|
41
|
+
options = options.dup
|
|
42
|
+
skip = options.delete(:skip_whodunit_stamps)
|
|
38
43
|
result = super
|
|
39
44
|
|
|
40
|
-
|
|
41
|
-
if Whodunit.auto_inject_whodunit_stamps &&
|
|
42
|
-
!@_whodunit_stamps_added &&
|
|
43
|
-
!options[:skip_whodunit_stamps]
|
|
45
|
+
if Whodunit.auto_inject_whodunit_stamps && !_whodunit_stamps_added && !skip
|
|
44
46
|
whodunit_stamps(include_deleter: :auto)
|
|
45
|
-
@_whodunit_stamps_added = true
|
|
46
47
|
end
|
|
47
48
|
|
|
48
49
|
result
|
|
49
50
|
end
|
|
50
51
|
|
|
51
|
-
#
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
52
|
+
# assign true tp the tracker `@_whodunit_stamps_added` before the
|
|
53
|
+
# reuse/call of the `whodunit_stamps` flow from the Whodunit::MigrationHelpers module (see railtie.rb)
|
|
54
|
+
#
|
|
55
|
+
def whodunit_stamps(include_deleter: :auto, creator_type: nil, updater_type: nil, deleter_type: nil)
|
|
56
|
+
self._whodunit_stamps_added = true
|
|
57
|
+
self.class.whodunit_stamps(self, include_deleter:, creator_type:, updater_type:, deleter_type:)
|
|
55
58
|
end
|
|
56
59
|
end
|
|
57
60
|
end
|
data/lib/whodunit/version.rb
CHANGED
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: whodunit
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.4.1
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Ken C. Demanawa
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: exe
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2026-05-
|
|
11
|
+
date: 2026-05-31 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: activerecord
|
|
@@ -192,6 +192,20 @@ dependencies:
|
|
|
192
192
|
- - ">="
|
|
193
193
|
- !ruby/object:Gem::Version
|
|
194
194
|
version: '3.0'
|
|
195
|
+
- !ruby/object:Gem::Dependency
|
|
196
|
+
name: sqlite3
|
|
197
|
+
requirement: !ruby/object:Gem::Requirement
|
|
198
|
+
requirements:
|
|
199
|
+
- - "~>"
|
|
200
|
+
- !ruby/object:Gem::Version
|
|
201
|
+
version: '2.9'
|
|
202
|
+
type: :development
|
|
203
|
+
prerelease: false
|
|
204
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
205
|
+
requirements:
|
|
206
|
+
- - "~>"
|
|
207
|
+
- !ruby/object:Gem::Version
|
|
208
|
+
version: '2.9'
|
|
195
209
|
- !ruby/object:Gem::Dependency
|
|
196
210
|
name: yard
|
|
197
211
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -259,9 +273,9 @@ require_paths:
|
|
|
259
273
|
- lib
|
|
260
274
|
required_ruby_version: !ruby/object:Gem::Requirement
|
|
261
275
|
requirements:
|
|
262
|
-
- - "
|
|
276
|
+
- - ">="
|
|
263
277
|
- !ruby/object:Gem::Version
|
|
264
|
-
version: '3.
|
|
278
|
+
version: '3.2'
|
|
265
279
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
266
280
|
requirements:
|
|
267
281
|
- - ">="
|