whodunit 0.1.0 → 0.2.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 +2 -1
- data/CHANGELOG.md +54 -6
- data/README.md +76 -7
- data/exe/whodunit +18 -0
- data/lib/whodunit/controller_methods.rb +2 -2
- data/lib/whodunit/generator/application_record_integration.rb +85 -0
- data/lib/whodunit/generator.rb +134 -0
- data/lib/whodunit/migration_helpers.rb +94 -56
- data/lib/whodunit/railtie.rb +6 -0
- data/lib/whodunit/stampable.rb +115 -35
- data/lib/whodunit/table_definition_extension.rb +57 -0
- data/lib/whodunit/version.rb +1 -1
- data/lib/whodunit.rb +46 -4
- metadata +17 -10
- data/lib/whodunit/soft_delete_detector.rb +0 -119
data/lib/whodunit.rb
CHANGED
@@ -3,10 +3,10 @@
|
|
3
3
|
require "active_support/all"
|
4
4
|
require_relative "whodunit/version"
|
5
5
|
require_relative "whodunit/current"
|
6
|
-
require_relative "whodunit/soft_delete_detector"
|
7
6
|
require_relative "whodunit/stampable"
|
8
7
|
require_relative "whodunit/migration_helpers"
|
9
8
|
require_relative "whodunit/controller_methods"
|
9
|
+
require_relative "whodunit/table_definition_extension"
|
10
10
|
require_relative "whodunit/railtie"
|
11
11
|
|
12
12
|
# Lightweight creator/updater/deleter tracking for ActiveRecord models.
|
@@ -55,9 +55,15 @@ module Whodunit
|
|
55
55
|
# @return [Symbol] the deleter column name
|
56
56
|
mattr_accessor :deleter_column, default: :deleter_id
|
57
57
|
|
58
|
-
#
|
59
|
-
#
|
60
|
-
|
58
|
+
# The column name used for soft-delete timestamps (default: nil)
|
59
|
+
# Set to a column name to enable soft-delete support (e.g., :deleted_at, :discarded_at)
|
60
|
+
# Set to nil to disable soft-delete support entirely
|
61
|
+
# @return [Symbol, nil] the soft-delete column name
|
62
|
+
mattr_accessor :soft_delete_column, default: nil
|
63
|
+
|
64
|
+
# Whether to automatically add whodunit_stamps to create_table migrations (default: true)
|
65
|
+
# @return [Boolean] auto-injection setting
|
66
|
+
mattr_accessor :auto_inject_whodunit_stamps, default: true
|
61
67
|
|
62
68
|
# @!group Data Type Configuration
|
63
69
|
|
@@ -88,8 +94,10 @@ module Whodunit
|
|
88
94
|
#
|
89
95
|
# @yield [self] configuration block
|
90
96
|
# @return [void]
|
97
|
+
# @raise [Whodunit::Error] if both creator_column and updater_column are set to nil
|
91
98
|
def self.configure
|
92
99
|
yield self
|
100
|
+
validate_column_configuration!
|
93
101
|
end
|
94
102
|
|
95
103
|
# Get the user class name as a string
|
@@ -118,4 +126,38 @@ module Whodunit
|
|
118
126
|
def self.deleter_data_type
|
119
127
|
deleter_column_type || column_data_type
|
120
128
|
end
|
129
|
+
|
130
|
+
# Check if soft-delete is enabled
|
131
|
+
# @return [Boolean] true if soft-delete is configured (soft_delete_column is not nil)
|
132
|
+
def self.soft_delete_enabled?
|
133
|
+
!soft_delete_column.nil?
|
134
|
+
end
|
135
|
+
|
136
|
+
# Check if creator column is enabled
|
137
|
+
# @return [Boolean] true if creator_column is not nil
|
138
|
+
def self.creator_enabled?
|
139
|
+
!creator_column.nil?
|
140
|
+
end
|
141
|
+
|
142
|
+
# Check if updater column is enabled
|
143
|
+
# @return [Boolean] true if updater_column is not nil
|
144
|
+
def self.updater_enabled?
|
145
|
+
!updater_column.nil?
|
146
|
+
end
|
147
|
+
|
148
|
+
# Check if deleter column is enabled
|
149
|
+
# @return [Boolean] true if deleter_column is not nil
|
150
|
+
def self.deleter_enabled?
|
151
|
+
!deleter_column.nil?
|
152
|
+
end
|
153
|
+
|
154
|
+
# Validate that column configuration is valid
|
155
|
+
# @raise [Whodunit::Error] if both creator_column and updater_column are nil
|
156
|
+
def self.validate_column_configuration!
|
157
|
+
return if creator_enabled? || updater_enabled?
|
158
|
+
|
159
|
+
raise Whodunit::Error,
|
160
|
+
"At least one of creator_column or updater_column must be configured (not nil). " \
|
161
|
+
"Setting both to nil would disable all stamping functionality."
|
162
|
+
end
|
121
163
|
end
|
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.1
|
4
|
+
version: 0.2.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: 2025-07-
|
11
|
+
date: 2025-07-21 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activerecord
|
@@ -193,11 +193,11 @@ dependencies:
|
|
193
193
|
- !ruby/object:Gem::Version
|
194
194
|
version: 0.9.37
|
195
195
|
description: A lightweight Rails gem that provides simple auditing by tracking who
|
196
|
-
created, updated, and deleted ActiveRecord models.
|
197
|
-
and zero performance overhead.
|
196
|
+
created, updated, and deleted ActiveRecord models.
|
198
197
|
email:
|
199
198
|
- kenneth.c.demanawa@gmail.com
|
200
|
-
executables:
|
199
|
+
executables:
|
200
|
+
- whodunit
|
201
201
|
extensions: []
|
202
202
|
extra_rdoc_files: []
|
203
203
|
files:
|
@@ -209,16 +209,19 @@ files:
|
|
209
209
|
- LICENSE
|
210
210
|
- README.md
|
211
211
|
- Rakefile
|
212
|
+
- exe/whodunit
|
212
213
|
- gemfiles/rails_7_2.gemfile
|
213
214
|
- gemfiles/rails_8_2.gemfile
|
214
215
|
- gemfiles/rails_edge.gemfile
|
215
216
|
- lib/whodunit.rb
|
216
217
|
- lib/whodunit/controller_methods.rb
|
217
218
|
- lib/whodunit/current.rb
|
219
|
+
- lib/whodunit/generator.rb
|
220
|
+
- lib/whodunit/generator/application_record_integration.rb
|
218
221
|
- lib/whodunit/migration_helpers.rb
|
219
222
|
- lib/whodunit/railtie.rb
|
220
|
-
- lib/whodunit/soft_delete_detector.rb
|
221
223
|
- lib/whodunit/stampable.rb
|
224
|
+
- lib/whodunit/table_definition_extension.rb
|
222
225
|
- lib/whodunit/version.rb
|
223
226
|
- sig/whodunit.rbs
|
224
227
|
homepage: https://github.com/kanutocd/whodunit
|
@@ -230,17 +233,21 @@ metadata:
|
|
230
233
|
source_code_uri: https://github.com/kanutocd/whodunit.git
|
231
234
|
changelog_uri: https://github.com/kanutocd/whodunit/blob/main/CHANGELOG.md
|
232
235
|
bug_tracker_uri: https://github.com/kanutocd/whodunit/issues
|
233
|
-
documentation_uri: https://github.
|
236
|
+
documentation_uri: https://kanutocd.github.io/whodunit
|
234
237
|
rubygems_mfa_required: 'true'
|
235
|
-
post_install_message:
|
238
|
+
post_install_message: "\U0001F389 Thanks for installing Whodunit!\n\nWhat's next?\n\n1.
|
239
|
+
Generate configuration (recommended):\n whodunit install\n\n2. Add stamp columns
|
240
|
+
to your models:\n rails generate migration AddStampsToUsers\n # Then add: add_whodunit_stamps
|
241
|
+
:users\n\n3. Include Whodunit::Stampable in your models:\n class User < ApplicationRecord\n
|
242
|
+
\ include Whodunit::Stampable\n end\n\n\U0001F4D6 Complete documentation: https://kanutocd.github.io/whodunit\n"
|
236
243
|
rdoc_options: []
|
237
244
|
require_paths:
|
238
245
|
- lib
|
239
246
|
required_ruby_version: !ruby/object:Gem::Requirement
|
240
247
|
requirements:
|
241
|
-
- - "
|
248
|
+
- - ">"
|
242
249
|
- !ruby/object:Gem::Version
|
243
|
-
version: 3.
|
250
|
+
version: '3.1'
|
244
251
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
245
252
|
requirements:
|
246
253
|
- - ">="
|
@@ -1,119 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Whodunit
|
4
|
-
# Smart detection of soft-delete implementations.
|
5
|
-
#
|
6
|
-
# This class provides multi-layered detection for various soft-delete implementations
|
7
|
-
# including popular gems like Discard and Paranoia, as well as custom implementations.
|
8
|
-
#
|
9
|
-
# @example Check if a model has soft-delete enabled
|
10
|
-
# class Post < ApplicationRecord
|
11
|
-
# # has deleted_at column
|
12
|
-
# end
|
13
|
-
#
|
14
|
-
# Whodunit::SoftDeleteDetector.enabled_for?(Post) # => true
|
15
|
-
#
|
16
|
-
# @example With Discard gem
|
17
|
-
# class Post < ApplicationRecord
|
18
|
-
# include Discard::Model
|
19
|
-
# end
|
20
|
-
#
|
21
|
-
# Whodunit::SoftDeleteDetector.enabled_for?(Post) # => true
|
22
|
-
#
|
23
|
-
# @since 0.1.0
|
24
|
-
class SoftDeleteDetector
|
25
|
-
# Main detection method that checks if soft-delete is enabled for a model.
|
26
|
-
#
|
27
|
-
# Uses multiple detection strategies:
|
28
|
-
# 1. Gem-based detection (Discard, Paranoia, etc.)
|
29
|
-
# 2. Column pattern detection (deleted_at, discarded_at, etc.)
|
30
|
-
# 3. Method-based detection (respond_to? soft-delete methods)
|
31
|
-
#
|
32
|
-
# @param model [Class] the ActiveRecord model class to check
|
33
|
-
# @return [Boolean] true if soft-delete is detected, false otherwise
|
34
|
-
# @example
|
35
|
-
# Whodunit::SoftDeleteDetector.enabled_for?(Post) # => true
|
36
|
-
# Whodunit::SoftDeleteDetector.enabled_for?(User) # => false
|
37
|
-
def self.enabled_for?(model)
|
38
|
-
return false unless model.respond_to?(:columns)
|
39
|
-
|
40
|
-
gem_based_detection?(model) ||
|
41
|
-
column_pattern_detection(model) ||
|
42
|
-
method_based_detection(model)
|
43
|
-
end
|
44
|
-
|
45
|
-
# Detect popular soft-delete gems.
|
46
|
-
#
|
47
|
-
# Detects the following gems:
|
48
|
-
# - Discard (checks for Discard module inclusion)
|
49
|
-
# - Paranoia (checks for paranoid? method and Paranoid ancestors)
|
50
|
-
# - ActsAsParanoid (checks for acts_as_paranoid method)
|
51
|
-
#
|
52
|
-
# @param model [Class] the ActiveRecord model class to check
|
53
|
-
# @return [Boolean] true if a gem-based soft-delete is detected
|
54
|
-
# @api private
|
55
|
-
def self.gem_based_detection?(model)
|
56
|
-
# Discard gem
|
57
|
-
return true if model.included_modules.any? { |mod| mod.to_s.include?("Discard") }
|
58
|
-
|
59
|
-
# Paranoia gem
|
60
|
-
return true if model.respond_to?(:paranoid?) ||
|
61
|
-
model.respond_to?(:acts_as_paranoid) ||
|
62
|
-
model.ancestors.any? { |a| a.to_s.include?("Paranoid") }
|
63
|
-
|
64
|
-
# ActsAsParanoid (older version)
|
65
|
-
return true if model.respond_to?(:acts_as_paranoid)
|
66
|
-
|
67
|
-
false
|
68
|
-
end
|
69
|
-
|
70
|
-
# Detect soft-delete by column patterns.
|
71
|
-
#
|
72
|
-
# Looks for common soft-delete column names:
|
73
|
-
# - deleted_at, destroyed_at, discarded_at, archived_at
|
74
|
-
# - soft_deleted_at, soft_destroyed_at, removed_at
|
75
|
-
#
|
76
|
-
# Only considers timestamp columns (datetime, timestamp, date).
|
77
|
-
#
|
78
|
-
# @param model [Class] the ActiveRecord model class to check
|
79
|
-
# @return [Boolean] true if soft-delete columns are found
|
80
|
-
# @api private
|
81
|
-
def self.column_pattern_detection(model)
|
82
|
-
soft_delete_columns = %w[
|
83
|
-
deleted_at destroyed_at discarded_at archived_at
|
84
|
-
soft_deleted_at soft_destroyed_at removed_at
|
85
|
-
]
|
86
|
-
|
87
|
-
model.columns.any? do |column|
|
88
|
-
soft_delete_columns.include?(column.name) &&
|
89
|
-
timestamp_column?(column)
|
90
|
-
end
|
91
|
-
end
|
92
|
-
|
93
|
-
# Detect soft-delete by method presence.
|
94
|
-
#
|
95
|
-
# Checks if the model responds to common soft-delete method names.
|
96
|
-
# This catches custom implementations that follow standard naming conventions.
|
97
|
-
#
|
98
|
-
# @param model [Class] the ActiveRecord model class to check
|
99
|
-
# @return [Boolean] true if soft-delete methods are found
|
100
|
-
# @api private
|
101
|
-
def self.method_based_detection(model)
|
102
|
-
soft_delete_methods = %w[
|
103
|
-
deleted_at destroyed_at discarded_at archived_at
|
104
|
-
soft_deleted_at soft_destroyed_at removed_at
|
105
|
-
]
|
106
|
-
|
107
|
-
soft_delete_methods.any? { |method| model.respond_to?(method) }
|
108
|
-
end
|
109
|
-
|
110
|
-
# Check if a column is a timestamp type.
|
111
|
-
#
|
112
|
-
# @param column [Object] the column object (responds to #type)
|
113
|
-
# @return [Boolean] true if the column is a timestamp type
|
114
|
-
# @api private
|
115
|
-
def self.timestamp_column?(column)
|
116
|
-
%i[datetime timestamp date].include?(column.type)
|
117
|
-
end
|
118
|
-
end
|
119
|
-
end
|