better_model 1.0.0 โ†’ 1.2.0

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 6ba3b1688c75e16f9499780eebd533c307cd8ba18f9c37a03597c8d62310fae7
4
- data.tar.gz: '0835904e4ea513187668f8f9c36e3d9855096bc46a2150555fae900b320b764d'
3
+ metadata.gz: ec236d26e4c1e0a5a62e9932606a1baa28de1bcadf8b447f1da545fb35d029b6
4
+ data.tar.gz: 24e4aa004924ab09c6104cad770229041b8c8d24556ce5f2f2d190bf15071e90
5
5
  SHA512:
6
- metadata.gz: d42074244a7e4af9321b68e9657f343ac4c087956856cfd0cbfe68e72adc1fce5200fc051cdfe1badd0e6bc753dfa3abcf0603113e3dede3cd7ce083b3ba932c
7
- data.tar.gz: e5305841ab87d40047b6bc458bdac8a163a96d0d9e864ead0a0335ab84b53759a5da837cb6b95f1c2bdc3596fcd74dc7281d77d370a3db0aa9cc98f72c281708
6
+ metadata.gz: 77d291e54bcbbb179eabd842290530d0f42e03636981e93bfdeb6575d5d0e02960d359072c0b0db0144f35cdbea647d463bf7320037c557552f6fce8365a393e
7
+ data.tar.gz: bfe3bf61206cb343dce4d84b2ff643e719c09b93a623de77e127a00aadbce646d25bfcc2cd66ca3bd725b6af224a82eb7cff2e059f79f45c8e026d5d878c95d6
data/README.md CHANGED
@@ -1,8 +1,8 @@
1
- # BetterModel
1
+ # BetterModel ๐Ÿš€
2
2
 
3
- BetterModel is a Rails engine gem (Rails 8.1+) that provides powerful extensions for ActiveRecord models, including declarative status management, permissions, archiving, sorting, filtering, and unified search capabilities.
3
+ BetterModel is a Rails engine gem (Rails 8.1+) that provides powerful extensions for ActiveRecord models, including declarative status management, permissions, state machines, validations, archiving, change tracking, sorting, filtering, and unified search capabilities.
4
4
 
5
- ## Installation
5
+ ## ๐Ÿ“ฆ Installation
6
6
 
7
7
  Add this line to your application's Gemfile:
8
8
 
@@ -20,7 +20,7 @@ Or install it yourself as:
20
20
  $ gem install better_model
21
21
  ```
22
22
 
23
- ## Quick Start
23
+ ## โšก Quick Start
24
24
 
25
25
  Simply include `BetterModel` in your model to get all features:
26
26
 
@@ -52,7 +52,52 @@ class Article < ApplicationRecord
52
52
  skip_archived_by_default true # Hide archived records by default
53
53
  end
54
54
 
55
- # 6. SEARCHABLE - Configure unified search interface
55
+ # 6. VALIDATABLE - Declarative validation system (opt-in)
56
+ validatable do
57
+ # Basic validations
58
+ validate :title, :content, presence: true
59
+
60
+ # Conditional validations
61
+ validate_if :is_published? do
62
+ validate :published_at, presence: true
63
+ end
64
+
65
+ # Cross-field validations
66
+ validate_order :starts_at, :before, :ends_at
67
+
68
+ # Business rules
69
+ validate_business_rule :valid_category
70
+
71
+ # Validation groups (multi-step forms)
72
+ validation_group :step1, [:title, :content]
73
+ validation_group :step2, [:published_at]
74
+ end
75
+
76
+ # 7. STATEABLE - Declarative state machine (opt-in)
77
+ stateable do
78
+ # Define states
79
+ state :draft, initial: true
80
+ state :published
81
+ state :archived
82
+
83
+ # Define transitions with guards and callbacks
84
+ transition :publish, from: :draft, to: :published do
85
+ guard { valid? }
86
+ guard if: :is_ready_for_publishing? # Statusable integration
87
+ before { set_published_at }
88
+ after { notify_subscribers }
89
+ end
90
+
91
+ transition :archive, from: [:draft, :published], to: :archived
92
+ end
93
+
94
+ # 8. TRACEABLE - Audit trail with time-travel (opt-in)
95
+ traceable do
96
+ track :title, :content, :status, :published_at
97
+ versions_table :article_versions # Optional: custom table
98
+ end
99
+
100
+ # 9. SEARCHABLE - Configure unified search interface
56
101
  searchable do
57
102
  per_page 25
58
103
  max_per_page 100
@@ -62,41 +107,66 @@ class Article < ApplicationRecord
62
107
  end
63
108
  ```
