Module: Whodunit
- Defined in:
- lib/whodunit.rb,
lib/whodunit/current.rb,
lib/whodunit/railtie.rb,
lib/whodunit/version.rb,
lib/whodunit/generator.rb,
lib/whodunit/stampable.rb,
lib/whodunit/migration_helpers.rb,
lib/whodunit/controller_methods.rb,
lib/whodunit/table_definition_extension.rb,
lib/whodunit/generator/application_record_integration.rb
Overview
Lightweight creator/updater/deleter tracking for ActiveRecord models.
Whodunit provides simple auditing by tracking who created, updated, and deleted ActiveRecord models. It features smart soft-delete detection and zero performance overhead.
Defined Under Namespace
Modules: ControllerMethods, MigrationHelpers, Stampable, TableDefinitionExtension Classes: Current, Error, Generator, Railtie
Constant Summary collapse
- VERSION =
"0.3.0"
Configuration collapse
-
#auto_inject_whodunit_stamps ⇒ Boolean
Whether to automatically add whodunit_stamps to create_table migrations (default: true).
-
#creator_column ⇒ Symbol
The column name for tracking who created the record (default: :creator_id).
-
#deleter_column ⇒ Symbol
The column name for tracking who deleted the record (default: :deleter_id).
-
#soft_delete_column ⇒ Symbol?
The column name used for soft-delete timestamps (default: nil) Set to a column name to enable soft-delete support (e.g., :deleted_at, :discarded_at) Set to nil to disable soft-delete support entirely.
-
#updater_column ⇒ Symbol
The column name for tracking who updated the record (default: :updater_id).
-
#user_class ⇒ String
The class name of the user model (default: “User”).
Data Type Configuration collapse
-
#column_data_type ⇒ Symbol
The default data type for stamp columns (default: :bigint).
-
#creator_column_type ⇒ Symbol?
Specific data type for creator column (overrides column_data_type if set).
-
#deleter_column_type ⇒ Symbol?
Specific data type for deleter column (overrides column_data_type if set).
-
#updater_column_type ⇒ Symbol?
Specific data type for updater column (overrides column_data_type if set).
Reverse Association Configuration collapse
-
#auto_setup_reverse_associations ⇒ Boolean
Whether to automatically set up reverse associations on the user class (default: true) When enabled, including Whodunit::Stampable in a model will automatically add has_many associations to the user class (e.g., has_many :created_posts).
-
#reverse_association_prefix ⇒ String
Prefix for reverse association names (default: “”) Used to generate association names like “created_posts”, “updated_comments”.
-
#reverse_association_suffix ⇒ String
Suffix for reverse association names (default: “”) Used to generate association names like “posts_created”, “comments_updated”.
Model Registry collapse
-
.configure {|self| ... } ⇒ void
Configure Whodunit settings.
-
.user_class_name ⇒ String
Get the user class name as a string.
-
#registered_models ⇒ Array<Class>
Registry to track models that include Whodunit::Stampable This is used to set up reverse associations on the user class.
Data Type Helpers collapse
-
.creator_data_type ⇒ Symbol
Get the data type for the creator column.
-
.creator_enabled? ⇒ Boolean
Check if creator column is enabled.
-
.deleter_data_type ⇒ Symbol
Get the data type for the deleter column.
-
.deleter_enabled? ⇒ Boolean
Check if deleter column is enabled.
-
.soft_delete_enabled? ⇒ Boolean
Check if soft-delete is enabled.
-
.updater_data_type ⇒ Symbol
Get the data type for the updater column.
-
.updater_enabled? ⇒ Boolean
Check if updater column is enabled.
Model Registration & Reverse Associations collapse
-
.generate_reverse_association_name(action, model_plural) ⇒ String
Generate a reverse association name based on action and model name.
-
.register_model(model_class) ⇒ void
Register a model class that includes Whodunit::Stampable This is called automatically when Stampable is included.
-
.resolve_foreign_key(model_class, foreign_key_column) ⇒ Symbol
Resolve the actual foreign key column name from model configuration.
-
.resolve_user_class ⇒ Class?
Resolve the user class constant.
-
.setup_all_reverse_associations ⇒ void
Set up all reverse associations for all registered models This can be called manually if needed (e.g., after configuration changes).
-
.setup_creator_reverse_association(user_class_instance, model_class, model_plural) ⇒ void
Set up creator reverse association.
-
.setup_deleter_reverse_association(user_class_instance, model_class, model_plural) ⇒ void
Set up deleter reverse association.
-
.setup_reverse_associations_for_model(model_class) ⇒ void
Set up reverse associations on the user class for a specific model.
-
.setup_updater_reverse_association(user_class_instance, model_class, model_plural) ⇒ void
Set up updater reverse association.
-
.setup_user_reverse_association(user_class_instance, association_name, model_class, foreign_key_column) ⇒ void
Set up a specific reverse association on the user class.
-
.validate_column_configuration! ⇒ Object
Validate that column configuration is valid.
Class Method Details
.configure {|self| ... } ⇒ void
This method returns an undefined value.
Configure Whodunit settings
123 124 125 126 |
# File 'lib/whodunit.rb', line 123 def self.configure yield self validate_column_configuration! end |
.creator_data_type ⇒ Symbol
Get the data type for the creator column
139 140 141 |
# File 'lib/whodunit.rb', line 139 def self.creator_data_type creator_column_type || column_data_type end |
.creator_enabled? ⇒ Boolean
Check if creator column is enabled
163 164 165 |
# File 'lib/whodunit.rb', line 163 def self.creator_enabled? !creator_column.nil? end |
.deleter_data_type ⇒ Symbol
Get the data type for the deleter column
151 152 153 |
# File 'lib/whodunit.rb', line 151 def self.deleter_data_type deleter_column_type || column_data_type end |
.deleter_enabled? ⇒ Boolean
Check if deleter column is enabled
175 176 177 |
# File 'lib/whodunit.rb', line 175 def self.deleter_enabled? !deleter_column.nil? end |
.generate_reverse_association_name(action, model_plural) ⇒ String
Generate a reverse association name based on action and model name
224 225 226 |
# File 'lib/whodunit.rb', line 224 def self.generate_reverse_association_name(action, model_plural) "#{reverse_association_prefix}#{action}_#{model_plural}#{reverse_association_suffix}" end |
.register_model(model_class) ⇒ void
This method returns an undefined value.
Register a model class that includes Whodunit::Stampable This is called automatically when Stampable is included
185 186 187 188 189 190 191 192 193 |
# File 'lib/whodunit.rb', line 185 def self.register_model(model_class) return unless auto_setup_reverse_associations return if registered_models.include?(model_class) return if model_class.respond_to?(:whodunit_reverse_associations_enabled?) && !model_class.whodunit_reverse_associations_enabled? registered_models << model_class setup_reverse_associations_for_model(model_class) end |
.resolve_foreign_key(model_class, foreign_key_column) ⇒ Symbol
Resolve the actual foreign key column name from model configuration
295 296 297 298 299 300 301 302 303 304 305 306 |
# File 'lib/whodunit.rb', line 295 def self.resolve_foreign_key(model_class, foreign_key_column) return foreign_key_column unless model_class.respond_to?(:whodunit_setting) column_mapping = { creator_id: :creator_column, updater_id: :updater_column, deleter_id: :deleter_column } setting_key = column_mapping[foreign_key_column] setting_key ? (model_class.whodunit_setting(setting_key) || foreign_key_column) : foreign_key_column end |
.resolve_user_class ⇒ Class?
Resolve the user class constant
230 231 232 233 234 |
# File 'lib/whodunit.rb', line 230 def self.resolve_user_class user_class.constantize rescue StandardError nil end |
.setup_all_reverse_associations ⇒ void
This method returns an undefined value.
Set up all reverse associations for all registered models This can be called manually if needed (e.g., after configuration changes)
214 215 216 217 218 |
# File 'lib/whodunit.rb', line 214 def self.setup_all_reverse_associations registered_models.each do |model_class| setup_reverse_associations_for_model(model_class) end end |
.setup_creator_reverse_association(user_class_instance, model_class, model_plural) ⇒ void
This method returns an undefined value.
Set up creator reverse association
241 242 243 244 245 246 |
# File 'lib/whodunit.rb', line 241 def self.setup_creator_reverse_association(user_class_instance, model_class, model_plural) return unless model_class.respond_to?(:model_creator_enabled?) && model_class.model_creator_enabled? association_name = generate_reverse_association_name("created", model_plural) setup_user_reverse_association(user_class_instance, association_name, model_class, :creator_id) end |
.setup_deleter_reverse_association(user_class_instance, model_class, model_plural) ⇒ void
This method returns an undefined value.
Set up deleter reverse association
265 266 267 268 269 270 271 |
# File 'lib/whodunit.rb', line 265 def self.setup_deleter_reverse_association(user_class_instance, model_class, model_plural) return unless model_class.respond_to?(:model_deleter_enabled?) && model_class.model_deleter_enabled? return unless model_class.respond_to?(:soft_delete_enabled?) && model_class.soft_delete_enabled? association_name = generate_reverse_association_name("deleted", model_plural) setup_user_reverse_association(user_class_instance, association_name, model_class, :deleter_id) end |
.setup_reverse_associations_for_model(model_class) ⇒ void
This method returns an undefined value.
Set up reverse associations on the user class for a specific model
198 199 200 201 202 203 204 205 206 207 208 209 |
# File 'lib/whodunit.rb', line 198 def self.setup_reverse_associations_for_model(model_class) return unless auto_setup_reverse_associations user_class_instance = resolve_user_class return unless user_class_instance.respond_to?(:has_many) model_plural = model_class.name.underscore.pluralize setup_creator_reverse_association(user_class_instance, model_class, model_plural) setup_updater_reverse_association(user_class_instance, model_class, model_plural) setup_deleter_reverse_association(user_class_instance, model_class, model_plural) end |
.setup_updater_reverse_association(user_class_instance, model_class, model_plural) ⇒ void
This method returns an undefined value.
Set up updater reverse association
253 254 255 256 257 258 |
# File 'lib/whodunit.rb', line 253 def self.setup_updater_reverse_association(user_class_instance, model_class, model_plural) return unless model_class.respond_to?(:model_updater_enabled?) && model_class.model_updater_enabled? association_name = generate_reverse_association_name("updated", model_plural) setup_user_reverse_association(user_class_instance, association_name, model_class, :updater_id) end |
.setup_user_reverse_association(user_class_instance, association_name, model_class, foreign_key_column) ⇒ void
This method returns an undefined value.
Set up a specific reverse association on the user class
279 280 281 282 283 284 285 286 287 288 289 |
# File 'lib/whodunit.rb', line 279 def self.setup_user_reverse_association(user_class_instance, association_name, model_class, foreign_key_column) actual_foreign_key = resolve_foreign_key(model_class, foreign_key_column) # Check if association already exists to avoid duplicates return if user_class_instance.reflect_on_association(association_name.to_sym) user_class_instance.has_many association_name.to_sym, class_name: model_class.name, foreign_key: actual_foreign_key, dependent: :nullify end |
.soft_delete_enabled? ⇒ Boolean
Check if soft-delete is enabled
157 158 159 |
# File 'lib/whodunit.rb', line 157 def self.soft_delete_enabled? !soft_delete_column.nil? end |
.updater_data_type ⇒ Symbol
Get the data type for the updater column
145 146 147 |
# File 'lib/whodunit.rb', line 145 def self.updater_data_type updater_column_type || column_data_type end |
.updater_enabled? ⇒ Boolean
Check if updater column is enabled
169 170 171 |
# File 'lib/whodunit.rb', line 169 def self.updater_enabled? !updater_column.nil? end |
.user_class_name ⇒ String
Get the user class name as a string
131 132 133 |
# File 'lib/whodunit.rb', line 131 def self.user_class_name user_class.to_s end |
.validate_column_configuration! ⇒ Object
Validate that column configuration is valid
310 311 312 313 314 315 316 |
# File 'lib/whodunit.rb', line 310 def self.validate_column_configuration! return if creator_enabled? || updater_enabled? raise Whodunit::Error, "At least one of creator_column or updater_column must be configured (not nil). " \ "Setting both to nil would disable all stamping functionality." end |
Instance Method Details
#auto_inject_whodunit_stamps ⇒ Boolean
Whether to automatically add whodunit_stamps to create_table migrations (default: true)
66 |
# File 'lib/whodunit.rb', line 66 mattr_accessor :auto_inject_whodunit_stamps, default: true |
#auto_setup_reverse_associations ⇒ Boolean
Whether to automatically set up reverse associations on the user class (default: true) When enabled, including Whodunit::Stampable in a model will automatically add has_many associations to the user class (e.g., has_many :created_posts)
92 |
# File 'lib/whodunit.rb', line 92 mattr_accessor :auto_setup_reverse_associations, default: true |
#column_data_type ⇒ Symbol
The default data type for stamp columns (default: :bigint)
72 |
# File 'lib/whodunit.rb', line 72 mattr_accessor :column_data_type, default: :bigint |
#creator_column ⇒ Symbol
The column name for tracking who created the record (default: :creator_id)
48 |
# File 'lib/whodunit.rb', line 48 mattr_accessor :creator_column, default: :creator_id |
#creator_column_type ⇒ Symbol?
Specific data type for creator column (overrides column_data_type if set)
76 |
# File 'lib/whodunit.rb', line 76 mattr_accessor :creator_column_type, default: nil |
#deleter_column ⇒ Symbol
The column name for tracking who deleted the record (default: :deleter_id)
56 |
# File 'lib/whodunit.rb', line 56 mattr_accessor :deleter_column, default: :deleter_id |
#deleter_column_type ⇒ Symbol?
Specific data type for deleter column (overrides column_data_type if set)
84 |
# File 'lib/whodunit.rb', line 84 mattr_accessor :deleter_column_type, default: nil |
#registered_models ⇒ Array<Class>
Registry to track models that include Whodunit::Stampable This is used to set up reverse associations on the user class
109 |
# File 'lib/whodunit.rb', line 109 mattr_accessor :registered_models, default: [] |
#reverse_association_prefix ⇒ String
Prefix for reverse association names (default: “”) Used to generate association names like “created_posts”, “updated_comments”
97 |
# File 'lib/whodunit.rb', line 97 mattr_accessor :reverse_association_prefix, default: "" |
#reverse_association_suffix ⇒ String
Suffix for reverse association names (default: “”) Used to generate association names like “posts_created”, “comments_updated”
102 |
# File 'lib/whodunit.rb', line 102 mattr_accessor :reverse_association_suffix, default: "" |
#soft_delete_column ⇒ Symbol?
The column name used for soft-delete timestamps (default: nil) Set to a column name to enable soft-delete support (e.g., :deleted_at, :discarded_at) Set to nil to disable soft-delete support entirely
62 |
# File 'lib/whodunit.rb', line 62 mattr_accessor :soft_delete_column, default: nil |
#updater_column ⇒ Symbol
The column name for tracking who updated the record (default: :updater_id)
52 |
# File 'lib/whodunit.rb', line 52 mattr_accessor :updater_column, default: :updater_id |
#updater_column_type ⇒ Symbol?
Specific data type for updater column (overrides column_data_type if set)
80 |
# File 'lib/whodunit.rb', line 80 mattr_accessor :updater_column_type, default: nil |
#user_class ⇒ String
The class name of the user model (default: “User”)
44 |
# File 'lib/whodunit.rb', line 44 mattr_accessor :user_class, default: "User" |