action-audit 1.0.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.
data/docs/migration.md ADDED
@@ -0,0 +1,571 @@
1
+ # Migration Guide
2
+
3
+ Guide for migrating from other audit solutions to ActionAudit.
4
+
5
+ ## Migration Overview
6
+
7
+ ActionAudit provides a lightweight, configuration-based approach to auditing that differs from database-backed audit solutions. This guide helps you migrate from various audit gems and custom solutions.
8
+
9
+ ## From Manual Logging Solutions
10
+
11
+ ### Before: Manual Rails.logger Calls
12
+
13
+ ```ruby
14
+ # Old approach: Manual logging in each action
15
+ class UsersController < ApplicationController
16
+ def create
17
+ @user = User.create!(user_params)
18
+ Rails.logger.info "User created: #{@user.email} by #{current_user&.email}"
19
+ redirect_to @user
20
+ end
21
+
22
+ def update
23
+ @user = User.find(params[:id])
24
+ old_email = @user.email
25
+ @user.update!(user_params)
26
+ Rails.logger.info "User #{@user.id} updated: #{old_email} -> #{@user.email}"
27
+ redirect_to @user
28
+ end
29
+
30
+ def destroy
31
+ @user = User.find(params[:id])
32
+ user_email = @user.email
33
+ @user.destroy!
34
+ Rails.logger.info "User deleted: #{user_email} by #{current_user&.email}"
35
+ redirect_to users_path
36
+ end
37
+ end
38
+ ```
39
+
40
+ ### After: ActionAudit Configuration
41
+
42
+ ```ruby
43
+ # New approach: Include ActionAudit
44
+ class UsersController < ApplicationController
45
+ include ActionAudit
46
+
47
+ def create
48
+ @user = User.create!(user_params)
49
+ # Automatic logging via audit.yml
50
+ redirect_to @user
51
+ end
52
+
53
+ def update
54
+ @user = User.find(params[:id])
55
+ @user.update!(user_params)
56
+ # Automatic logging via audit.yml
57
+ redirect_to @user
58
+ end
59
+
60
+ def destroy
61
+ @user = User.find(params[:id])
62
+ @user.destroy!
63
+ # Automatic logging via audit.yml
64
+ redirect_to users_path
65
+ end
66
+ end
67
+ ```
68
+
69
+ ```yaml
70
+ # config/audit.yml
71
+ users:
72
+ create: "User created: %{email}"
73
+ update: "User %{id} updated"
74
+ destroy: "User deleted: %{id}"
75
+ ```
76
+
77
+ ```ruby
78
+ # config/initializers/action_audit.rb
79
+ ActionAudit.log_formatter = lambda do |controller, action, message|
80
+ user_info = defined?(current_user) && current_user ? " by #{current_user.email}" : ""
81
+ "#{message}#{user_info}"
82
+ end
83
+ ```
84
+
85
+ **Migration Benefits:**
86
+ - **Centralized Configuration:** All audit messages in one place
87
+ - **Consistency:** Uniform message format across controllers
88
+ - **Maintainability:** Easy to update messages without touching controller code
89
+ - **DRY Principle:** No repeated logging code
90
+
91
+ ## From Database Audit Gems
92
+
93
+ ### From Audited Gem
94
+
95
+ The `audited` gem stores audit records in the database. ActionAudit focuses on logging instead.
96
+
97
+ #### Before: Audited Configuration
98
+
99
+ ```ruby
100
+ # Gemfile
101
+ gem 'audited'
102
+
103
+ # Model
104
+ class User < ApplicationRecord
105
+ audited only: [:name, :email], on: [:create, :update, :destroy]
106
+ end
107
+
108
+ # Querying audit records
109
+ user.audits.where(action: 'create')
110
+ user.audits.last.audited_changes
111
+ ```
112
+
113
+ #### After: ActionAudit Configuration
114
+
115
+ ```ruby
116
+ # Gemfile
117
+ gem 'action_audit'
118
+
119
+ # Controller
120
+ class UsersController < ApplicationController
121
+ include ActionAudit
122
+
123
+ def create
124
+ @user = User.create!(user_params)
125
+ # ActionAudit logs the action
126
+ end
127
+ end
128
+ ```
129
+
130
+ ```yaml
131
+ # config/audit.yml
132
+ users:
133
+ create: "Created user %{email} with %{name}"
134
+ update: "Updated user %{id}: %{name}"
135
+ destroy: "Deleted user %{id}"
136
+ ```
137
+
138
+ **Key Differences:**
139
+ - **Storage:** ActionAudit uses Rails logs, not database
140
+ - **Performance:** No database writes for audit records
141
+ - **Querying:** Use log analysis tools instead of ActiveRecord queries
142
+ - **Retention:** Managed by log rotation, not database cleanup
143
+
144
+ ### From PaperTrail Gem
145
+
146
+ PaperTrail tracks changes to models with database storage.
147
+
148
+ #### Migration Strategy
149
+
150
+ 1. **Keep PaperTrail for data versioning**
151
+ 2. **Add ActionAudit for user action logging**
152
+ 3. **Use both gems for different purposes**
153
+
154
+ ```ruby
155
+ # Model: Keep PaperTrail for data history
156
+ class User < ApplicationRecord
157
+ has_paper_trail only: [:name, :email, :role]
158
+ end
159
+
160
+ # Controller: Add ActionAudit for action logging
161
+ class UsersController < ApplicationController
162
+ include ActionAudit
163
+
164
+ def update
165
+ @user = User.find(params[:id])
166
+ @user.update!(user_params)
167
+ # PaperTrail records the data change
168
+ # ActionAudit logs the user action
169
+ end
170
+ end
171
+ ```
172
+
173
+ **Use Cases:**
174
+ - **PaperTrail:** Data versioning, rollbacks, change history
175
+ - **ActionAudit:** User actions, security logging, compliance
176
+
177
+ ## From Custom Audit Solutions
178
+
179
+ ### From Service Object Pattern
180
+
181
+ ```ruby
182
+ # Before: Custom audit service
183
+ class AuditService
184
+ def self.log_user_action(action, user, target = nil)
185
+ message = build_message(action, user, target)
186
+ Rails.logger.info("[AUDIT] #{message}")
187
+ AuditRecord.create!(
188
+ action: action,
189
+ user: user,
190
+ target: target,
191
+ message: message
192
+ )
193
+ end
194
+
195
+ private
196
+
197
+ def self.build_message(action, user, target)
198
+ case action
199
+ when :create_user
200
+ "User #{user.email} created user #{target.email}"
201
+ when :update_user
202
+ "User #{user.email} updated user #{target.id}"
203
+ # ... many more cases
204
+ end
205
+ end
206
+ end
207
+
208
+ # Usage in controllers
209
+ class UsersController < ApplicationController
210
+ def create
211
+ @user = User.create!(user_params)
212
+ AuditService.log_user_action(:create_user, current_user, @user)
213
+ redirect_to @user
214
+ end
215
+ end
216
+ ```
217
+
218
+ ```ruby
219
+ # After: ActionAudit
220
+ class UsersController < ApplicationController
221
+ include ActionAudit
222
+
223
+ def create
224
+ @user = User.create!(user_params)
225
+ params[:created_user_email] = @user.email
226
+ # ActionAudit handles the rest
227
+ redirect_to @user
228
+ end
229
+ end
230
+ ```
231
+
232
+ ```yaml
233
+ # config/audit.yml
234
+ users:
235
+ create: "User created: %{created_user_email}"
236
+ update: "User updated: %{id}"
237
+ destroy: "User deleted: %{id}"
238
+ ```
239
+
240
+ ```ruby
241
+ # config/initializers/action_audit.rb
242
+ ActionAudit.log_formatter = lambda do |controller, action, message|
243
+ user_email = defined?(current_user) && current_user ? current_user.email : "system"
244
+ "[AUDIT] User #{user_email}: #{message}"
245
+ end
246
+ ```
247
+
248
+ ## Migration Steps
249
+
250
+ ### Step 1: Install ActionAudit
251
+
252
+ ```ruby
253
+ # Gemfile
254
+ gem 'action_audit'
255
+ ```
256
+
257
+ ```bash
258
+ bundle install
259
+ rails generate action_audit:install
260
+ ```
261
+
262
+ ### Step 2: Identify Current Audit Points
263
+
264
+ Analyze your existing codebase to find:
265
+
266
+ ```bash
267
+ # Find manual logging calls
268
+ grep -r "Rails.logger.*audit\|audit.*log" app/
269
+
270
+ # Find service object calls
271
+ grep -r "AuditService\|Audit.*log" app/
272
+
273
+ # Find existing audit gem usage
274
+ grep -r "audited\|paper_trail" app/
275
+ ```
276
+
277
+ ### Step 3: Map to ActionAudit Configuration
278
+
279
+ Create a mapping of your current audit points:
280
+
281
+ ```yaml
282
+ # config/audit.yml
283
+ # Map your existing audit points to configuration
284
+
285
+ # From: Rails.logger.info "User #{user.email} created"
286
+ users:
287
+ create: "User created: %{email}"
288
+
289
+ # From: AuditService.log(:user_update, current_user, @user)
290
+ users:
291
+ update: "User updated: %{id}"
292
+
293
+ # From: audit_comment: "Deleted user account"
294
+ users:
295
+ destroy: "User deleted: %{id}"
296
+ ```
297
+
298
+ ### Step 4: Update Controllers Gradually
299
+
300
+ Migrate controllers one at a time:
301
+
302
+ ```ruby
303
+ # Phase 1: Add ActionAudit alongside existing logging
304
+ class UsersController < ApplicationController
305
+ include ActionAudit
306
+
307
+ def create
308
+ @user = User.create!(user_params)
309
+
310
+ # Keep existing logging temporarily
311
+ Rails.logger.info "User created: #{@user.email}"
312
+
313
+ # ActionAudit will also log
314
+ redirect_to @user
315
+ end
316
+ end
317
+ ```
318
+
319
+ ```ruby
320
+ # Phase 2: Remove old logging after verification
321
+ class UsersController < ApplicationController
322
+ include ActionAudit
323
+
324
+ def create
325
+ @user = User.create!(user_params)
326
+ # Only ActionAudit logging now
327
+ redirect_to @user
328
+ end
329
+ end
330
+ ```
331
+
332
+ ### Step 5: Configure Custom Formatting
333
+
334
+ Match your existing log format:
335
+
336
+ ```ruby
337
+ # config/initializers/action_audit.rb
338
+
339
+ # If you had: "[AUDIT] User john@example.com: Created user jane@example.com"
340
+ ActionAudit.log_formatter = lambda do |controller, action, message|
341
+ user_email = defined?(current_user) && current_user ? current_user.email : "system"
342
+ "[AUDIT] User #{user_email}: #{message}"
343
+ end
344
+
345
+ ActionAudit.log_tag = nil # No additional tagging if you had custom format
346
+ ```
347
+
348
+ ### Step 6: Update Log Processing
349
+
350
+ If you have log processing tools, update them for ActionAudit format:
351
+
352
+ ```bash
353
+ # Old log format
354
+ [AUDIT] User john@example.com created user jane@example.com
355
+
356
+ # New ActionAudit format
357
+ [AUDIT] User john@example.com: User created: jane@example.com
358
+ ```
359
+
360
+ Update your log parsing scripts accordingly.
361
+
362
+ ## Testing Migration
363
+
364
+ ### Parallel Logging During Migration
365
+
366
+ Run both systems in parallel to verify migration:
367
+
368
+ ```ruby
369
+ # Temporary parallel logging
370
+ class UsersController < ApplicationController
371
+ include ActionAudit
372
+
373
+ def create
374
+ @user = User.create!(user_params)
375
+
376
+ # Old system
377
+ AuditService.log_user_action(:create_user, current_user, @user)
378
+
379
+ # New system (ActionAudit automatic)
380
+
381
+ redirect_to @user
382
+ end
383
+ end
384
+ ```
385
+
386
+ ### Verification Script
387
+
388
+ ```ruby
389
+ # Create: verify_migration.rb
390
+ require_relative 'config/environment'
391
+
392
+ # Test ActionAudit configuration
393
+ puts "Testing ActionAudit Configuration"
394
+ puts "=" * 40
395
+
396
+ # Check all your migrated audit points
397
+ test_cases = [
398
+ ['users', 'create'],
399
+ ['users', 'update'],
400
+ ['users', 'destroy'],
401
+ ['admin/users', 'create'],
402
+ ['sessions', 'create']
403
+ ]
404
+
405
+ test_cases.each do |controller, action|
406
+ message = ActionAudit::AuditMessages.lookup(controller, action)
407
+ status = message ? "✓" : "✗ MISSING"
408
+ puts "#{status} #{controller}/#{action}: #{message}"
409
+ end
410
+
411
+ # Test parameter interpolation
412
+ puts "\nTesting Parameter Interpolation"
413
+ puts "=" * 40
414
+
415
+ sample_params = { id: 123, email: 'test@example.com', name: 'Test User' }
416
+ test_message = ActionAudit::AuditMessages.lookup('users', 'create')
417
+
418
+ if test_message
419
+ begin
420
+ result = test_message % sample_params.symbolize_keys
421
+ puts "✓ Interpolation: #{result}"
422
+ rescue KeyError => e
423
+ puts "✗ Interpolation failed: #{e.message}"
424
+ end
425
+ end
426
+ ```
427
+
428
+ ## Rollback Plan
429
+
430
+ Keep your migration reversible:
431
+
432
+ ### Rollback to Manual Logging
433
+
434
+ ```ruby
435
+ # Keep this code commented during migration
436
+ class UsersController < ApplicationController
437
+ # include ActionAudit # Comment out ActionAudit
438
+
439
+ def create
440
+ @user = User.create!(user_params)
441
+
442
+ # Uncomment manual logging if needed
443
+ Rails.logger.info "[AUDIT] User created: #{@user.email}"
444
+
445
+ redirect_to @user
446
+ end
447
+ end
448
+ ```
449
+
450
+ ### Feature Flags
451
+
452
+ Use feature flags to control migration:
453
+
454
+ ```ruby
455
+ # config/initializers/action_audit.rb
456
+ if Rails.application.config.use_action_audit
457
+ # ActionAudit configuration
458
+ ActionAudit.log_tag = "AUDIT"
459
+ else
460
+ # Disable ActionAudit
461
+ module ActionAudit
462
+ def audit_request
463
+ # No-op when disabled
464
+ end
465
+ end
466
+ end
467
+ ```
468
+
469
+ ## Post-Migration Cleanup
470
+
471
+ ### Remove Old Dependencies
472
+
473
+ ```ruby
474
+ # Remove from Gemfile after successful migration
475
+ # gem 'audited'
476
+ # gem 'paper_trail' # Only if not needed for versioning
477
+ ```
478
+
479
+ ### Clean Up Old Code
480
+
481
+ ```bash
482
+ # Find and remove old audit service calls
483
+ grep -r "AuditService\|OldAuditGem" app/ --exclude-dir=tmp
484
+ ```
485
+
486
+ ### Update Documentation
487
+
488
+ Update your application documentation to reflect the new audit approach:
489
+
490
+ - How to add new audit messages
491
+ - Log format and location
492
+ - How to query audit logs
493
+ - Maintenance procedures
494
+
495
+ ## Common Migration Issues
496
+
497
+ ### Different Parameter Names
498
+
499
+ **Problem:** Old system used different parameter names.
500
+
501
+ ```ruby
502
+ # Old system expected
503
+ AuditService.log(:user_created, user_id: @user.id, user_email: @user.email)
504
+
505
+ # ActionAudit expects params[:user_email]
506
+ ```
507
+
508
+ **Solution:** Map parameters in controller:
509
+
510
+ ```ruby
511
+ def create
512
+ @user = User.create!(user_params)
513
+ params[:user_email] = @user.email # Map for ActionAudit
514
+ redirect_to @user
515
+ end
516
+ ```
517
+
518
+ ### Complex Audit Logic
519
+
520
+ **Problem:** Old system had complex conditional audit logic.
521
+
522
+ **Solution:** Use custom formatter or controller-level logic:
523
+
524
+ ```ruby
525
+ # config/initializers/action_audit.rb
526
+ ActionAudit.log_formatter = lambda do |controller, action, message|
527
+ # Add complex logic here if needed
528
+ if controller == 'admin/users' && sensitive_action?(action)
529
+ alert_security_team(message)
530
+ end
531
+
532
+ message
533
+ end
534
+ ```
535
+
536
+ ### Database Audit Records
537
+
538
+ **Problem:** Need to maintain database audit records.
539
+
540
+ **Solution:** Create custom after_action alongside ActionAudit:
541
+
542
+ ```ruby
543
+ class ApplicationController < ActionController::Base
544
+ include ActionAudit
545
+
546
+ after_action :create_audit_record, if: :should_audit_to_database?
547
+
548
+ private
549
+
550
+ def create_audit_record
551
+ # Create database record if needed
552
+ AuditRecord.create!(
553
+ controller: self.class.name,
554
+ action: action_name,
555
+ user: current_user,
556
+ timestamp: Time.current
557
+ )
558
+ end
559
+
560
+ def should_audit_to_database?
561
+ # Define when to create database records
562
+ %w[create update destroy].include?(action_name)
563
+ end
564
+ end
565
+ ```
566
+
567
+ ## Next Steps
568
+
569
+ - [See real-world examples](examples.md)
570
+ - [Check troubleshooting guide](troubleshooting.md)
571
+ - [Return to main documentation](README.md)