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.
@@ -0,0 +1,413 @@
1
+ # Multi-Engine Setup Guide
2
+
3
+ ActionAudit is designed to work seamlessly across multiple Rails engines, automatically discovering and loading audit configurations from each engine.
4
+
5
+ ## How Multi-Engine Support Works
6
+
7
+ ActionAudit uses a Rails engine (`ActionAudit::Engine`) that automatically:
8
+
9
+ 1. **Discovers all mounted engines** in your Rails application
10
+ 2. **Looks for `config/audit.yml`** files in each engine's root directory
11
+ 3. **Merges all configurations** into a single audit message registry
12
+ 4. **Handles configuration reloading** in development mode
13
+
14
+ ## Setting Up Multi-Engine Auditing
15
+
16
+ ### Main Application Setup
17
+
18
+ 1. **Add ActionAudit to your main app's Gemfile:**
19
+
20
+ ```ruby
21
+ # Gemfile
22
+ gem 'action_audit'
23
+ ```
24
+
25
+ 2. **Create your main app's audit configuration:**
26
+
27
+ ```yaml
28
+ # config/audit.yml (main app)
29
+ sessions:
30
+ create: "User logged in with %{email}"
31
+ destroy: "User logged out"
32
+
33
+ profiles:
34
+ update: "User updated their profile"
35
+ ```
36
+
37
+ 3. **Configure logging in your main app:**
38
+
39
+ ```ruby
40
+ # config/initializers/action_audit.rb (main app)
41
+ ActionAudit.log_tag = "AUDIT"
42
+ ActionAudit.log_formatter = ->(controller, action, msg) do
43
+ "[#{Time.current.iso8601}] #{controller}/#{action} | #{msg}"
44
+ end
45
+ ```
46
+
47
+ ### Engine Setup
48
+
49
+ Each engine can have its own audit configuration:
50
+
51
+ #### Engine 1: Admin Engine
52
+
53
+ ```ruby
54
+ # engines/admin_engine/lib/admin_engine.rb
55
+ module AdminEngine
56
+ class Engine < ::Rails::Engine
57
+ isolate_namespace AdminEngine
58
+ end
59
+ end
60
+ ```
61
+
62
+ ```yaml
63
+ # engines/admin_engine/config/audit.yml
64
+ admin:
65
+ users:
66
+ create: "Admin created user %{email}"
67
+ update: "Admin updated user %{id}"
68
+ destroy: "Admin deleted user %{id}"
69
+
70
+ settings:
71
+ update: "Admin updated %{setting_name} setting"
72
+ ```
73
+
74
+ ```ruby
75
+ # engines/admin_engine/app/controllers/admin/users_controller.rb
76
+ class Admin::UsersController < ApplicationController
77
+ include ActionAudit
78
+
79
+ def create
80
+ # Will log: "Admin created user john@example.com"
81
+ end
82
+ end
83
+ ```
84
+
85
+ #### Engine 2: API Engine
86
+
87
+ ```ruby
88
+ # engines/api_engine/lib/api_engine.rb
89
+ module ApiEngine
90
+ class Engine < ::Rails::Engine
91
+ isolate_namespace ApiEngine
92
+ end
93
+ end
94
+ ```
95
+
96
+ ```yaml
97
+ # engines/api_engine/config/audit.yml
98
+ api:
99
+ v1:
100
+ webhooks:
101
+ create: "Webhook received from %{source}"
102
+
103
+ users:
104
+ create: "API user created with %{email}"
105
+ update: "API user %{id} updated"
106
+ ```
107
+
108
+ ```ruby
109
+ # engines/api_engine/app/controllers/api/v1/users_controller.rb
110
+ class API::V1::UsersController < ApplicationController
111
+ include ActionAudit
112
+
113
+ def create
114
+ # Will log: "API user created with jane@example.com"
115
+ end
116
+ end
117
+ ```
118
+
119
+ ## Configuration Merging
120
+
121
+ ActionAudit automatically merges configurations from all engines. The final merged configuration would look like:
122
+
123
+ ```yaml
124
+ # Merged configuration (conceptual view)
125
+ sessions: # from main app
126
+ create: "User logged in with %{email}"
127
+ destroy: "User logged out"
128
+
129
+ profiles: # from main app
130
+ update: "User updated their profile"
131
+
132
+ admin: # from admin_engine
133
+ users:
134
+ create: "Admin created user %{email}"
135
+ update: "Admin updated user %{id}"
136
+ destroy: "Admin deleted user %{id}"
137
+ settings:
138
+ update: "Admin updated %{setting_name} setting"
139
+
140
+ api: # from api_engine
141
+ v1:
142
+ webhooks:
143
+ create: "Webhook received from %{source}"
144
+ users:
145
+ create: "API user created with %{email}"
146
+ update: "API user %{id} updated"
147
+ ```
148
+
149
+ ## Engine Directory Structure
150
+
151
+ Here's a typical directory structure for a multi-engine Rails application:
152
+
153
+ ```
154
+ my_rails_app/
155
+ ├── config/
156
+ │ ├── audit.yml # Main app audit config
157
+ │ └── initializers/
158
+ │ └── action_audit.rb # Global audit configuration
159
+ ├── engines/
160
+ │ ├── admin_engine/
161
+ │ │ ├── config/
162
+ │ │ │ └── audit.yml # Admin engine audit config
163
+ │ │ └── app/controllers/
164
+ │ │ └── admin/
165
+ │ │ └── users_controller.rb
166
+ │ └── api_engine/
167
+ │ ├── config/
168
+ │ │ └── audit.yml # API engine audit config
169
+ │ └── app/controllers/
170
+ │ └── api/
171
+ │ └── v1/
172
+ │ └── users_controller.rb
173
+ └── Gemfile
174
+ ```
175
+
176
+ ## Development Mode Behavior
177
+
178
+ In development mode, ActionAudit automatically reloads all audit configurations when files change. This means:
179
+
180
+ 1. **File watching**: Changes to any `config/audit.yml` file are detected
181
+ 2. **Automatic reload**: Configurations are reloaded without restarting the server
182
+ 3. **Merged updates**: New configurations are merged with existing ones
183
+
184
+ ## Production Deployment
185
+
186
+ ### Configuration Loading Order
187
+
188
+ ActionAudit loads configurations in this order:
189
+
190
+ 1. **Main application** `config/audit.yml`
191
+ 2. **Each engine** `config/audit.yml` (in the order Rails discovers them)
192
+
193
+ ### Conflict Resolution
194
+
195
+ If multiple engines define the same audit path, the **last loaded configuration wins**. For example:
196
+
197
+ ```yaml
198
+ # Engine A: config/audit.yml
199
+ users:
200
+ create: "Engine A created user %{email}"
201
+
202
+ # Engine B: config/audit.yml
203
+ users:
204
+ create: "Engine B created user %{email}" # This will be used
205
+ ```
206
+
207
+ To avoid conflicts, use namespaced controller paths:
208
+
209
+ ```yaml
210
+ # Engine A: config/audit.yml
211
+ engine_a:
212
+ users:
213
+ create: "Engine A created user %{email}"
214
+
215
+ # Engine B: config/audit.yml
216
+ engine_b:
217
+ users:
218
+ create: "Engine B created user %{email}"
219
+ ```
220
+
221
+ ## Testing Multi-Engine Setup
222
+
223
+ ### Verifying Configuration Loading
224
+
225
+ You can verify that configurations from all engines are loaded:
226
+
227
+ ```ruby
228
+ # In Rails console
229
+ ActionAudit::AuditMessages.messages
230
+ # Should show merged configuration from all engines
231
+
232
+ # Check specific messages
233
+ ActionAudit::AuditMessages.lookup("admin/users", "create")
234
+ ActionAudit::AuditMessages.lookup("api/v1/users", "create")
235
+ ```
236
+
237
+ ### Testing Individual Engines
238
+
239
+ Test each engine's audit configuration separately:
240
+
241
+ ```ruby
242
+ # spec/engines/admin_engine_spec.rb
243
+ RSpec.describe "AdminEngine audit configuration" do
244
+ it "loads admin user audit messages" do
245
+ message = ActionAudit::AuditMessages.lookup("admin/users", "create")
246
+ expect(message).to eq("Admin created user %{email}")
247
+ end
248
+ end
249
+ ```
250
+
251
+ ## Best Practices
252
+
253
+ ### 1. Use Namespaced Paths
254
+
255
+ Always namespace your audit configurations to avoid conflicts:
256
+
257
+ ```yaml
258
+ # Good: Namespaced
259
+ admin_engine:
260
+ users:
261
+ create: "Admin created user %{email}"
262
+
263
+ # Bad: Generic (could conflict)
264
+ users:
265
+ create: "Created user %{email}"
266
+ ```
267
+
268
+ ### 2. Consistent Parameter Naming
269
+
270
+ Use consistent parameter names across engines:
271
+
272
+ ```yaml
273
+ # Good: Consistent naming
274
+ admin:
275
+ users:
276
+ create: "Admin created user %{email}"
277
+
278
+ api:
279
+ users:
280
+ create: "API created user %{email}"
281
+
282
+ # Both use %{email} consistently
283
+ ```
284
+
285
+ ### 3. Engine-Specific Initializers
286
+
287
+ Each engine can have its own ActionAudit configuration:
288
+
289
+ ```ruby
290
+ # engines/admin_engine/config/initializers/action_audit.rb
291
+ if defined?(ActionAudit)
292
+ # Engine-specific configuration
293
+ # This runs after the main app's initializer
294
+ end
295
+ ```
296
+
297
+ ### 4. Shared Configuration
298
+
299
+ For shared audit messages, create a separate configuration file:
300
+
301
+ ```yaml
302
+ # config/shared_audit.yml
303
+ shared:
304
+ sessions:
305
+ create: "User logged in with %{email}"
306
+ destroy: "User logged out"
307
+ ```
308
+
309
+ Then load it in your main app's initializer:
310
+
311
+ ```ruby
312
+ # config/initializers/action_audit.rb
313
+ shared_config = Rails.root.join("config", "shared_audit.yml")
314
+ ActionAudit::AuditMessages.load_from_file(shared_config) if File.exist?(shared_config)
315
+ ```
316
+
317
+ ## Troubleshooting Multi-Engine Issues
318
+
319
+ ### Configuration Not Loading
320
+
321
+ 1. **Check file paths**: Ensure `config/audit.yml` exists in each engine's root
322
+ 2. **Verify engine mounting**: Make sure all engines are properly mounted in your main app
323
+ 3. **Check YAML syntax**: Invalid YAML will prevent loading
324
+
325
+ ### Conflicting Messages
326
+
327
+ 1. **Use namespaces**: Avoid generic controller paths
328
+ 2. **Check loading order**: Later engines override earlier ones
329
+ 3. **Use unique paths**: Make controller paths engine-specific
330
+
331
+ ### Development Reloading Issues
332
+
333
+ 1. **Restart server**: Sometimes manual restart is needed
334
+ 2. **Check file permissions**: Ensure Rails can read all audit.yml files
335
+ 3. **Verify file changes**: Make sure files are actually being modified
336
+
337
+ ## Example: Complete Multi-Engine Setup
338
+
339
+ Here's a complete example of a multi-engine Rails application with ActionAudit:
340
+
341
+ ### Main Application
342
+
343
+ ```ruby
344
+ # config/application.rb
345
+ require_relative "boot"
346
+ require "rails/all"
347
+
348
+ Bundler.require(*Rails.groups)
349
+
350
+ module MyRailsApp
351
+ class Application < Rails::Application
352
+ config.load_defaults 7.0
353
+ end
354
+ end
355
+ ```
356
+
357
+ ```yaml
358
+ # config/audit.yml
359
+ app:
360
+ sessions:
361
+ create: "User logged in with %{email}"
362
+ destroy: "User logged out"
363
+ ```
364
+
365
+ ### Admin Engine
366
+
367
+ ```ruby
368
+ # engines/admin/lib/admin.rb
369
+ module Admin
370
+ class Engine < ::Rails::Engine
371
+ isolate_namespace Admin
372
+ end
373
+ end
374
+ ```
375
+
376
+ ```yaml
377
+ # engines/admin/config/audit.yml
378
+ admin:
379
+ users:
380
+ create: "Admin created user %{email}"
381
+ update: "Admin updated user %{id}"
382
+ dashboard:
383
+ show: "Admin accessed dashboard"
384
+ ```
385
+
386
+ ### API Engine
387
+
388
+ ```ruby
389
+ # engines/api/lib/api.rb
390
+ module Api
391
+ class Engine < ::Rails::Engine
392
+ isolate_namespace Api
393
+ end
394
+ end
395
+ ```
396
+
397
+ ```yaml
398
+ # engines/api/config/audit.yml
399
+ api:
400
+ v1:
401
+ users:
402
+ create: "API user created %{email}"
403
+ webhooks:
404
+ create: "Webhook %{event} from %{source}"
405
+ ```
406
+
407
+ This setup provides complete audit coverage across all engines while maintaining clear separation of concerns.
408
+
409
+ ## Next Steps
410
+
411
+ - [Learn about API reference](api-reference.md)
412
+ - [See real-world examples](examples.md)
413
+ - [Check troubleshooting guide](troubleshooting.md)