64
109
 
65
- Now you can use all the features:
110
+ ๐Ÿ’ก **Now you can use all the features:**
66
111
 
67
112
  ```ruby
68
- # Check statuses
113
+ # โœ… Check statuses
69
114
  article.is?(:draft) # => true/false
70
115
  article.is_published? # => true/false
71
116
  article.statuses # => { draft: true, published: false, ... }
72
117
 
73
- # Check permissions
118
+ # ๐Ÿ” Check permissions
74
119
  article.permit?(:edit) # => true/false
75
120
  article.permit_delete? # => true/false
76
121
  article.permissions # => { edit: true, delete: true, ... }
77
122
 
78
- # Sort
123
+ # โฌ†๏ธ Sort
79
124
  Article.sort_title_asc
80
125
  Article.sort_view_count_desc
81
126
  Article.sort_published_at_desc
82
127
 
83
- # Filter with predicates
128
+ # ๐Ÿ” Filter with predicates
84
129
  Article.status_eq("published")
85
130
  Article.title_cont("Rails")
86
131
  Article.view_count_gteq(100)
87
132
  Article.published_at_present
88
133
 
89
- # Archive records
134
+ # ๐Ÿ—„๏ธ Archive records
90
135
  article.archive!(by: current_user, reason: "Outdated")
91
136
  article.archived? # => true
92
137
  article.restore!
93
138
 
94
- # Query archived records
139
+ # ๐Ÿ“‚ Query archived records
95
140
  Article.archived
96
141
  Article.not_archived
97
142
  Article.archived_recently(7.days)
98
143
 
99
- # Unified search with filters, sorting, and pagination
144
+ # โœ… Validate with groups (multi-step forms)
145
+ article.valid?(:step1) # Validate only step1 fields
146
+ article.valid?(:step2) # Validate only step2 fields
147
+ article.errors_for_group(:step1) # Get errors for step1 only
148
+
149
+ # ๐Ÿ”„ State machine transitions
150
+ article.state # => "draft"
151
+ article.draft? # => true
152
+ article.can_publish? # => true (checks guards)
153
+ article.publish! # Executes transition with guards & callbacks
154
+ article.published? # => true
155
+ article.state_transitions # History of all transitions
156
+ article.transition_history # Formatted history array
157
+
158
+ # โฐ Time travel & rollback (Traceable)
159
+ article.audit_trail # Full change history
160
+ article.as_of(3.days.ago) # Reconstruct past state
161
+ article.rollback_to(version) # Restore to previous version
162
+ article.changes_for(:status) # Changes for specific field
163
+
164
+ # ๐Ÿ” Query changes
165
+ Article.changed_by(user.id)
166
+ Article.changed_between(1.week.ago, Time.current)
167
+ Article.status_changed_from("draft").to("published")
168
+
169
+ # ๐Ÿ”Ž Unified search with filters, sorting, and pagination
100
170
  Article.search(
101
171
  { status_eq: "published", view_count_gteq: 50 },
102
172
  orders: [:sort_published_at_desc],
@@ -104,7 +174,7 @@ Article.search(
104
174
  )
105
175
  ```
106
176
 
107
- ### Including Individual Concerns (Advanced)
177
+ ### ๐ŸŽฏ Including Individual Concerns (Advanced)
108
178
 
109
179
  If you only need specific features, you can include individual concerns:
110
180
 
@@ -113,21 +183,42 @@ class Article < ApplicationRecord
113
183
  include BetterModel::Statusable # Only status management
114
184
  include BetterModel::Permissible # Only permissions
115
185
  include BetterModel::Archivable # Only archiving
186
+ include BetterModel::Traceable # Only audit trail & time-travel
116
187
  include BetterModel::Sortable # Only sorting
117
188
  include BetterModel::Predicable # Only filtering
189
+ include BetterModel::Validatable # Only validations
190
+ include BetterModel::Stateable # Only state machine
118
191
  include BetterModel::Searchable # Only search (requires Predicable & Sortable)
119
192
 
120
193
  # Define your features...
121
194
  end
