better_model 1.0.0 โ†’ 1.1.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: 75b360674e8e3baf46d99e536d2e012f0bbeea56169f2133d65193f9e093973b
4
+ data.tar.gz: e4feb8e169012f8b94fe9f9ad720838d68d24df3e811c4de2fb1f018e4edef9a
5
5
  SHA512:
6
- metadata.gz: d42074244a7e4af9321b68e9657f343ac4c087956856cfd0cbfe68e72adc1fce5200fc051cdfe1badd0e6bc753dfa3abcf0603113e3dede3cd7ce083b3ba932c
7
- data.tar.gz: e5305841ab87d40047b6bc458bdac8a163a96d0d9e864ead0a0335ab84b53759a5da837cb6b95f1c2bdc3596fcd74dc7281d77d370a3db0aa9cc98f72c281708
6
+ metadata.gz: bc082d6e0b93b1750f73ab4878f26f7f99aa2080aeb05c8382f5e4b47ee6287402b984686cebe665a7ffa1b154683aa00ddb8b7a78e841d41f3446a27d104957
7
+ data.tar.gz: 5fd80c99b6e83ad69870226c06c949ba11b8e15e44883ba5b33c7e2ca8e79e0f0c79f8465ad6c176ba6726f8b3947819b39feaa94a316935fc2045f41b78a13c
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,46 @@ 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. SEARCHABLE - Configure unified search interface
56
95
  searchable do
57
96
  per_page 25
58
97
  max_per_page 100
@@ -62,41 +101,55 @@ class Article < ApplicationRecord
62
101
  end
63
102
  ```
64
103
 
65
- Now you can use all the features:
104
+ ๐Ÿ’ก **Now you can use all the features:**
66
105
 
67
106
  ```ruby
68
- # Check statuses
107
+ # โœ… Check statuses
69
108
  article.is?(:draft) # => true/false
70
109
  article.is_published? # => true/false
71
110
  article.statuses # => { draft: true, published: false, ... }
72
111
 
73
- # Check permissions
112
+ # ๐Ÿ” Check permissions
74
113
  article.permit?(:edit) # => true/false
75
114
  article.permit_delete? # => true/false
76
115
  article.permissions # => { edit: true, delete: true, ... }
77
116
 
78
- # Sort
117
+ # โฌ†๏ธ Sort
79
118
  Article.sort_title_asc
80
119
  Article.sort_view_count_desc
81
120
  Article.sort_published_at_desc
82
121
 
83
- # Filter with predicates
122
+ # ๐Ÿ” Filter with predicates
84
123
  Article.status_eq("published")
85
124
  Article.title_cont("Rails")
86
125
  Article.view_count_gteq(100)
87
126
  Article.published_at_present
88
127
 
89
- # Archive records
128
+ # ๐Ÿ—„๏ธ Archive records
90
129
  article.archive!(by: current_user, reason: "Outdated")
91
130
  article.archived? # => true
92
131
  article.restore!
93
132
 
94
- # Query archived records
133
+ # ๐Ÿ“‚ Query archived records
95
134
  Article.archived
96
135
  Article.not_archived
97
136
  Article.archived_recently(7.days)
98
137
 
