support_table_data 1.4.0 → 1.5.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 +4 -4
- data/AGENTS.md +140 -0
- data/ARCHITECTURE.md +538 -0
- data/CHANGELOG.md +13 -0
- data/README.md +50 -5
- data/VERSION +1 -1
- data/lib/support_table_data/documentation/source_file.rb +95 -0
- data/lib/support_table_data/documentation/yard_doc.rb +91 -0
- data/lib/support_table_data/documentation.rb +9 -0
- data/lib/support_table_data/railtie.rb +22 -1
- data/lib/support_table_data/validation_error.rb +16 -0
- data/lib/support_table_data.rb +71 -53
- data/lib/tasks/support_table_data.rake +55 -12
- data/lib/tasks/utils.rb +63 -0
- data/support_table_data.gemspec +1 -1
- data/test_app/.gitignore +4 -0
- data/test_app/Gemfile +7 -0
- data/test_app/Rakefile +6 -0
- data/test_app/app/models/application_record.rb +5 -0
- data/test_app/app/models/secondary_application_record.rb +7 -0
- data/test_app/app/models/status.rb +11 -0
- data/test_app/app/models/thing.rb +10 -0
- data/test_app/bin/rails +4 -0
- data/test_app/config/application.rb +42 -0
- data/test_app/config/boot.rb +3 -0
- data/test_app/config/database.yml +17 -0
- data/test_app/config/environment.rb +5 -0
- data/test_app/config/environments/development.rb +11 -0
- data/test_app/config/environments/test.rb +11 -0
- data/test_app/config.ru +6 -0
- data/test_app/db/migrate/20260103060951_create_status.rb +8 -0
- data/test_app/db/schema.rb +20 -0
- data/test_app/db/secondary_migrate/20260104000001_create_things.rb +7 -0
- data/test_app/db/secondary_schema.rb +25 -0
- data/test_app/db/support_tables/statuses.yml +19 -0
- data/test_app/db/support_tables/things.yml +5 -0
- data/test_app/lib/tasks/database.rake +11 -0
- data/test_app/log/.keep +0 -0
- metadata +34 -8
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 7fded73fcb55268fa76b155b9cb192667bbe535e4e11f0cf00f8c3b8536fe3ee
|
|
4
|
+
data.tar.gz: 9e06e50abcba73a18918a7fe8fa0168c93a2d0b39c0d1cfa03f1d512368632af
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: c107aa8e78cfbdfe8fdafd1cc42bf2f25b90075f561e9a7933e643ec2773647f4f96cc047d4ed0b90f8b15cd50ffa1e1f282c7f3abc61e25d70c3fb5150a2958
|
|
7
|
+
data.tar.gz: 612b88d848c4eb101018bf2c643f8b76825e7bb22b459a6b5998a70238f9eb8627bbe7f6d8533b362b99300dcdce3a905bc3a22ca30c680ca03e4043c8837c7c
|
data/AGENTS.md
ADDED
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
# Copilot Instructions for support_table_data
|
|
2
|
+
|
|
3
|
+
## Project Overview
|
|
4
|
+
|
|
5
|
+
A Ruby gem providing an ActiveRecord mixin for managing support/lookup tables with canonical data defined in YAML/JSON/CSV files. The gem dynamically generates helper methods to reference specific records naturally in code (e.g., `Status.pending` instead of `Status.find_by(name: 'Pending')`).
|
|
6
|
+
|
|
7
|
+
**Core concept**: Support tables blur the line between data and code—they contain small canonical datasets that must exist for the application to work.
|
|
8
|
+
|
|
9
|
+
## Architecture
|
|
10
|
+
|
|
11
|
+
### Key Components
|
|
12
|
+
|
|
13
|
+
- **`SupportTableData` module** ([lib/support_table_data.rb](lib/support_table_data.rb)): Main concern mixed into ActiveRecord models
|
|
14
|
+
- **Named instance system**: Dynamically generates class methods (`.pending`), predicate methods (`.pending?`), and attribute helpers (`.pending_id`) from hash-based data files
|
|
15
|
+
- **Data sync engine**: Compares canonical data files with database records, creating/updating as needed in atomic transactions
|
|
16
|
+
- **File parsers**: Supports YAML, JSON, and CSV formats with unified interface
|
|
17
|
+
|
|
18
|
+
### Data Flow
|
|
19
|
+
|
|
20
|
+
1. Data files (YAML/JSON/CSV) define canonical records with unique key attributes
|
|
21
|
+
2. `add_support_table_data` registers file paths and triggers method generation for hash-based files
|
|
22
|
+
3. `sync_table_data!` parses files, loads matching DB records, and updates/creates within transactions
|
|
23
|
+
4. Named instance methods are dynamically defined via `class_eval` with memoization
|
|
24
|
+
|
|
25
|
+
## Development Workflows
|
|
26
|
+
|
|
27
|
+
### Running Tests
|
|
28
|
+
|
|
29
|
+
```bash
|
|
30
|
+
bundle exec rspec # Run all specs
|
|
31
|
+
bundle exec rspec spec/support_table_data_spec.rb # Single file
|
|
32
|
+
bundle exec rake appraisals # Test against all ActiveRecord versions
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
Uses RSpec with in-memory SQLite database. Test models defined in [spec/models.rb](spec/models.rb), data files in `spec/data/`.
|
|
36
|
+
|
|
37
|
+
### Testing Against Multiple ActiveRecord Versions
|
|
38
|
+
|
|
39
|
+
The gem supports ActiveRecord 6.0-8.0. Uses Appraisal for multi-version testing:
|
|
40
|
+
|
|
41
|
+
```bash
|
|
42
|
+
bundle exec appraisal install # Install all gemfiles
|
|
43
|
+
bundle exec appraisal rspec # Run specs against all versions
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
See `Appraisals` file and `gemfiles/` directory.
|
|
47
|
+
|
|
48
|
+
### Code Style
|
|
49
|
+
|
|
50
|
+
Uses Standard Ruby formatter:
|
|
51
|
+
|
|
52
|
+
```bash
|
|
53
|
+
bundle exec rake standard:fix # Auto-fix style issues
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
## Critical Patterns
|
|
57
|
+
|
|
58
|
+
### Named Instance Method Generation
|
|
59
|
+
|
|
60
|
+
**Hash-based data files** trigger dynamic method generation. Example from [spec/data/colors/named_colors.yml](spec/data/colors/named_colors.yml):
|
|
61
|
+
|
|
62
|
+
```yaml
|
|
63
|
+
red:
|
|
64
|
+
id: 1
|
|
65
|
+
name: Red
|
|
66
|
+
value: 16711680
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
Generates:
|
|
70
|
+
- `Color.red` → finds record by id
|
|
71
|
+
- `color_instance.red?` → tests if `color_instance.id == 1`
|
|
72
|
+
- `Color.red_id` → returns `1` (if `named_instance_attribute_helpers :id` defined)
|
|
73
|
+
|
|
74
|
+
**Implementation**: See `define_support_table_named_instance_methods` in [lib/support_table_data.rb](lib/support_table_data.rb#L230-L265). Methods are generated using `class_eval` with string interpolation.
|
|
75
|
+
|
|
76
|
+
### Custom Setters for Associations
|
|
77
|
+
|
|
78
|
+
Support tables often reference other support tables via named instances. Pattern from [spec/models.rb](spec/models.rb#L72-L74):
|
|
79
|
+
|
|
80
|
+
```ruby
|
|
81
|
+
def group_name=(value)
|
|
82
|
+
self.group = Group.named_instance(value)
|
|
83
|
+
end
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
Allows data files to reference related records by instance name instead of foreign keys.
|
|
87
|
+
|
|
88
|
+
### Key Attribute Configuration
|
|
89
|
+
|
|
90
|
+
By default, uses model's `id` column. Override for non-id keys:
|
|
91
|
+
|
|
92
|
+
```ruby
|
|
93
|
+
self.support_table_key_attribute = :name # Use 'name' instead of 'id'
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
Key attributes cannot be updated—changing them creates new records.
|
|
97
|
+
|
|
98
|
+
### Dependency Resolution
|
|
99
|
+
|
|
100
|
+
`sync_all!` automatically resolves dependencies via `belongs_to` associations and loads tables in correct order. For complex cases (join tables, indirect dependencies), explicitly declare:
|
|
101
|
+
|
|
102
|
+
```ruby
|
|
103
|
+
support_table_dependency "OtherModel"
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
See [lib/support_table_data.rb](lib/support_table_data.rb#L219-L222) and dependency resolution logic.
|
|
107
|
+
|
|
108
|
+
## Testing Conventions
|
|
109
|
+
|
|
110
|
+
- **Test data isolation**: Each test deletes all records in `before` block ([spec/spec_helper.rb](spec/spec_helper.rb))
|
|
111
|
+
- **Sync before assertions**: Tests call `sync_table_data!` or `sync_all!` before verifying records exist
|
|
112
|
+
- **Multi-file merging**: Tests verify that multiple data files for same model merge correctly (see `Color` model with 5 data files)
|
|
113
|
+
- **STI handling**: See `Polygon`/`Triangle`/`Rectangle` tests for Single Table Inheritance patterns
|
|
114
|
+
|
|
115
|
+
## Common Pitfalls
|
|
116
|
+
|
|
117
|
+
1. **Method name conflicts**: Named instance methods raise `ArgumentError` if method already exists. Instance names must match `/\A[a-z][a-z0-9_]+\z/`
|
|
118
|
+
2. **Array vs hash data**: Only hash-keyed data generates named instance methods. Use arrays or underscore-prefixed keys (`_others`) for records without helpers
|
|
119
|
+
3. **Protected instances**: Records in data files cannot be deleted via `destroy` (though this gem doesn't enforce it—see companion caching gem)
|
|
120
|
+
4. **Transaction safety**: All sync operations wrapped in transactions; changes rollback on failure
|
|
121
|
+
|
|
122
|
+
## Rails Integration
|
|
123
|
+
|
|
124
|
+
In Rails apps, the gem automatically:
|
|
125
|
+
- Sets `SupportTableData.data_directory` to `Rails.root/db/support_tables`
|
|
126
|
+
- Provides `rake support_table_data:sync` task ([lib/tasks/support_table_data.rake](lib/tasks/support_table_data.rake))
|
|
127
|
+
- Handles eager loading in both classic and Zeitwerk autoloaders
|
|
128
|
+
|
|
129
|
+
## File References
|
|
130
|
+
|
|
131
|
+
- Main module: [lib/support_table_data.rb](lib/support_table_data.rb)
|
|
132
|
+
- Test models: [spec/models.rb](spec/models.rb) - comprehensive examples of patterns
|
|
133
|
+
- Sync task: [lib/tasks/support_table_data.rake](lib/tasks/support_table_data.rake)
|
|
134
|
+
- Architecture docs: [ARCHITECTURE.md](ARCHITECTURE.md) - detailed diagrams and design decisions
|
|
135
|
+
|
|
136
|
+
## Version Compatibility
|
|
137
|
+
|
|
138
|
+
- Ruby ≥ 2.5
|
|
139
|
+
- ActiveRecord ≥ 6.0
|
|
140
|
+
- Ruby 3.4+: Requires `csv` gem in Gemfile (removed from stdlib)
|
data/ARCHITECTURE.md
ADDED
|
@@ -0,0 +1,538 @@
|
|
|
1
|
+
# Support Table Data Architecture
|
|
2
|
+
|
|
3
|
+
This document describes the architecture and design patterns of the `support_table_data` gem, which provides a robust solution for managing static support tables (lookup tables) in ActiveRecord applications.
|
|
4
|
+
|
|
5
|
+
## Overview
|
|
6
|
+
|
|
7
|
+
The SupportTableData gem solves the common problem of managing small, canonical datasets that exist at the intersection of data and code. These support tables contain a limited number of rows with values that are often referenced in application logic, making them critical for proper application function.
|
|
8
|
+
|
|
9
|
+
## Core Components
|
|
10
|
+
|
|
11
|
+
### Main Components Overview
|
|
12
|
+
|
|
13
|
+
```mermaid
|
|
14
|
+
flowchart TB
|
|
15
|
+
subgraph "Application Layer"
|
|
16
|
+
Model[ActiveRecord Model]
|
|
17
|
+
DataFiles[Data Files<br/>YAML/JSON/CSV]
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
subgraph "SupportTableData Gem"
|
|
21
|
+
Concern[SupportTableData Module]
|
|
22
|
+
Parser[File Parser]
|
|
23
|
+
Sync[Data Synchronizer]
|
|
24
|
+
Helpers[Helper Methods]
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
subgraph "Infrastructure"
|
|
28
|
+
DB[(Database)]
|
|
29
|
+
Rails[Rails Environment]
|
|
30
|
+
Rake[Rake Tasks]
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
Model --> Concern
|
|
34
|
+
DataFiles --> Parser
|
|
35
|
+
Parser --> Sync
|
|
36
|
+
Sync --> DB
|
|
37
|
+
Concern --> Helpers
|
|
38
|
+
Rails --> Rake
|
|
39
|
+
Rake --> Sync
|
|
40
|
+
|
|
41
|
+
style Concern fill:#e1f5fe
|
|
42
|
+
style DataFiles fill:#f3e5f5
|
|
43
|
+
style DB fill:#e8f5e8
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
## Data Flow Architecture
|
|
47
|
+
|
|
48
|
+
The gem follows a clear data flow pattern from static files to database records:
|
|
49
|
+
|
|
50
|
+
```mermaid
|
|
51
|
+
flowchart LR
|
|
52
|
+
subgraph "Source Data"
|
|
53
|
+
YML[YAML Files]
|
|
54
|
+
JSON[JSON Files]
|
|
55
|
+
CSV[CSV Files]
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
subgraph "Processing"
|
|
59
|
+
Parse[File Parser]
|
|
60
|
+
Validate[Data Validation]
|
|
61
|
+
Transform[Data Transformation]
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
subgraph "Storage"
|
|
65
|
+
Memory[In-Memory Cache]
|
|
66
|
+
DB[(Database Tables)]
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
subgraph "Usage"
|
|
70
|
+
Helpers[Helper Methods]
|
|
71
|
+
Queries[Database Queries]
|
|
72
|
+
Predicates[Predicate Methods]
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
YML --> Parse
|
|
76
|
+
JSON --> Parse
|
|
77
|
+
CSV --> Parse
|
|
78
|
+
Parse --> Validate
|
|
79
|
+
Validate --> Transform
|
|
80
|
+
Transform --> Memory
|
|
81
|
+
Transform --> DB
|
|
82
|
+
Memory --> Helpers
|
|
83
|
+
DB --> Queries
|
|
84
|
+
Helpers --> Predicates
|
|
85
|
+
|
|
86
|
+
style Parse fill:#fff3e0
|
|
87
|
+
style DB fill:#e8f5e8
|
|
88
|
+
style Helpers fill:#e3f2fd
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
## Class Structure
|
|
92
|
+
|
|
93
|
+
### Core Module Design
|
|
94
|
+
|
|
95
|
+
```mermaid
|
|
96
|
+
classDiagram
|
|
97
|
+
class SupportTableData {
|
|
98
|
+
+data_directory : String
|
|
99
|
+
+sync_all!() : Hash
|
|
100
|
+
+support_table_classes() : Array
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
class ActiveRecord_Model {
|
|
104
|
+
+support_table_key_attribute : String
|
|
105
|
+
+support_table_data_directory : String
|
|
106
|
+
+add_support_table_data(path)
|
|
107
|
+
+sync_table_data!() : Array
|
|
108
|
+
+named_instance(name) : Record
|
|
109
|
+
+instance_names() : Array
|
|
110
|
+
+protected_instance?(record) : Boolean
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
class NamedInstanceHelpers {
|
|
114
|
+
+class_name() : Record
|
|
115
|
+
+class_name_question() : Boolean
|
|
116
|
+
+class_name_attribute() : Value
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
class FileParser {
|
|
120
|
+
+parse_yaml(content) : Hash
|
|
121
|
+
+parse_json(content) : Hash
|
|
122
|
+
+parse_csv(content) : Array
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
class DataSynchronizer {
|
|
126
|
+
+sync_records(data) : Array
|
|
127
|
+
+create_record(attributes) : Record
|
|
128
|
+
+update_record(record, attributes) : Record
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
SupportTableData --> ActiveRecord_Model : extends
|
|
132
|
+
ActiveRecord_Model --> NamedInstanceHelpers : generates
|
|
133
|
+
ActiveRecord_Model --> FileParser : uses
|
|
134
|
+
ActiveRecord_Model --> DataSynchronizer : uses
|
|
135
|
+
|
|
136
|
+
note for NamedInstanceHelpers "Methods are dynamically generated based on data file content"
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
## Named Instance System
|
|
140
|
+
|
|
141
|
+
The gem's most powerful feature is its named instance system, which generates helper methods from data files:
|
|
142
|
+
|
|
143
|
+
```mermaid
|
|
144
|
+
flowchart TD
|
|
145
|
+
subgraph "Data File Structure"
|
|
146
|
+
HashData[Hash-based Data]
|
|
147
|
+
ArrayData[Array-based Data]
|
|
148
|
+
end
|
|
149
|
+
|
|
150
|
+
subgraph "Method Generation"
|
|
151
|
+
ClassMethods[Class Methods<br/>Status.pending]
|
|
152
|
+
InstanceMethods[Instance Methods<br/>status.pending?]
|
|
153
|
+
AttributeHelpers[Attribute Helpers<br/>Status.pending_id]
|
|
154
|
+
end
|
|
155
|
+
|
|
156
|
+
subgraph "Runtime Usage"
|
|
157
|
+
FindRecord[Find Specific Record]
|
|
158
|
+
TestRecord[Test Record Type]
|
|
159
|
+
GetAttribute[Get Static Attribute]
|
|
160
|
+
end
|
|
161
|
+
|
|
162
|
+
HashData --> ClassMethods
|
|
163
|
+
HashData --> InstanceMethods
|
|
164
|
+
ArrayData --> ClassMethods
|
|
165
|
+
ClassMethods --> FindRecord
|
|
166
|
+
InstanceMethods --> TestRecord
|
|
167
|
+
AttributeHelpers --> GetAttribute
|
|
168
|
+
|
|
169
|
+
style HashData fill:#f3e5f5
|
|
170
|
+
style ClassMethods fill:#e3f2fd
|
|
171
|
+
style InstanceMethods fill:#e8f5e8
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
## Data Synchronization Process
|
|
175
|
+
|
|
176
|
+
The synchronization process ensures database consistency with data files:
|
|
177
|
+
|
|
178
|
+
```mermaid
|
|
179
|
+
sequenceDiagram
|
|
180
|
+
participant App as Application
|
|
181
|
+
participant Model as AR Model
|
|
182
|
+
participant Parser as File Parser
|
|
183
|
+
participant DB as Database
|
|
184
|
+
|
|
185
|
+
App->>Model: sync_table_data!
|
|
186
|
+
Model->>Parser: Parse data files
|
|
187
|
+
Parser-->>Model: Canonical data
|
|
188
|
+
|
|
189
|
+
Model->>DB: BEGIN TRANSACTION
|
|
190
|
+
Model->>DB: Find existing records
|
|
191
|
+
DB-->>Model: Current records
|
|
192
|
+
|
|
193
|
+
loop For each record
|
|
194
|
+
Model->>Model: Compare attributes
|
|
195
|
+
alt Record changed
|
|
196
|
+
Model->>DB: UPDATE record
|
|
197
|
+
end
|
|
198
|
+
end
|
|
199
|
+
|
|
200
|
+
loop For new records
|
|
201
|
+
Model->>DB: INSERT record
|
|
202
|
+
end
|
|
203
|
+
|
|
204
|
+
Model->>DB: COMMIT TRANSACTION
|
|
205
|
+
Model-->>App: Changes summary
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
## File Format Support
|
|
209
|
+
|
|
210
|
+
The gem supports multiple data file formats with a unified interface:
|
|
211
|
+
|
|
212
|
+
```mermaid
|
|
213
|
+
flowchart LR
|
|
214
|
+
subgraph "Input Formats"
|
|
215
|
+
YAML[YAML<br/>*.yml, *.yaml]
|
|
216
|
+
JSON[JSON<br/>*.json]
|
|
217
|
+
CSV[CSV<br/>*.csv]
|
|
218
|
+
end
|
|
219
|
+
|
|
220
|
+
subgraph "Parser Layer"
|
|
221
|
+
YAMLParser[YAML::safe_load]
|
|
222
|
+
JSONParser[JSON::parse]
|
|
223
|
+
CSVParser[CSV Parser<br/>with headers]
|
|
224
|
+
end
|
|
225
|
+
|
|
226
|
+
subgraph "Output Format"
|
|
227
|
+
Hash[Hash Structure<br/>Named instances]
|
|
228
|
+
Array[Array Structure<br/>Simple records]
|
|
229
|
+
end
|
|
230
|
+
|
|
231
|
+
YAML --> YAMLParser
|
|
232
|
+
JSON --> JSONParser
|
|
233
|
+
CSV --> CSVParser
|
|
234
|
+
|
|
235
|
+
YAMLParser --> Hash
|
|
236
|
+
YAMLParser --> Array
|
|
237
|
+
JSONParser --> Hash
|
|
238
|
+
JSONParser --> Array
|
|
239
|
+
CSVParser --> Array
|
|
240
|
+
|
|
241
|
+
style YAML fill:#e8f5e8
|
|
242
|
+
style JSON fill:#fff3e0
|
|
243
|
+
style CSV fill:#f3e5f5
|
|
244
|
+
```
|
|
245
|
+
|
|
246
|
+
## Dependency Resolution
|
|
247
|
+
|
|
248
|
+
The gem automatically resolves dependencies between support table models:
|
|
249
|
+
|
|
250
|
+
```mermaid
|
|
251
|
+
flowchart TB
|
|
252
|
+
subgraph "Dependency Analysis"
|
|
253
|
+
Belongs[belongs_to Associations]
|
|
254
|
+
Explicit[Explicit Dependencies]
|
|
255
|
+
Through[has_many :through]
|
|
256
|
+
end
|
|
257
|
+
|
|
258
|
+
subgraph "Resolution Strategy"
|
|
259
|
+
Detect[Detect Dependencies]
|
|
260
|
+
Sort[Topological Sort]
|
|
261
|
+
Validate[Circular Detection]
|
|
262
|
+
end
|
|
263
|
+
|
|
264
|
+
subgraph "Load Order"
|
|
265
|
+
Level1[Independent Models]
|
|
266
|
+
Level2[Models with Dependencies]
|
|
267
|
+
Level3[Join Table Models]
|
|
268
|
+
end
|
|
269
|
+
|
|
270
|
+
Belongs --> Detect
|
|
271
|
+
Explicit --> Detect
|
|
272
|
+
Through --> Detect
|
|
273
|
+
|
|
274
|
+
Detect --> Sort
|
|
275
|
+
Sort --> Validate
|
|
276
|
+
Validate --> Level1
|
|
277
|
+
Level1 --> Level2
|
|
278
|
+
Level2 --> Level3
|
|
279
|
+
|
|
280
|
+
style Detect fill:#e3f2fd
|
|
281
|
+
style Sort fill:#f3e5f5
|
|
282
|
+
style Level1 fill:#e8f5e8
|
|
283
|
+
```
|
|
284
|
+
|
|
285
|
+
## Rails Integration
|
|
286
|
+
|
|
287
|
+
The gem integrates seamlessly with Rails applications:
|
|
288
|
+
|
|
289
|
+
```mermaid
|
|
290
|
+
flowchart TD
|
|
291
|
+
subgraph "Rails Boot Process"
|
|
292
|
+
Boot[Application Boot]
|
|
293
|
+
Eager[Eager Loading]
|
|
294
|
+
Routes[Routes Loading]
|
|
295
|
+
end
|
|
296
|
+
|
|
297
|
+
subgraph "Gem Integration"
|
|
298
|
+
Railtie[SupportTableData::Railtie]
|
|
299
|
+
Tasks[Rake Tasks]
|
|
300
|
+
AutoLoad[Auto Discovery]
|
|
301
|
+
end
|
|
302
|
+
|
|
303
|
+
subgraph "Development Workflow"
|
|
304
|
+
Migrate[db:migrate]
|
|
305
|
+
Sync[support_table_data:sync]
|
|
306
|
+
Test[Test Suite Setup]
|
|
307
|
+
end
|
|
308
|
+
|
|
309
|
+
Boot --> Railtie
|
|
310
|
+
Eager --> AutoLoad
|
|
311
|
+
Railtie --> Tasks
|
|
312
|
+
Tasks --> Sync
|
|
313
|
+
Migrate --> Sync
|
|
314
|
+
Sync --> Test
|
|
315
|
+
|
|
316
|
+
style Railtie fill:#e3f2fd
|
|
317
|
+
style Sync fill:#e8f5e8
|
|
318
|
+
style Test fill:#fff3e0
|
|
319
|
+
```
|
|
320
|
+
|
|
321
|
+
## Error Handling and Validation
|
|
322
|
+
|
|
323
|
+
The gem includes comprehensive error handling:
|
|
324
|
+
|
|
325
|
+
```mermaid
|
|
326
|
+
flowchart TD
|
|
327
|
+
subgraph "Validation Points"
|
|
328
|
+
FileFormat[File Format Validation]
|
|
329
|
+
DataStructure[Data Structure Validation]
|
|
330
|
+
MethodNames[Method Name Validation]
|
|
331
|
+
KeyAttributes[Key Attribute Validation]
|
|
332
|
+
end
|
|
333
|
+
|
|
334
|
+
subgraph "Error Types"
|
|
335
|
+
ParseError[File Parse Errors]
|
|
336
|
+
NameError[Method Name Conflicts]
|
|
337
|
+
DataError[Data Consistency Errors]
|
|
338
|
+
TransactionError[Database Transaction Errors]
|
|
339
|
+
end
|
|
340
|
+
|
|
341
|
+
subgraph "Recovery Strategies"
|
|
342
|
+
Rollback[Transaction Rollback]
|
|
343
|
+
ErrorReport[Detailed Error Messages]
|
|
344
|
+
PartialSync[Skip Invalid Records]
|
|
345
|
+
end
|
|
346
|
+
|
|
347
|
+
FileFormat --> ParseError
|
|
348
|
+
DataStructure --> DataError
|
|
349
|
+
MethodNames --> NameError
|
|
350
|
+
KeyAttributes --> DataError
|
|
351
|
+
|
|
352
|
+
ParseError --> ErrorReport
|
|
353
|
+
NameError --> ErrorReport
|
|
354
|
+
DataError --> Rollback
|
|
355
|
+
TransactionError --> Rollback
|
|
356
|
+
|
|
357
|
+
style ParseError fill:#ffebee
|
|
358
|
+
style Rollback fill:#e8f5e8
|
|
359
|
+
style ErrorReport fill:#fff3e0
|
|
360
|
+
```
|
|
361
|
+
|
|
362
|
+
## Performance Considerations
|
|
363
|
+
|
|
364
|
+
The gem is designed for optimal performance with small datasets:
|
|
365
|
+
|
|
366
|
+
```mermaid
|
|
367
|
+
flowchart LR
|
|
368
|
+
subgraph "Optimization Strategies"
|
|
369
|
+
SmallData[Small Dataset Focus<br/>< 100 records]
|
|
370
|
+
Memoization[Method Memoization]
|
|
371
|
+
Transaction[Atomic Transactions]
|
|
372
|
+
LazyLoad[Lazy Method Generation]
|
|
373
|
+
end
|
|
374
|
+
|
|
375
|
+
subgraph "Memory Management"
|
|
376
|
+
ClassVars[Class Variables]
|
|
377
|
+
Mutex[Thread Safety]
|
|
378
|
+
WeakRef[Weak References]
|
|
379
|
+
end
|
|
380
|
+
|
|
381
|
+
subgraph "Database Efficiency"
|
|
382
|
+
BulkOps[Bulk Operations]
|
|
383
|
+
IndexHints[Key Attribute Indexing]
|
|
384
|
+
MinQueries[Minimize Queries]
|
|
385
|
+
end
|
|
386
|
+
|
|
387
|
+
SmallData --> ClassVars
|
|
388
|
+
Memoization --> Mutex
|
|
389
|
+
Transaction --> BulkOps
|
|
390
|
+
LazyLoad --> WeakRef
|
|
391
|
+
|
|
392
|
+
ClassVars --> MinQueries
|
|
393
|
+
Mutex --> IndexHints
|
|
394
|
+
BulkOps --> MinQueries
|
|
395
|
+
|
|
396
|
+
style SmallData fill:#e8f5e8
|
|
397
|
+
style Transaction fill:#e3f2fd
|
|
398
|
+
style MinQueries fill:#fff3e0
|
|
399
|
+
```
|
|
400
|
+
|
|
401
|
+
## Extension Points
|
|
402
|
+
|
|
403
|
+
The gem provides several extension points for customization:
|
|
404
|
+
|
|
405
|
+
```mermaid
|
|
406
|
+
flowchart TB
|
|
407
|
+
subgraph "Customization Options"
|
|
408
|
+
KeyAttr[Custom Key Attributes]
|
|
409
|
+
DataDir[Custom Data Directories]
|
|
410
|
+
Parser[Custom File Parsers]
|
|
411
|
+
Validation[Custom Validations]
|
|
412
|
+
end
|
|
413
|
+
|
|
414
|
+
subgraph "Integration Hooks"
|
|
415
|
+
BeforeSync[Before Sync Callbacks]
|
|
416
|
+
AfterSync[After Sync Callbacks]
|
|
417
|
+
MethodGen[Method Generation Hooks]
|
|
418
|
+
ErrorHook[Error Handling Hooks]
|
|
419
|
+
end
|
|
420
|
+
|
|
421
|
+
subgraph "External Gems"
|
|
422
|
+
Cache[SupportTableCache]
|
|
423
|
+
Observers[ActiveRecord Observers]
|
|
424
|
+
Auditing[Auditing Gems]
|
|
425
|
+
end
|
|
426
|
+
|
|
427
|
+
KeyAttr --> BeforeSync
|
|
428
|
+
DataDir --> MethodGen
|
|
429
|
+
Parser --> ErrorHook
|
|
430
|
+
Validation --> AfterSync
|
|
431
|
+
|
|
432
|
+
BeforeSync --> Cache
|
|
433
|
+
MethodGen --> Observers
|
|
434
|
+
ErrorHook --> Auditing
|
|
435
|
+
|
|
436
|
+
style Cache fill:#e3f2fd
|
|
437
|
+
style BeforeSync fill:#f3e5f5
|
|
438
|
+
style MethodGen fill:#e8f5e8
|
|
439
|
+
```
|
|
440
|
+
|
|
441
|
+
## Deployment Strategy
|
|
442
|
+
|
|
443
|
+
The gem follows a deployment-friendly pattern:
|
|
444
|
+
|
|
445
|
+
```mermaid
|
|
446
|
+
flowchart LR
|
|
447
|
+
subgraph "Development"
|
|
448
|
+
DevData[Dev Data Files]
|
|
449
|
+
DevDB[Dev Database]
|
|
450
|
+
DevTest[Test Suite]
|
|
451
|
+
end
|
|
452
|
+
|
|
453
|
+
subgraph "CI/CD Pipeline"
|
|
454
|
+
Build[Build Process]
|
|
455
|
+
Migration[Run Migrations]
|
|
456
|
+
DataSync[Sync Support Data]
|
|
457
|
+
TestRun[Run Tests]
|
|
458
|
+
end
|
|
459
|
+
|
|
460
|
+
subgraph "Production"
|
|
461
|
+
ProdDB[Production Database]
|
|
462
|
+
ProdData[Production Data]
|
|
463
|
+
Monitor[Monitoring]
|
|
464
|
+
end
|
|
465
|
+
|
|
466
|
+
DevData --> Build
|
|
467
|
+
DevDB --> Migration
|
|
468
|
+
DevTest --> TestRun
|
|
469
|
+
|
|
470
|
+
Build --> Migration
|
|
471
|
+
Migration --> DataSync
|
|
472
|
+
DataSync --> TestRun
|
|
473
|
+
TestRun --> ProdDB
|
|
474
|
+
|
|
475
|
+
ProdDB --> ProdData
|
|
476
|
+
ProdData --> Monitor
|
|
477
|
+
|
|
478
|
+
style DataSync fill:#e8f5e8
|
|
479
|
+
style TestRun fill:#e3f2fd
|
|
480
|
+
style Monitor fill:#fff3e0
|
|
481
|
+
```
|
|
482
|
+
|
|
483
|
+
## Best Practices
|
|
484
|
+
|
|
485
|
+
### Model Organization
|
|
486
|
+
|
|
487
|
+
```mermaid
|
|
488
|
+
flowchart TD
|
|
489
|
+
subgraph "File Structure"
|
|
490
|
+
Models[app/models/]
|
|
491
|
+
DataFiles[db/support_tables/]
|
|
492
|
+
Tests[spec/models/]
|
|
493
|
+
end
|
|
494
|
+
|
|
495
|
+
subgraph "Naming Conventions"
|
|
496
|
+
ModelFile[status.rb]
|
|
497
|
+
DataFile[statuses.yml]
|
|
498
|
+
TestFile[status_spec.rb]
|
|
499
|
+
end
|
|
500
|
+
|
|
501
|
+
subgraph "Content Organization"
|
|
502
|
+
Includes[Include SupportTableData]
|
|
503
|
+
Config[Configure Directories]
|
|
504
|
+
AddData[Add Data Files]
|
|
505
|
+
Helpers[Define Helpers]
|
|
506
|
+
end
|
|
507
|
+
|
|
508
|
+
Models --> ModelFile
|
|
509
|
+
DataFiles --> DataFile
|
|
510
|
+
Tests --> TestFile
|
|
511
|
+
|
|
512
|
+
ModelFile --> Includes
|
|
513
|
+
DataFile --> Config
|
|
514
|
+
TestFile --> AddData
|
|
515
|
+
Config --> Helpers
|
|
516
|
+
|
|
517
|
+
style ModelFile fill:#e3f2fd
|
|
518
|
+
style DataFile fill:#f3e5f5
|
|
519
|
+
style Includes fill:#e8f5e8
|
|
520
|
+
```
|
|
521
|
+
|
|
522
|
+
## Summary
|
|
523
|
+
|
|
524
|
+
The SupportTableData gem provides a comprehensive solution for managing static support tables through:
|
|
525
|
+
|
|
526
|
+
1. **Declarative Configuration**: Define support data in version-controlled files
|
|
527
|
+
2. **Automatic Synchronization**: Keep database records in sync with data files
|
|
528
|
+
3. **Generated Helper Methods**: Clean, readable code for accessing specific records
|
|
529
|
+
4. **Dependency Management**: Automatic resolution of inter-table dependencies
|
|
530
|
+
5. **Rails Integration**: Seamless integration with Rails applications and deployment workflows
|
|
531
|
+
6. **Type Safety**: Compile-time method generation with runtime validation
|
|
532
|
+
7. **Performance**: Optimized for small datasets with minimal overhead
|
|
533
|
+
|
|
534
|
+
The architecture promotes maintainable code by keeping support data close to the application logic while ensuring data consistency across environments.
|
|
535
|
+
|
|
536
|
+
<function_calls>
|
|
537
|
+
<invoke name="get-syntax-docs-mermaid">
|
|
538
|
+
<parameter name="file">flowchart.md
|
data/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,19 @@ All notable changes to this project will be documented in this file.
|
|
|
4
4
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|
5
5
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
6
6
|
|
|
7
|
+
## 1.5.0
|
|
8
|
+
|
|
9
|
+
### Added
|
|
10
|
+
|
|
11
|
+
- The default data directory in a Rails application can be set with the `config.support_table.data_directory` option in the Rails application configuration.
|
|
12
|
+
- Added rake task `support_table_data:yard_docs:add` for Rails applications that will add YARD documentation to support table models for the named instance helpers. There is also a task `support_table_data:yard_docs:verify` that can be used in a build pipeline to verify that the documentation is up to date. You can also remove the documentation with the `support_table_data:yard_docs:remove` task.
|
|
13
|
+
- The data synchronization task is now automatically attached to several Rails tasks: `db:seed`, `db:seed:replant`, `db:prepare`, `db:test:prepare`, `db:fixtures:load`. Support tables will be synced after running any of these tasks. This can be disabled by setting `config.support_table.auto_sync = false` in the Rails application configuration.
|
|
14
|
+
|
|
15
|
+
### Changed
|
|
16
|
+
|
|
17
|
+
- The default data directory is now set in a Railtie and can be overridden with the `config.support_table.data_directory` option in the Rails application configuration.
|
|
18
|
+
- The `support_table_key_attribute` method now returns "id" if not explicitly set instead of implicitly interpreting `nil` as the primary key. This makes the behavior more consistent and explicit and avoids edge cases when running the code in environments where the database connection is not available. This is a breaking change if the table uses a primary key other than "id" and the `support_table_key_attribute` was not explicitly set to that primary key.
|
|
19
|
+
|
|
7
20
|
## 1.4.0
|
|
8
21
|
|
|
9
22
|
### Fixed
|