122
195
  ```
123
196
 
124
- ## Requirements
197
+ ## ๐Ÿ“‹ Features Overview
198
+
199
+ BetterModel provides nine powerful concerns that work seamlessly together:
200
+
201
+ ### Core Features
202
+
203
+ - **โœจ Statusable** - Declarative status management with lambda-based conditions
204
+ - **๐Ÿ” Permissible** - State-based permission system
205
+ - **๐Ÿ—„๏ธ Archivable** - Soft delete with tracking (by user, reason)
206
+ - **โฐ Traceable** ๐Ÿ†• - Complete audit trail with time-travel and rollback
207
+ - **โฌ†๏ธ Sortable** - Type-aware sorting scopes
208
+ - **๐Ÿ” Predicable** - Advanced filtering with rich predicate system
209
+ - **๐Ÿ”Ž Searchable** - Unified search interface (Predicable + Sortable)
210
+ - **โœ… Validatable** - Declarative validation DSL with conditional rules
211
+ - **๐Ÿ”„ Stateable** ๐Ÿ†• - Declarative state machines with guards & callbacks
212
+
213
+ [See all features in detail โ†’](#-features)
214
+
215
+ ## โš™๏ธ Requirements
125
216
 
126
217
  - **Ruby:** 3.0 or higher
127
218
  - **Rails:** 8.1 or higher
128
219
  - **ActiveRecord:** Included with Rails
129
220
 
130
- ## Database Compatibility
221
+ ## ๐Ÿ’พ Database Compatibility
131
222
 
132
223
  BetterModel works with all databases supported by ActiveRecord:
133
224
 
@@ -143,20 +234,20 @@ BetterModel works with all databases supported by ActiveRecord:
143
234
  - Array predicates: `overlaps`, `contains`, `contained_by`
144
235
  - JSONB predicates: `has_key`, `has_any_key`, `has_all_keys`, `jsonb_contains`
145
236
 
146
- ## Features
237
+ ## ๐Ÿ“š Features
147
238
 
148
- BetterModel provides six powerful concerns that work together seamlessly:
239
+ BetterModel provides eight powerful concerns that work together seamlessly:
149
240
 
150
241
  ### ๐Ÿ“‹ Statusable - Declarative Status Management
151
242
 
152
243
  Define derived statuses dynamically based on model attributes - no database columns needed!
153
244
 
154
- **Key Benefits:**
155
- - Declarative DSL with clear, readable conditions
156
- - Statuses calculated in real-time from model attributes
157
- - Reference other statuses in conditions
158
- - Automatic method generation (`is_draft?`, `is_published?`)
159
- - Thread-safe with immutable registry
245
+ **๐ŸŽฏ Key Benefits:**
246
+ - โœจ Declarative DSL with clear, readable conditions
247
+ - โšก Statuses calculated in real-time from model attributes
248
+ - ๐Ÿ”— Reference other statuses in conditions
249
+ - ๐Ÿค– Automatic method generation (`is_draft?`, `is_published?`)
250
+ - ๐Ÿ”’ Thread-safe with immutable registry
160
251
 
161
252
  **[๐Ÿ“– Full Documentation โ†’](docs/statusable.md)**
162
253
 
@@ -166,12 +257,12 @@ Define derived statuses dynamically based on model attributes - no database colu
166
257
 
167
258
  Define permissions dynamically based on model state and statuses - perfect for authorization logic!
168
259
 
169
- **Key Benefits:**
170
- - Declarative DSL following Statusable pattern
171
- - Permissions calculated from model state
172
- - Reference statuses in permission logic
173
- - Automatic method generation (`permit_edit?`, `permit_delete?`)
174
- - Thread-safe with immutable registry
260
+ **๐ŸŽฏ Key Benefits:**
261
+ - โœจ Declarative DSL following Statusable pattern
262
+ - โšก Permissions calculated from model state
263
+ - ๐Ÿ”— Reference statuses in permission logic
264
+ - ๐Ÿค– Automatic method generation (`permit_edit?`, `permit_delete?`)
265
+ - ๐Ÿ”’ Thread-safe with immutable registry
175
266
 
176
267
  **[๐Ÿ“– Full Documentation โ†’](docs/permissible.md)**
177
268
 
@@ -181,30 +272,87 @@ Define permissions dynamically based on model state and statuses - perfect for a
181
272
 
182
273
  Soft-delete records with archive tracking, audit trails, and restoration capabilities.
183
274
 
184
- **Key Benefits:**
185
- - Opt-in activation: only enabled when explicitly configured
186
- - Archive and restore methods with optional tracking
187
- - Status methods: `archived?` and `active?`
188
- - Semantic scopes: `archived`, `not_archived`, `archived_only`
189
- - Helper predicates: `archived_today`, `archived_this_week`, `archived_recently`
190
- - Optional default scope to hide archived records
191
- - Migration generator with flexible options
192
- - Thread-safe with immutable configuration
275
+ **๐ŸŽฏ Key Benefits:**
276
+ - ๐ŸŽ›๏ธ Opt-in activation: only enabled when explicitly configured
277
+ - ๐Ÿ”„ Archive and restore methods with optional tracking
278
+ - โœ… Status methods: `archived?` and `active?`
279
+ - ๐Ÿ” Semantic scopes: `archived`, `not_archived`, `archived_only`
280
+ - ๐Ÿ› ๏ธ Helper predicates: `archived_today`, `archived_this_week`, `archived_recently`
281
+ - ๐Ÿ‘ป Optional default scope to hide archived records
282
+ - ๐Ÿš€ Migration generator with flexible options
283
+ - ๐Ÿ”’ Thread-safe with immutable configuration
193
284
 
194
285
  **[๐Ÿ“– Full Documentation โ†’](docs/archivable.md)**
195
286
 
196
287
  ---
197
288
 
289
+ ### โœ… Validatable - Declarative Validation System
290
+
291
+ Define validations declaratively with support for conditional rules, cross-field validation, business rules, and validation groups.
292
+
293
+ **๐ŸŽฏ Key Benefits:**
294
+ - ๐ŸŽ›๏ธ Opt-in activation: only enabled when explicitly configured
295
+ - โœจ Declarative DSL for all validation types
296
+ - ๐Ÿ”€ Conditional validations: `validate_if` / `validate_unless`
297
+ - ๐Ÿ”— Cross-field validations: `validate_order` for date/number comparisons
298
+ - ๐Ÿ’ผ Business rules: delegate complex logic to custom methods
299
+ - ๐Ÿ“‹ Validation groups: partial validation for multi-step forms
300
+ - ๐Ÿ”’ Thread-safe with immutable configuration
301
+
302
+ **[๐Ÿ“– Full Documentation โ†’](docs/validatable.md)**
303
+
304
+ ---
305
+
306
+ ### ๐Ÿ”„ Stateable - Declarative State Machine
307
+
308
+ Define state machines declaratively with transitions, guards, validations, and callbacks for robust workflow management.
309
+
310
+ **๐ŸŽฏ Key Benefits:**
311
+ - ๐ŸŽ›๏ธ Opt-in activation: only enabled when explicitly configured
312
+ - โœจ Declarative DSL for states and transitions
313
+ - ๐Ÿ›ก๏ธ Guards: preconditions with lambda, methods, or Statusable predicates
314
+ - โœ… Validations: custom validation logic per transition
315
+ - ๐Ÿ”— Callbacks: before/after/around hooks for each transition
316
+ - ๐Ÿ“œ State history tracking with customizable table names
317
+ - ๐Ÿค– Dynamic methods: `pending?`, `confirm!`, `can_confirm?`
318
+ - ๐Ÿ”— Integration with Statusable for complex guard logic
319
+ - ๐Ÿ”’ Thread-safe with immutable configuration
320
+
321
+ **[๐Ÿ“– Full Documentation โ†’](docs/stateable.md)**
322
+
323
+ ---
324
+
325
+ ### โฐ Traceable - Audit Trail with Time-Travel
326
+
327
+ Track all changes to your records with complete audit trail, time-travel capabilities, and rollback support.
328
+
329
+ **๐ŸŽฏ Key Benefits:**
330
+ - ๐ŸŽ›๏ธ Opt-in activation: only enabled when explicitly configured
331
+ - ๐Ÿ“ Automatic change tracking on create, update, and destroy
332
+ - ๐Ÿ‘ค User attribution: track who made each change
333
+ - ๐Ÿ’ฌ Change reasons: optional context for changes
334
+ - โฐ Time-travel: reconstruct object state at any point in history
335
+ - โ†ฉ๏ธ Rollback support: restore records to previous versions
336
+ - ๐Ÿ” Rich query API: find changes by user, time, or field transitions
337
+ - ๐Ÿ“Š Flexible table naming: per-model, shared, or custom tables
338
+ - ๐Ÿ”— Polymorphic association for efficient storage
339
+ - ๐Ÿ’พ Database adapter safety: PostgreSQL, MySQL, SQLite support
340
+ - ๐Ÿ”’ Thread-safe dynamic class creation
341
+
342
+ **[๐Ÿ“– Full Documentation โ†’](docs/traceable.md)**
343
+
344
+ ---
345
+
198
346
  ### โฌ†๏ธ Sortable - Type-Aware Sorting Scopes
199
347
 
200
348
  Generate intelligent sorting scopes automatically with database-specific optimizations and NULL handling.
201
349
 
202
- **Key Benefits:**
203
- - Type-aware scope generation (string, numeric, datetime, boolean)
204
- - Case-insensitive sorting for strings
205
- - Database-specific NULLS FIRST/LAST support
206
- - Sort by multiple fields with chaining
207
- - Optimized queries with proper indexing support
350
+ **๐ŸŽฏ Key Benefits:**
351
+ - ๐ŸŽฏ Type-aware scope generation (string, numeric, datetime, boolean)
352
+ - ๐Ÿ”ค Case-insensitive sorting for strings
353
+ - ๐Ÿ’พ Database-specific NULLS FIRST/LAST support
354
+ - ๐Ÿ”— Sort by multiple fields with chaining
355
+ - โšก Optimized queries with proper indexing support
208
356
 
209
357
  **[๐Ÿ“– Full Documentation โ†’](docs/sortable.md)**
210
358
 
@@ -214,13 +362,13 @@ Generate intelligent sorting scopes automatically with database-specific optimiz
214
362
 
215
363
  Generate comprehensive predicate scopes for filtering and searching with support for all data types.
216
364
 
217
- **Key Benefits:**
218
- - Complete coverage: string, numeric, datetime, boolean, null predicates
219
- - Type-safe predicates based on column type
220
- - Case-insensitive string matching
221
- - Range queries (between) for numerics and dates
222
- - PostgreSQL array and JSONB support
223
- - Chainable with standard ActiveRecord queries
365
+ **๐ŸŽฏ Key Benefits:**
366
+ - โœ… Complete coverage: string, numeric, datetime, boolean, null predicates
367
+ - ๐Ÿ”’ Type-safe predicates based on column type
368
+ - ๐Ÿ”ค Case-insensitive string matching
369
+ - ๐Ÿ“Š Range queries (between) for numerics and dates
370
+ - ๐Ÿ˜ PostgreSQL array and JSONB support
371
+ - ๐Ÿ”— Chainable with standard ActiveRecord queries
224
372
 
225
373
  **[๐Ÿ“– Full Documentation โ†’](docs/predicable.md)**
226
374
 
@@ -230,57 +378,230 @@ Generate comprehensive predicate scopes for filtering and searching with support
230
378
 
231
379
  Orchestrate Predicable and Sortable into a powerful, secure search interface with pagination and security.
232
380
 
233
- **Key Benefits:**
234
- - Unified API: single `search()` method for all operations
235
- - OR conditions for complex logic
236
- - Built-in pagination with DoS protection (max_per_page)
237
- - Security enforcement with required predicates
238
- - Default ordering configuration
239
- - Strong parameters integration
240
- - Type-safe validation of all parameters
381
+ **๐ŸŽฏ Key Benefits:**
382
+ - ๐ŸŽฏ Unified API: single `search()` method for all operations
383
+ - ๐Ÿ”€ OR conditions for complex logic
384
+ - ๐Ÿ“„ Built-in pagination with DoS protection (max_per_page)
385
+ - ๐Ÿ”’ Security enforcement with required predicates
386
+ - โš™๏ธ Default ordering configuration
387
+ - ๐Ÿ’ช Strong parameters integration
388
+ - โœ… Type-safe validation of all parameters
241
389
 
242
390
  **[๐Ÿ“– Full Documentation โ†’](docs/searchable.md)**
243
391
 
244
392
  ---
245
393
 
246
- ## Version & Changelog
394
+ ### ๐Ÿ“œ Traceable - Audit Trail & Change Tracking
395
+
396
+ Track all changes to your records with comprehensive audit trail functionality, time-travel queries, and rollback capabilities.
397
+
398
+ **๐ŸŽฏ Key Benefits:**
399
+ - ๐ŸŽ›๏ธ Opt-in activation: only enabled when explicitly configured
400
+ - ๐Ÿค– Automatic change tracking on create/update/destroy
401
+ - โฐ Time-travel: reconstruct record state at any point in time
402
+ - โ†ฉ๏ธ Rollback: restore to previous versions
403
+ - ๐Ÿ“ Audit trail with who/why tracking
404
+ - ๐Ÿ” Query changes by user, date range, or field transitions
405
+ - ๐Ÿ—‚๏ธ Flexible table naming: per-model tables (default), shared table, or custom names
406
+
407
+ **[๐Ÿ“– Full Documentation โ†’](docs/traceable.md)**
408
+
409
+ #### ๐Ÿš€ Quick Setup
410
+
411
+ **1๏ธโƒฃ Step 1: Create the versions table**
412
+
413
+ By default, each model gets its own versions table (`{model}_versions`):
414
+
415
+ ```bash
416
+ # Creates migration for article_versions table
417
+ rails g better_model:traceable Article --create-table
418
+ rails db:migrate
419
+ ```
420
+
421
+ Or use a custom table name:
422
+
423
+ ```bash
424
+ # Creates migration for custom table name
425
+ rails g better_model:traceable Article --create-table --table-name=audit_log
426
+ rails db:migrate
427
+ ```
428
+
429
+ **2๏ธโƒฃ Step 2: Enable in your model**
430
+
431
+ ```ruby
432
+ class Article < ApplicationRecord
433
+ include BetterModel
434
+
435
+ # Activate traceable (opt-in)
436
+ traceable do
437
+ track :status, :title, :published_at # Fields to track
438
+ # versions_table 'audit_log' # Optional: custom table (default: article_versions)
439
+ end
440
+ end
441
+ ```
442
+
443
+ **๐Ÿ’ก Usage:**
444
+
445
+ ```ruby
446
+ # ๐Ÿค– Automatic tracking on changes
447
+ article.update!(status: "published", updated_by_id: user.id, updated_reason: "Approved")
448
+
449
+ # ๐Ÿ” Query version history
450
+ article.versions # All versions (ordered desc)
451
+ article.changes_for(:status) # Changes for specific field
452
+ article.audit_trail # Full formatted history
453
+
454
+ # โฐ Time-travel: reconstruct state at specific time
455
+ past_article = article.as_of(3.days.ago)
456
+ past_article.status # => "draft" (what it was 3 days ago)
457
+
458
+ # โ†ฉ๏ธ Rollback to previous version
459
+ version = article.versions.where(event: "updated").first
460
+ article.rollback_to(version, updated_by_id: user.id, updated_reason: "Mistake")
461
+
462
+ # ๐Ÿ“Š Class-level queries
463
+ Article.changed_by(user.id) # Records changed by user
464
+ Article.changed_between(1.week.ago, Time.current) # Changes in period
465
+ Article.status_changed_from("draft").to("published") # Specific transitions (PostgreSQL)
466
+
467
+ # ๐Ÿ“ฆ Integration with as_json
468
+ article.as_json(include_audit_trail: true) # Include full history in JSON
469
+ ```
470
+
471
+ **๐Ÿ’พ Database Schema:**
472
+
473
+ By default, each model gets its own versions table (e.g., `article_versions` for Article model).
474
+ You can also use a shared table across multiple models or a custom table name.
475
+
476
+ | Column | Type | Description |
477
+ |--------|------|-------------|
478
+ | `item_type` | string | Polymorphic model name |
479
+ | `item_id` | integer | Polymorphic record ID |
480
+ | `event` | string | Event type: created/updated/destroyed |
481
+ | `object_changes` | json | Before/after values for tracked fields |
482
+ | `updated_by_id` | integer | Optional: user who made the change |
483
+ | `updated_reason` | string | Optional: reason for the change |
484
+ | `created_at` | datetime | When the change occurred |
485
+
486
+ **๐Ÿ—‚๏ธ Table Naming Options:**
487
+
488
+ ```ruby
489
+ # 1๏ธโƒฃ Option 1: Per-model table (default)
490
+ class Article < ApplicationRecord
491
+ traceable do
492
+ track :status
493
+ # Uses article_versions table automatically
494
+ end
495
+ end
496
+
497
+ # 2๏ธโƒฃ Option 2: Custom table name
498
+ class Article < ApplicationRecord
499
+ traceable do
500
+ track :status
501
+ versions_table 'audit_log' # Uses audit_log table
502
+ end
503
+ end
504
+
505
+ # 3๏ธโƒฃ Option 3: Shared table across models
506
+ class Article < ApplicationRecord
507
+ traceable do
508
+ track :status
509
+ versions_table 'versions' # Shared table
510
+ end
511
+ end
512
+
513
+ class User < ApplicationRecord
514
+ traceable do
515
+ track :email
516
+ versions_table 'versions' # Same shared table
517
+ end
518
+ end
519
+ ```
520
+
521
+ **๐Ÿ“ Optional Tracking:**
522
+
523
+ To track who made changes and why, simply set attributes before saving:
524
+
525
+ ```ruby
526
+ article.updated_by_id = current_user.id
527
+ article.updated_reason = "Fixed typo"
528
+ article.update!(title: "Corrected Title")
529
+
530
+ # The version will automatically include updated_by_id and updated_reason
531
+ ```
532
+
533
+ ---
534
+
535
+ ## ๐Ÿ“Œ Version & Changelog
247
536
 
248
537
  **Current Version:** 1.0.0
249
538
 
250
539
  See [CHANGELOG.md](CHANGELOG.md) for version history and release notes.
251
540
 
252
- ## Support & Community
541
+ ## ๐Ÿ’ฌ Support & Community
542
+
543
+ - ๐Ÿ› **Issues & Bugs:** [GitHub Issues](https://github.com/alessiobussolari/better_model/issues)
544
+ - ๐Ÿ’ป **Source Code:** [GitHub Repository](https://github.com/alessiobussolari/better_model)
545
+ - ๐Ÿ“– **Documentation:** This README and detailed docs in `docs/` directory
546
+
547
+ ## ๐Ÿ“š Complete Documentation
548
+
549
+ ### ๐Ÿ“– Feature Guides
550
+
551
+ Detailed documentation for each BetterModel concern:
552
+
553
+ - [**Statusable**](docs/statusable.md) - Status management with derived conditions
554
+ - [**Permissible**](docs/permissible.md) - Permission system based on state
555
+ - [**Archivable**](docs/archivable.md) - Soft delete with comprehensive tracking
556
+ - [**Traceable**](docs/traceable.md) ๐Ÿ†• - Audit trail, time-travel, and rollback
557
+ - [**Sortable**](docs/sortable.md) - Type-aware sorting system
558
+ - [**Predicable**](docs/predicable.md) - Advanced filtering and predicates
559
+ - [**Searchable**](docs/searchable.md) - Unified search interface
560
+ - [**Validatable**](docs/validatable.md) - Declarative validation system
561
+ - [**Stateable**](docs/stateable.md) ๐Ÿ†• - State machine with transitions
253
562
 
254
- - **Issues & Bugs:** [GitHub Issues](https://github.com/alessiobussolari/better_model/issues)
255
- - **Source Code:** [GitHub Repository](https://github.com/alessiobussolari/better_model)
256
- - **Documentation:** This README and detailed docs in `docs/` directory
563
+ ### ๐ŸŽ“ Advanced Guides
257
564
 
258
- ## Contributing
565
+ Learn how to master BetterModel in production:
566
+
567
+ - [**Integration Guide**](docs/integration_guide.md) ๐Ÿ†• - Combining multiple concerns effectively
568
+ - [**Performance Guide**](docs/performance_guide.md) ๐Ÿ†• - Optimization strategies and indexing
569
+ - [**Migration Guide**](docs/migration_guide.md) ๐Ÿ†• - Adding BetterModel to existing apps
570
+
571
+ ### ๐Ÿ’ก Quick Links
572
+
573
+ - [Installation](#-installation)
574
+ - [Quick Start](#-quick-start)
575
+ - [Features Overview](#-features-overview)
576
+ - [Requirements](#%EF%B8%8F-requirements)
577
+ - [Contributing](#-contributing)
578
+
579
+ ## ๐Ÿค Contributing
259
580
 
260
581
  We welcome contributions! Here's how you can help:
261
582
 
262
- ### Reporting Bugs
583
+ ### ๐Ÿ› Reporting Bugs
263
584
 
264
- 1. Check if the issue already exists in [GitHub Issues](https://github.com/alessiobussolari/better_model/issues)
265
- 2. Create a new issue with:
585
+ 1. โœ… Check if the issue already exists in [GitHub Issues](https://github.com/alessiobussolari/better_model/issues)
586
+ 2. ๐Ÿ“ Create a new issue with:
266
587
  - Clear description of the problem
267
588
  - Steps to reproduce
268
589
  - Expected vs actual behavior
269
590
  - Ruby/Rails versions
270
591
  - Database adapter
271
592
 
272
- ### Submitting Pull Requests
593
+ ### ๐Ÿš€ Submitting Pull Requests
273
594
 
274
- 1. Fork the repository
275
- 2. Create a feature branch (`git checkout -b feature/amazing-feature`)
276
- 3. Make your changes with tests
277
- 4. Run the test suite (`bundle exec rake test`)
278
- 5. Ensure RuboCop passes (`bundle exec rubocop`)
279
- 6. Commit your changes (`git commit -m 'Add amazing feature'`)
280
- 7. Push to the branch (`git push origin feature/amazing-feature`)
281
- 8. Open a Pull Request
595
+ 1. ๐Ÿด Fork the repository
596
+ 2. ๐ŸŒฟ Create a feature branch (`git checkout -b feature/amazing-feature`)
597
+ 3. โœ๏ธ Make your changes with tests
598
+ 4. ๐Ÿงช Run the test suite (`bundle exec rake test`)
599
+ 5. ๐Ÿ’… Ensure RuboCop passes (`bundle exec rubocop`)
600
+ 6. ๐Ÿ’พ Commit your changes (`git commit -m 'Add amazing feature'`)
601
+ 7. ๐Ÿ“ค Push to the branch (`git push origin feature/amazing-feature`)
602
+ 8. ๐ŸŽ‰ Open a Pull Request
282
603
 
283
- ### Development Setup
604
+ ### ๐Ÿ”ง Development Setup
284
605
 
285
606
  ```bash