99
- # Unified search with filters, sorting, and pagination
138
+ # โœ… Validate with groups (multi-step forms)
139
+ article.valid?(:step1) # Validate only step1 fields
140
+ article.valid?(:step2) # Validate only step2 fields
141
+ article.errors_for_group(:step1) # Get errors for step1 only
142
+
143
+ # ๐Ÿ”„ State machine transitions
144
+ article.state # => "draft"
145
+ article.draft? # => true
146
+ article.can_publish? # => true (checks guards)
147
+ article.publish! # Executes transition with guards & callbacks
148
+ article.published? # => true
149
+ article.state_transitions # History of all transitions
150
+ article.transition_history # Formatted history array
151
+
152
+ # ๐Ÿ”Ž Unified search with filters, sorting, and pagination
100
153
  Article.search(
101
154
  { status_eq: "published", view_count_gteq: 50 },
102
155
  orders: [:sort_published_at_desc],
@@ -104,7 +157,7 @@ Article.search(
104
157
  )
105
158
  ```
106
159
 
107
- ### Including Individual Concerns (Advanced)
160
+ ### ๐ŸŽฏ Including Individual Concerns (Advanced)
108
161
 
109
162
  If you only need specific features, you can include individual concerns:
110
163
 
@@ -115,19 +168,21 @@ class Article < ApplicationRecord
115
168
  include BetterModel::Archivable # Only archiving
116
169
  include BetterModel::Sortable # Only sorting
117
170
  include BetterModel::Predicable # Only filtering
171
+ include BetterModel::Validatable # Only validations
172
+ include BetterModel::Stateable # Only state machine
118
173
  include BetterModel::Searchable # Only search (requires Predicable & Sortable)
119
174
 
120
175
  # Define your features...
121
176
  end
122
177
  ```
123
178
 
124
- ## Requirements
179
+ ## โš™๏ธ Requirements
125
180
 
126
181
  - **Ruby:** 3.0 or higher
127
182
  - **Rails:** 8.1 or higher
128
183
  - **ActiveRecord:** Included with Rails
129
184
 
130
- ## Database Compatibility
185
+ ## ๐Ÿ’พ Database Compatibility
131
186
 
132
187
  BetterModel works with all databases supported by ActiveRecord:
133
188
 
@@ -143,20 +198,20 @@ BetterModel works with all databases supported by ActiveRecord:
143
198
  - Array predicates: `overlaps`, `contains`, `contained_by`
144
199
  - JSONB predicates: `has_key`, `has_any_key`, `has_all_keys`, `jsonb_contains`
145
200
 
146
- ## Features
201
+ ## ๐Ÿ“š Features
147
202
 
148
- BetterModel provides six powerful concerns that work together seamlessly:
203
+ BetterModel provides eight powerful concerns that work together seamlessly:
149
204
 
150
205
  ### ๐Ÿ“‹ Statusable - Declarative Status Management
151
206
 
152
207
  Define derived statuses dynamically based on model attributes - no database columns needed!
153
208
 
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
209
+ **๐ŸŽฏ Key Benefits:**
210
+ - โœจ Declarative DSL with clear, readable conditions
211
+ - โšก Statuses calculated in real-time from model attributes
212
+ - ๐Ÿ”— Reference other statuses in conditions
213
+ - ๐Ÿค– Automatic method generation (`is_draft?`, `is_published?`)
214
+ - ๐Ÿ”’ Thread-safe with immutable registry
160
215
 
161
216
  **[๐Ÿ“– Full Documentation โ†’](docs/statusable.md)**
162
217
 
@@ -166,12 +221,12 @@ Define derived statuses dynamically based on model attributes - no database colu
166
221
 
167
222
  Define permissions dynamically based on model state and statuses - perfect for authorization logic!
168
223
 
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
224
+ **๐ŸŽฏ Key Benefits:**
225
+ - โœจ Declarative DSL following Statusable pattern
226
+ - โšก Permissions calculated from model state
227
+ - ๐Ÿ”— Reference statuses in permission logic
228
+ - ๐Ÿค– Automatic method generation (`permit_edit?`, `permit_delete?`)
229
+ - ๐Ÿ”’ Thread-safe with immutable registry
175
230
 
176
231
  **[๐Ÿ“– Full Documentation โ†’](docs/permissible.md)**
177
232
 
@@ -181,30 +236,66 @@ Define permissions dynamically based on model state and statuses - perfect for a
181
236
 
182
237
  Soft-delete records with archive tracking, audit trails, and restoration capabilities.
183
238
 
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
239
+ **๐ŸŽฏ Key Benefits:**
240
+ - ๐ŸŽ›๏ธ Opt-in activation: only enabled when explicitly configured
241
+ - ๐Ÿ”„ Archive and restore methods with optional tracking
242
+ - โœ… Status methods: `archived?` and `active?`
243
+ - ๐Ÿ” Semantic scopes: `archived`, `not_archived`, `archived_only`
244
+ - ๐Ÿ› ๏ธ Helper predicates: `archived_today`, `archived_this_week`, `archived_recently`
245
+ - ๐Ÿ‘ป Optional default scope to hide archived records
246
+ - ๐Ÿš€ Migration generator with flexible options
247
+ - ๐Ÿ”’ Thread-safe with immutable configuration
193
248
 
194
249
  **[๐Ÿ“– Full Documentation โ†’](docs/archivable.md)**
195
250
 
196
251
  ---
197
252
 
253
+ ### โœ… Validatable - Declarative Validation System
254
+
255
+ Define validations declaratively with support for conditional rules, cross-field validation, business rules, and validation groups.
256
+
257
+ **๐ŸŽฏ Key Benefits:**
258
+ - ๐ŸŽ›๏ธ Opt-in activation: only enabled when explicitly configured
259
+ - โœจ Declarative DSL for all validation types
260
+ - ๐Ÿ”€ Conditional validations: `validate_if` / `validate_unless`
261
+ - ๐Ÿ”— Cross-field validations: `validate_order` for date/number comparisons
262
+ - ๐Ÿ’ผ Business rules: delegate complex logic to custom methods
263
+ - ๐Ÿ“‹ Validation groups: partial validation for multi-step forms
264
+ - ๐Ÿ”’ Thread-safe with immutable configuration
265
+
266
+ **[๐Ÿ“– Full Documentation โ†’](docs/validatable.md)**
267
+
268
+ ---
269
+
270
+ ### ๐Ÿ”„ Stateable - Declarative State Machine
271
+
272
+ Define state machines declaratively with transitions, guards, validations, and callbacks for robust workflow management.
273
+
274
+ **๐ŸŽฏ Key Benefits:**
275
+ - ๐ŸŽ›๏ธ Opt-in activation: only enabled when explicitly configured
276
+ - โœจ Declarative DSL for states and transitions
277
+ - ๐Ÿ›ก๏ธ Guards: preconditions with lambda, methods, or Statusable predicates
278
+ - โœ… Validations: custom validation logic per transition
279
+ - ๐Ÿ”— Callbacks: before/after/around hooks for each transition
280
+ - ๐Ÿ“œ State history tracking with customizable table names
281
+ - ๐Ÿค– Dynamic methods: `pending?`, `confirm!`, `can_confirm?`
282
+ - ๐Ÿ”— Integration with Statusable for complex guard logic
283
+ - ๐Ÿ”’ Thread-safe with immutable configuration
284
+
285
+ **[๐Ÿ“– Full Documentation โ†’](docs/stateable.md)**
286
+
287
+ ---
288
+
198
289
  ### โฌ†๏ธ Sortable - Type-Aware Sorting Scopes
199
290
 
200
291
  Generate intelligent sorting scopes automatically with database-specific optimizations and NULL handling.
201
292
 
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
293
+ **๐ŸŽฏ Key Benefits:**
294
+ - ๐ŸŽฏ Type-aware scope generation (string, numeric, datetime, boolean)
295
+ - ๐Ÿ”ค Case-insensitive sorting for strings
296
+ - ๐Ÿ’พ Database-specific NULLS FIRST/LAST support
297
+ - ๐Ÿ”— Sort by multiple fields with chaining
298
+ - โšก Optimized queries with proper indexing support
208
299
 
209
300
  **[๐Ÿ“– Full Documentation โ†’](docs/sortable.md)**
210
301
 
@@ -214,13 +305,13 @@ Generate intelligent sorting scopes automatically with database-specific optimiz
214
305
 
215
306
  Generate comprehensive predicate scopes for filtering and searching with support for all data types.
216
307
 
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
308
+ **๐ŸŽฏ Key Benefits:**
309
+ - โœ… Complete coverage: string, numeric, datetime, boolean, null predicates
310
+ - ๐Ÿ”’ Type-safe predicates based on column type
311
+ - ๐Ÿ”ค Case-insensitive string matching
312
+ - ๐Ÿ“Š Range queries (between) for numerics and dates
313
+ - ๐Ÿ˜ PostgreSQL array and JSONB support
314
+ - ๐Ÿ”— Chainable with standard ActiveRecord queries
224
315
 
225
316
  **[๐Ÿ“– Full Documentation โ†’](docs/predicable.md)**
226
317
 
@@ -230,57 +321,198 @@ Generate comprehensive predicate scopes for filtering and searching with support
230
321
 
231
322
  Orchestrate Predicable and Sortable into a powerful, secure search interface with pagination and security.
232
323
 
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
324
+ **๐ŸŽฏ Key Benefits:**
325
+ - ๐ŸŽฏ Unified API: single `search()` method for all operations
326
+ - ๐Ÿ”€ OR conditions for complex logic
327
+ - ๐Ÿ“„ Built-in pagination with DoS protection (max_per_page)
328
+ - ๐Ÿ”’ Security enforcement with required predicates
329
+ - โš™๏ธ Default ordering configuration
330
+ - ๐Ÿ’ช Strong parameters integration
331
+ - โœ… Type-safe validation of all parameters
241
332
 
242
333
  **[๐Ÿ“– Full Documentation โ†’](docs/searchable.md)**
243
334
 
244
335
  ---
245
336
 
246
- ## Version & Changelog
337
+ ### ๐Ÿ“œ Traceable - Audit Trail & Change Tracking
338
+
339
+ Track all changes to your records with comprehensive audit trail functionality, time-travel queries, and rollback capabilities.
340
+
341
+ **๐ŸŽฏ Key Benefits:**
342
+ - ๐ŸŽ›๏ธ Opt-in activation: only enabled when explicitly configured
343
+ - ๐Ÿค– Automatic change tracking on create/update/destroy
344
+ - โฐ Time-travel: reconstruct record state at any point in time
345
+ - โ†ฉ๏ธ Rollback: restore to previous versions
346
+ - ๐Ÿ“ Audit trail with who/why tracking
347
+ - ๐Ÿ” Query changes by user, date range, or field transitions
348
+ - ๐Ÿ—‚๏ธ Flexible table naming: per-model tables (default), shared table, or custom names
349
+
350
+ **[๐Ÿ“– Full Documentation โ†’](docs/traceable.md)**
351
+
352
+ #### ๐Ÿš€ Quick Setup
353
+
354
+ **1๏ธโƒฃ Step 1: Create the versions table**
355
+
356
+ By default, each model gets its own versions table (`{model}_versions`):
357
+
358
+ ```bash
359
+ # Creates migration for article_versions table
360
+ rails g better_model:traceable Article --create-table
361
+ rails db:migrate
362
+ ```
363
+
364
+ Or use a custom table name:
365
+
366
+ ```bash
367
+ # Creates migration for custom table name
368
+ rails g better_model:traceable Article --create-table --table-name=audit_log
369
+ rails db:migrate
370
+ ```
371
+
372
+ **2๏ธโƒฃ Step 2: Enable in your model**
373
+
374
+ ```ruby
375
+ class Article < ApplicationRecord
376
+ include BetterModel
377
+
378
+ # Activate traceable (opt-in)
379
+ traceable do
380
+ track :status, :title, :published_at # Fields to track
381
+ # versions_table 'audit_log' # Optional: custom table (default: article_versions)
382
+ end
383
+ end
384
+ ```
385
+
386
+ **๐Ÿ’ก Usage:**
387
+
388
+ ```ruby
389
+ # ๐Ÿค– Automatic tracking on changes
390
+ article.update!(status: "published", updated_by_id: user.id, updated_reason: "Approved")
391
+
392
+ # ๐Ÿ” Query version history
393
+ article.versions # All versions (ordered desc)
394
+ article.changes_for(:status) # Changes for specific field
395
+ article.audit_trail # Full formatted history
396
+
397
+ # โฐ Time-travel: reconstruct state at specific time
398
+ past_article = article.as_of(3.days.ago)
399
+ past_article.status # => "draft" (what it was 3 days ago)
400
+
401
+ # โ†ฉ๏ธ Rollback to previous version
402
+ version = article.versions.where(event: "updated").first
403
+ article.rollback_to(version, updated_by_id: user.id, updated_reason: "Mistake")
404
+
405
+ # ๐Ÿ“Š Class-level queries
406
+ Article.changed_by(user.id) # Records changed by user
407
+ Article.changed_between(1.week.ago, Time.current) # Changes in period
408
+ Article.status_changed_from("draft").to("published") # Specific transitions (PostgreSQL)
409
+
410
+ # ๐Ÿ“ฆ Integration with as_json
411
+ article.as_json(include_audit_trail: true) # Include full history in JSON
412
+ ```
413
+
414
+ **๐Ÿ’พ Database Schema:**
415
+
416
+ By default, each model gets its own versions table (e.g., `article_versions` for Article model).
417
+ You can also use a shared table across multiple models or a custom table name.
418
+
419
+ | Column | Type | Description |
420
+ |--------|------|-------------|
421
+ | `item_type` | string | Polymorphic model name |
422
+ | `item_id` | integer | Polymorphic record ID |
423
+ | `event` | string | Event type: created/updated/destroyed |
424
+ | `object_changes` | json | Before/after values for tracked fields |
425
+ | `updated_by_id` | integer | Optional: user who made the change |
426
+ | `updated_reason` | string | Optional: reason for the change |
427
+ | `created_at` | datetime | When the change occurred |
428
+
429
+ **๐Ÿ—‚๏ธ Table Naming Options:**
430
+
431
+ ```ruby
432
+ # 1๏ธโƒฃ Option 1: Per-model table (default)
433
+ class Article < ApplicationRecord
434
+ traceable do
435
+ track :status
436
+ # Uses article_versions table automatically
437
+ end
438
+ end
439
+
440
+ # 2๏ธโƒฃ Option 2: Custom table name
441
+ class Article < ApplicationRecord
442
+ traceable do
443
+ track :status
444
+ versions_table 'audit_log' # Uses audit_log table
445
+ end
446
+ end
447
+
448
+ # 3๏ธโƒฃ Option 3: Shared table across models
449
+ class Article < ApplicationRecord
450
+ traceable do
451
+ track :status
452
+ versions_table 'versions' # Shared table
453
+ end
454
+ end
455
+
456
+ class User < ApplicationRecord
457
+ traceable do
458
+ track :email
459
+ versions_table 'versions' # Same shared table
460
+ end
461
+ end
462
+ ```
463
+
464
+ **๐Ÿ“ Optional Tracking:**
465
+
466
+ To track who made changes and why, simply set attributes before saving:
467
+
468
+ ```ruby
469
+ article.updated_by_id = current_user.id
470
+ article.updated_reason = "Fixed typo"
471
+ article.update!(title: "Corrected Title")
472
+
473
+ # The version will automatically include updated_by_id and updated_reason
474
+ ```
475
+
476
+ ---
477
+
478
+ ## ๐Ÿ“Œ Version & Changelog
247
479
 
248
480
  **Current Version:** 1.0.0
249
481
 
250
482
  See [CHANGELOG.md](CHANGELOG.md) for version history and release notes.
251
483
 
252
- ## Support & Community
484
+ ## ๐Ÿ’ฌ Support & Community
253
485
 
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
486
+ - ๐Ÿ› **Issues & Bugs:** [GitHub Issues](https://github.com/alessiobussolari/better_model/issues)
487
+ - ๐Ÿ’ป **Source Code:** [GitHub Repository](https://github.com/alessiobussolari/better_model)
488
+ - ๐Ÿ“– **Documentation:** This README and detailed docs in `docs/` directory
257
489
 
258
- ## Contributing
490
+ ## ๐Ÿค Contributing
259
491
 
260
492
  We welcome contributions! Here's how you can help:
261
493
 
262
- ### Reporting Bugs
494
+ ### ๐Ÿ› Reporting Bugs
263
495
 
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:
496
+ 1. โœ… Check if the issue already exists in [GitHub Issues](https://github.com/alessiobussolari/better_model/issues)
497
+ 2. ๐Ÿ“ Create a new issue with:
266
498
  - Clear description of the problem
267
499
  - Steps to reproduce
268
500
  - Expected vs actual behavior
269
501
  - Ruby/Rails versions
270
502
  - Database adapter
271
503
 
272
- ### Submitting Pull Requests
504
+ ### ๐Ÿš€ Submitting Pull Requests
273
505
 
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
506
+ 1. ๐Ÿด Fork the repository
507
+ 2. ๐ŸŒฟ Create a feature branch (`git checkout -b feature/amazing-feature`)
508
+ 3. โœ๏ธ Make your changes with tests
509
+ 4. ๐Ÿงช Run the test suite (`bundle exec rake test`)
510
+ 5. ๐Ÿ’… Ensure RuboCop passes (`bundle exec rubocop`)
511
+ 6. ๐Ÿ’พ Commit your changes (`git commit -m 'Add amazing feature'`)
512
+ 7. ๐Ÿ“ค Push to the branch (`git push origin feature/amazing-feature`)
513
+ 8. ๐ŸŽ‰ Open a Pull Request
282
514
 
283
- ### Development Setup
515
+ ### ๐Ÿ”ง Development Setup
284
516
 
285
517
  ```bash
286
518
  # Clone your fork
@@ -300,13 +532,13 @@ bundle exec rake test # Coverage report in coverage/index.html
300
532
  bundle exec rubocop
301
533
  ```
302
534
 
303
- ### Code Guidelines
535
+ ### ๐Ÿ“ Code Guidelines
304
536
 
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)
537
+ - โœจ Follow the existing code style (enforced by RuboCop Omakase)
538
+ - ๐Ÿงช Write tests for new features
539
+ - ๐Ÿ“ Update documentation (README) for user-facing changes
540
+ - ๐ŸŽฏ Keep pull requests focused (one feature/fix per PR)
309
541
 
310
- ## License
542
+ ## ๐Ÿ“ License
311
543
 
312
544
  The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
@@ -115,7 +115,7 @@ module BetterModel
115
115
 
116
116
  # Applica default scope SOLO se configurato
117
117
  if archivable_config[:skip_archived_by_default]
118
- default_scope -> { not_archived }
118
+ default_scope -> { where(archived_at: nil) }
119
119
  end
120
120
  end
121
121
  end
@@ -124,19 +124,19 @@ module BetterModel
124
124
  #
125
125
  # @return [ActiveRecord::Relation]
126
126
  def archived_only
127
- raise NotEnabledError unless archivable_enabled?
127
+ raise ArchivableNotEnabledError unless archivable_enabled?
128
128
  unscoped.archived
129
129
  end
130
130
 
131
131
  # Helper: alias per archived_at_today
132
132
  def archived_today
133
- raise NotEnabledError unless archivable_enabled?
133
+ raise ArchivableNotEnabledError unless archivable_enabled?
134
134
  archived_at_today
135
135
  end
136
136
 
137
137
  # Helper: alias per archived_at_this_week
138
138
  def archived_this_week
139
- raise NotEnabledError unless archivable_enabled?
139
+ raise ArchivableNotEnabledError unless archivable_enabled?
140
140
  archived_at_this_week
141
141
  end
142
142
 
@@ -145,7 +145,7 @@ module BetterModel
145
145
  # @param duration [ActiveSupport::Duration] Durata (es: 7.days)
146
146
  # @return [ActiveRecord::Relation]
147
147
  def archived_recently(duration = 7.days)
148
- raise NotEnabledError unless archivable_enabled?
148
+ raise ArchivableNotEnabledError unless archivable_enabled?
149
149
  archived_at_within(duration)
150
150
  end
151
151
 
@@ -164,10 +164,10 @@ module BetterModel
164
164
  # @param by [Integer, Object] ID utente o oggetto user (opzionale)
165
165
  # @param reason [String] Motivo dell'archiviazione (opzionale)
166
166
  # @return [self]
167
- # @raise [NotEnabledError] se archivable non รจ attivo
167
+ # @raise [ArchivableNotEnabledError] se archivable non รจ attivo
168
168
  # @raise [AlreadyArchivedError] se giร  archiviato
169
169
  def archive!(by: nil, reason: nil)
170
- raise NotEnabledError unless self.class.archivable_enabled?
170
+ raise ArchivableNotEnabledError unless self.class.archivable_enabled?
171
171
  raise AlreadyArchivedError, "Record is already archived" if archived?
172
172
 
173
173
  self.archived_at = Time.current
@@ -186,10 +186,10 @@ module BetterModel
186
186
  # Ripristina record archiviato
187
187
  #
188
188
  # @return [self]
189
- # @raise [NotEnabledError] se archivable non รจ attivo
189
+ # @raise [ArchivableNotEnabledError] se archivable non รจ attivo
190
190
  # @raise [NotArchivedError] se non archiviato
191
191
  def restore!
192
- raise NotEnabledError unless self.class.archivable_enabled?
192
+ raise ArchivableNotEnabledError unless self.class.archivable_enabled?
193
193
  raise NotArchivedError, "Record is not archived" unless archived?
194
194
 
195
195
  self.archived_at = nil
@@ -241,7 +241,7 @@ module BetterModel
241
241
  class AlreadyArchivedError < ArchivableError; end
242
242
  class NotArchivedError < ArchivableError; end
243
243
 
244
- class NotEnabledError < ArchivableError
244
+ class ArchivableNotEnabledError < ArchivableError
245
245
  def initialize(msg = nil)
246
246
  super(msg || "Archivable is not enabled. Add 'archivable do...end' to your model.")
247
247
  end