286
607
  # Clone your fork
@@ -300,13 +621,34 @@ bundle exec rake test # Coverage report in coverage/index.html
300
621
  bundle exec rubocop
301
622
  ```
302
623
 
303
- ### Code Guidelines
624
+ ### ๐Ÿ“Š Test Coverage Notes
625
+
626
+ The test suite runs on **SQLite** for performance and portability. Current coverage: **91.45%** (1272 / 1391 lines).
627
+
628
+ **Database-Specific Features Not Covered:**
629
+ - **Predicable**: PostgreSQL array predicates (`_overlaps`, `_contains`, `_contained_by`) and JSONB predicates (`_has_key`, `_has_any_key`, `_has_all_keys`, `_jsonb_contains`) - lines 278-376 in `lib/better_model/predicable.rb`
630
+ - **Traceable**: PostgreSQL JSONB queries and MySQL JSON_EXTRACT queries for field-specific change tracking - lines 454-489 in `lib/better_model/traceable.rb`
631
+ - **Sortable**: MySQL NULLS emulation with CASE statements - lines 198-203 in `lib/better_model/sortable.rb`
632
+
633
+ These features are fully implemented with proper SQL sanitization but require manual testing on PostgreSQL/MySQL:
634
+
635
+ ```bash
636
+ # Test on PostgreSQL
637
+ RAILS_ENV=test DATABASE_URL=postgresql://user:pass@localhost/better_model_test rails console
638
+
639
+ # Test on MySQL
640
+ RAILS_ENV=test DATABASE_URL=mysql2://user:pass@localhost/better_model_test rails console
641
+ ```
642
+
643
+ All code has inline comments marking database-specific sections for maintainability.
644
+
645
+ ### ๐Ÿ“ Code Guidelines
304
646
 
305
- - Follow the existing code style (enforced by RuboCop Omakase)
306
- - Write tests for new features
307
- - Update documentation (README) for user-facing changes
308
- - Keep pull requests focused (one feature/fix per PR)
647
+ - โœจ Follow the existing code style (enforced by RuboCop Omakase)
648
+ - ๐Ÿงช Write tests for new features
649
+ - ๐Ÿ“ Update documentation (README) for user-facing changes
650
+ - ๐ŸŽฏ Keep pull requests focused (one feature/fix per PR)
309
651
 
310
- ## License
652
+ ## ๐Ÿ“ License
311
653
 
312
654
  The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).