propel_facets 0.1.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.
- checksums.yaml +7 -0
- data/CHANGELOG.md +62 -0
- data/LICENSE +21 -0
- data/README.md +354 -0
- data/lib/generators/propel_facets/README.md +130 -0
- data/lib/generators/propel_facets/USAGE +68 -0
- data/lib/generators/propel_facets/install_generator.rb +152 -0
- data/lib/generators/propel_facets/templates/config/propel_facets.rb +188 -0
- data/lib/generators/propel_facets/templates/controllers/concerns/facet_renderer.rb +81 -0
- data/lib/generators/propel_facets/templates/controllers/concerns/strong_params_helper.rb +61 -0
- data/lib/generators/propel_facets/templates/doc/json_facet.md +78 -0
- data/lib/generators/propel_facets/templates/errors/application_error.rb +10 -0
- data/lib/generators/propel_facets/templates/errors/missing_facet.rb +13 -0
- data/lib/generators/propel_facets/templates/lib/api_params.rb +44 -0
- data/lib/generators/propel_facets/templates/models/application_record.rb +13 -0
- data/lib/generators/propel_facets/templates/models/concerns/model_facet.rb +189 -0
- data/lib/generators/propel_facets/test/propel_facets_generator_test.rb +75 -0
- data/lib/generators/propel_facets/test/test_helper.rb +20 -0
- data/lib/generators/propel_facets/unpack_generator.rb +307 -0
- data/lib/propel_facets.rb +3 -0
- metadata +86 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: da6cba3a34b195a31c1b16b7609f418cffd3b4b8ff94f54459a8a8abc2b55155
|
4
|
+
data.tar.gz: 119e220c8e5d0bc8f5a63b651bba57c8766a8cfffeecb5c7848bd079b45a8891
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: ed75a71a012e5740455d6aaadcbc9b374c7a0ad22a4cb7108d6036e00b73b6cc506a084bf744d02d857077e6e4541552015b1ed1fca463bea9706b26228a7b8d
|
7
|
+
data.tar.gz: 66d137d4866629b9e392d65abef7d916e66132710a945cbb7c5c8c5bdcd62cbaa7994175dd35f51f17d96136ae4e2d2ea59bf9ef2df5440c6a5c58ecbec26d95
|
data/CHANGELOG.md
ADDED
@@ -0,0 +1,62 @@
|
|
1
|
+
# Changelog
|
2
|
+
|
3
|
+
All notable changes to this project will be documented in this file.
|
4
|
+
|
5
|
+
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
6
|
+
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
7
|
+
|
8
|
+
## [Unreleased]
|
9
|
+
|
10
|
+
### Planned Features
|
11
|
+
- Caching system integration with Rails caching (Solid Cache support)
|
12
|
+
- Automatic association inclusion configuration
|
13
|
+
- Field naming conventions (camelCase, kebab-case, etc.)
|
14
|
+
- Metadata inclusion (pagination, counts, etc.)
|
15
|
+
- Performance logging and optimization tools
|
16
|
+
|
17
|
+
## [0.1.0] - 2025-01-XX
|
18
|
+
|
19
|
+
### Added
|
20
|
+
- **Self-extracting generator gem architecture** - Install temporarily, extract code, remove dependency
|
21
|
+
- **Rails generator system** with install and unpack commands
|
22
|
+
- **Model concern (ModelFacet)** for defining JSON facets with inheritance
|
23
|
+
- **Controller concerns** for rendering facets and parameter handling:
|
24
|
+
- `FacetRenderer` - Connect facets to controller actions
|
25
|
+
- `StrongParamsHelper` - Enhanced parameter handling for complex JSON
|
26
|
+
- **Complete configuration system** with implemented features only:
|
27
|
+
- JSON root structure configuration (`:data`, `:model`, `:class`, `:none`)
|
28
|
+
- API format selection (`:rest`, `:jsonapi`, `:openapi`, `:graphql`, etc.)
|
29
|
+
- Strict mode for error handling
|
30
|
+
- Default facets and inheritance patterns
|
31
|
+
- **Error handling system** with custom error classes
|
32
|
+
- **API parameter utilities** for complex JSON structures
|
33
|
+
- **Comprehensive documentation** and examples
|
34
|
+
- **Path gem installation** support for development workflow
|
35
|
+
- **Template system** with customizable generators
|
36
|
+
|
37
|
+
### Features
|
38
|
+
- **Multiple JSON representations** per model with simple DSL
|
39
|
+
- **Facet inheritance** with base facets and extension chains
|
40
|
+
- **Field and method selection** for precise API responses
|
41
|
+
- **Association rendering** with custom facet selection
|
42
|
+
- **Configurable JSON root structures** for different API standards
|
43
|
+
- **Rails conventions integration** with standard patterns
|
44
|
+
- **Zero runtime dependencies** after code extraction
|
45
|
+
|
46
|
+
### Technical Implementation
|
47
|
+
- Clean generator architecture following Rails conventions
|
48
|
+
- Template-based code generation for easy customization
|
49
|
+
- Proper Ruby module structure with namespace isolation
|
50
|
+
- Comprehensive test suite for generator functionality
|
51
|
+
- Documentation-driven development with extensive examples
|
52
|
+
|
53
|
+
### Generator Commands
|
54
|
+
- `rails generate propel_facets:install` - Install PropelFacets into application
|
55
|
+
- `rails generate propel_facets:unpack` - Extract generator for customization
|
56
|
+
- Selective unpacking with `--models-only`, `--controllers-only`, etc.
|
57
|
+
|
58
|
+
### Self-Extracting Benefits
|
59
|
+
- **No runtime gem dependencies** - all code lives in host application
|
60
|
+
- **Full customization control** - modify any generated component
|
61
|
+
- **Standard Rails patterns** - follows established conventions
|
62
|
+
- **Easy maintenance** - no hidden gem complexity in production
|
data/LICENSE
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
MIT License
|
2
|
+
|
3
|
+
Copyright (c) 2025 Propel Facets Generator
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
13
|
+
copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
21
|
+
SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,354 @@
|
|
1
|
+
# PropelFacets
|
2
|
+
|
3
|
+
A Rails generator that provides a flexible system for defining different JSON representations of ActiveRecord models and automatically connecting them to controller actions.
|
4
|
+
|
5
|
+
## Installation
|
6
|
+
|
7
|
+
PropelFacets is designed as a **self-extracting generator gem**. You install it temporarily, run the generators to extract the code into your application, then remove the gem dependency.
|
8
|
+
|
9
|
+
### Step 1: Add to Gemfile as a Path Gem
|
10
|
+
|
11
|
+
```ruby
|
12
|
+
# In your Gemfile
|
13
|
+
gem 'propel_facets', path: 'propel_facets'
|
14
|
+
```
|
15
|
+
|
16
|
+
### Step 2: Bundle Install
|
17
|
+
|
18
|
+
```bash
|
19
|
+
bundle install
|
20
|
+
```
|
21
|
+
|
22
|
+
### Step 3: Unpack the Generator (Optional)
|
23
|
+
|
24
|
+
If you want to customize the generator templates:
|
25
|
+
|
26
|
+
```bash
|
27
|
+
rails generate propel_facets:unpack
|
28
|
+
```
|
29
|
+
|
30
|
+
This extracts the generator into `lib/generators/propel_facets/` for customization.
|
31
|
+
|
32
|
+
### Step 4: Install PropelFacets
|
33
|
+
|
34
|
+
```bash
|
35
|
+
rails generate propel_facets:install
|
36
|
+
```
|
37
|
+
|
38
|
+
This installs the facets system including model and controller concerns, utilities, and configuration.
|
39
|
+
|
40
|
+
### Step 5: Remove Gem Dependency (Optional)
|
41
|
+
|
42
|
+
After installation, you can remove the gem from your Gemfile. All functionality remains in your application.
|
43
|
+
|
44
|
+
## Quick Start
|
45
|
+
|
46
|
+
### In Models
|
47
|
+
|
48
|
+
Define different JSON representations using facets:
|
49
|
+
|
50
|
+
```ruby
|
51
|
+
class User < ApplicationRecord
|
52
|
+
# Basic facet with specific fields
|
53
|
+
json_facet :summary, fields: [:id, :name, :email, :created_at]
|
54
|
+
|
55
|
+
# Extended facet building on another
|
56
|
+
json_facet :details, base: :summary,
|
57
|
+
fields: [:updated_at],
|
58
|
+
methods: [:full_name],
|
59
|
+
include: [:posts]
|
60
|
+
|
61
|
+
# Association facets
|
62
|
+
json_facet :with_posts, base: :summary, include: [:posts]
|
63
|
+
|
64
|
+
# Custom method
|
65
|
+
def full_name
|
66
|
+
"#{first_name} #{last_name}"
|
67
|
+
end
|
68
|
+
end
|
69
|
+
```
|
70
|
+
|
71
|
+
### In Controllers
|
72
|
+
|
73
|
+
Connect facets to controller actions:
|
74
|
+
|
75
|
+
```ruby
|
76
|
+
class UsersController < ApplicationController
|
77
|
+
include FacetRenderer
|
78
|
+
include StrongParamsHelper
|
79
|
+
|
80
|
+
connect_facet :summary, actions: [:index]
|
81
|
+
connect_facet :details, actions: [:show, :update]
|
82
|
+
|
83
|
+
permitted_params :name, :email, :role
|
84
|
+
|
85
|
+
def index
|
86
|
+
users = User.all
|
87
|
+
render json: { data: users.map { |user| resource_json(user) } }
|
88
|
+
end
|
89
|
+
|
90
|
+
def show
|
91
|
+
user = User.find(params[:id])
|
92
|
+
render json: { data: resource_json(user) }
|
93
|
+
end
|
94
|
+
end
|
95
|
+
```
|
96
|
+
|
97
|
+
### Enhanced Parameter Handling
|
98
|
+
|
99
|
+
For complex JSON parameters:
|
100
|
+
|
101
|
+
```ruby
|
102
|
+
class ProductsController < ApplicationController
|
103
|
+
include StrongParamsHelper
|
104
|
+
|
105
|
+
permitted_params :name, :price, :category
|
106
|
+
permitted_unknown_params :metadata, :settings # For dynamic JSON structures
|
107
|
+
|
108
|
+
def create
|
109
|
+
# Handles both strong params and unknown params
|
110
|
+
product = Product.new(resource_params)
|
111
|
+
# ...
|
112
|
+
end
|
113
|
+
end
|
114
|
+
```
|
115
|
+
|
116
|
+
## Features
|
117
|
+
|
118
|
+
### Flexible JSON Representations
|
119
|
+
- **Multiple facets per model** - Define various JSON views for different contexts
|
120
|
+
- **Facet inheritance** - Build complex facets by extending simpler ones
|
121
|
+
- **Field selection** - Include specific model attributes
|
122
|
+
- **Method inclusion** - Include results of model methods
|
123
|
+
- **Association rendering** - Include related models with their own facets
|
124
|
+
|
125
|
+
### Controller Integration
|
126
|
+
- **Automatic facet-action mapping** - Connect specific facets to controller actions
|
127
|
+
- **Resource JSON rendering** - Simple method to render models with appropriate facets
|
128
|
+
- **Enhanced parameter handling** - Support for complex JSON structures
|
129
|
+
- **Strong parameters extension** - Handles both known and unknown parameters
|
130
|
+
|
131
|
+
### Configuration System
|
132
|
+
- **JSON root structures** - Configure response format (`:data`, `:model`, `:class`, `:none`)
|
133
|
+
- **API format standards** - Support for REST, JSON:API, OpenAPI, GraphQL formats
|
134
|
+
- **Strict mode** - Control error handling for missing facets
|
135
|
+
- **Default facets** - Set up standard facets across all models
|
136
|
+
|
137
|
+
### Rails Integration
|
138
|
+
- **ApplicationRecord defaults** - Standard facets available on all models
|
139
|
+
- **ActiveStorage support** - Automatic attachment URL handling
|
140
|
+
- **Standard Rails patterns** - Follows Rails conventions throughout
|
141
|
+
- **Zero dependencies** - No runtime gem dependencies after extraction
|
142
|
+
|
143
|
+
## Facet Options
|
144
|
+
|
145
|
+
When defining facets, you can use these options:
|
146
|
+
|
147
|
+
- **`fields`**: Array of model attributes to include
|
148
|
+
- **`methods`**: Array of model methods to call and include
|
149
|
+
- **`include`**: Array of associations to include (uses association name as JSON key)
|
150
|
+
- **`include_as`**: Hash of associations with custom JSON key names
|
151
|
+
- **`base`**: Name of another facet to extend from
|
152
|
+
|
153
|
+
```ruby
|
154
|
+
class Article < ApplicationRecord
|
155
|
+
# Basic reference facet
|
156
|
+
json_facet :reference, fields: [:id, :title]
|
157
|
+
|
158
|
+
# Summary extends reference
|
159
|
+
json_facet :summary, base: :reference, fields: [:excerpt, :published_at]
|
160
|
+
|
161
|
+
# Details with methods and associations
|
162
|
+
json_facet :details, base: :summary,
|
163
|
+
methods: [:word_count, :reading_time],
|
164
|
+
include: [:author], # Will appear as "author" in JSON
|
165
|
+
include_as: [comments: :feedback] # Will appear as "feedback" in JSON
|
166
|
+
end
|
167
|
+
```
|
168
|
+
|
169
|
+
## Default Facets
|
170
|
+
|
171
|
+
All models inherit these default facets from `ApplicationRecord`:
|
172
|
+
|
173
|
+
- **`:reference`** - Basic id and type information
|
174
|
+
- **`:included`** - Extends reference facet
|
175
|
+
- **`:short`** - General purpose summary view
|
176
|
+
- **`:details`** - Comprehensive view with more fields
|
177
|
+
|
178
|
+
```ruby
|
179
|
+
# These are automatically available on all models:
|
180
|
+
User.first.as_json(facet: :reference) # => { "id": 1, "type": "User" }
|
181
|
+
User.first.as_json(facet: :short) # => More fields based on inheritance
|
182
|
+
```
|
183
|
+
|
184
|
+
## Configuration
|
185
|
+
|
186
|
+
Configure PropelFacets in `config/initializers/propel_facets.rb`:
|
187
|
+
|
188
|
+
```ruby
|
189
|
+
PropelFacets.configure do |config|
|
190
|
+
# JSON root structure: :data, :model, :class, :none
|
191
|
+
# :data => { "data": { "id": 1, "name": "John" } }
|
192
|
+
# :model => { "user": { "id": 1, "name": "John" } }
|
193
|
+
# :none => { "id": 1, "name": "John" }
|
194
|
+
config.root = :data
|
195
|
+
|
196
|
+
# API format standard: :rest, :jsonapi, :openapi, :graphql
|
197
|
+
config.api_format = :rest
|
198
|
+
|
199
|
+
# Default facets available on all models
|
200
|
+
config.default_facets = %w[reference included short details]
|
201
|
+
|
202
|
+
# Error handling: raise errors (true) or show warnings (false)
|
203
|
+
config.strict_mode = false
|
204
|
+
|
205
|
+
# Default base facet for inheritance chains
|
206
|
+
config.default_base_facet = :reference
|
207
|
+
end
|
208
|
+
```
|
209
|
+
|
210
|
+
## Advanced Usage
|
211
|
+
|
212
|
+
### Complex Facet Inheritance
|
213
|
+
|
214
|
+
```ruby
|
215
|
+
class Product < ApplicationRecord
|
216
|
+
# Base facets
|
217
|
+
json_facet :reference, fields: [:id, :name]
|
218
|
+
json_facet :pricing, fields: [:price, :currency]
|
219
|
+
|
220
|
+
# Combine multiple facets
|
221
|
+
json_facet :listing, base: :reference,
|
222
|
+
fields: [:description, :availability],
|
223
|
+
methods: [:formatted_price]
|
224
|
+
|
225
|
+
# Full details combining multiple concerns
|
226
|
+
json_facet :admin, base: :listing,
|
227
|
+
fields: [:cost, :margin, :created_at],
|
228
|
+
include: [:supplier, :reviews]
|
229
|
+
end
|
230
|
+
```
|
231
|
+
|
232
|
+
### Dynamic Parameter Handling
|
233
|
+
|
234
|
+
```ruby
|
235
|
+
class ApiController < ApplicationController
|
236
|
+
include StrongParamsHelper
|
237
|
+
|
238
|
+
# Handle known parameters
|
239
|
+
permitted_params :name, :email, :status
|
240
|
+
|
241
|
+
# Handle dynamic JSON structures
|
242
|
+
permitted_unknown_params :preferences, :metadata, :custom_fields
|
243
|
+
|
244
|
+
private
|
245
|
+
|
246
|
+
def resource_params
|
247
|
+
# Returns both strong params and unknown params merged
|
248
|
+
super
|
249
|
+
end
|
250
|
+
end
|
251
|
+
```
|
252
|
+
|
253
|
+
### Custom JSON Formatting
|
254
|
+
|
255
|
+
```ruby
|
256
|
+
# Configure different JSON root structures
|
257
|
+
PropelFacets.configure do |config|
|
258
|
+
config.root = :none # Flat JSON structure
|
259
|
+
end
|
260
|
+
|
261
|
+
# Result:
|
262
|
+
User.first.as_json(facet: :summary)
|
263
|
+
# => { "id": 1, "name": "John", "email": "john@example.com" }
|
264
|
+
|
265
|
+
# vs. with config.root = :data:
|
266
|
+
# => { "data": { "id": 1, "name": "John", "email": "john@example.com" } }
|
267
|
+
```
|
268
|
+
|
269
|
+
## Self-Extracting Architecture
|
270
|
+
|
271
|
+
PropelFacets follows a self-extracting pattern that provides:
|
272
|
+
|
273
|
+
- **No runtime dependencies** - all code lives in your application
|
274
|
+
- **Full control** - modify any component after installation
|
275
|
+
- **No black boxes** - transparent, readable Rails code
|
276
|
+
- **Easy maintenance** - standard Rails patterns throughout
|
277
|
+
|
278
|
+
After installation, you can:
|
279
|
+
- Remove the gem from your Gemfile
|
280
|
+
- Customize all generated code
|
281
|
+
- Maintain and extend functionality independently
|
282
|
+
- Modify facet behavior for your specific needs
|
283
|
+
|
284
|
+
## Generated Files
|
285
|
+
|
286
|
+
After installation, PropelFacets creates:
|
287
|
+
|
288
|
+
### Model Support
|
289
|
+
- `app/models/concerns/model_facet.rb` - Facet definition DSL for models
|
290
|
+
- `app/models/application_record.rb` - Base model with default facets (if needed)
|
291
|
+
|
292
|
+
### Controller Support
|
293
|
+
- `app/controllers/concerns/facet_renderer.rb` - Controller facet rendering
|
294
|
+
- `app/controllers/concerns/strong_params_helper.rb` - Enhanced parameter handling
|
295
|
+
|
296
|
+
### Utilities
|
297
|
+
- `lib/api_params.rb` - API parameter utility class
|
298
|
+
|
299
|
+
### Error Handling
|
300
|
+
- `app/errors/application_error.rb` - Base error class
|
301
|
+
- `app/errors/missing_facet.rb` - Facet-specific error handling
|
302
|
+
|
303
|
+
### Configuration
|
304
|
+
- `config/initializers/propel_facets.rb` - PropelFacets configuration
|
305
|
+
|
306
|
+
### Documentation
|
307
|
+
- `doc/json_facet.md` - Complete usage documentation and examples
|
308
|
+
|
309
|
+
## Integration with PropelApi
|
310
|
+
|
311
|
+
PropelFacets integrates seamlessly with PropelApi for complete API development:
|
312
|
+
|
313
|
+
```ruby
|
314
|
+
# Install both systems
|
315
|
+
rails generate propel_api:install --adapter=propel_facets
|
316
|
+
rails generate propel_facets:install
|
317
|
+
|
318
|
+
# Generated API controllers automatically use facets
|
319
|
+
class Api::V1::UsersController < Api::V1::ApiController
|
320
|
+
connect_facet :short, actions: [:index]
|
321
|
+
connect_facet :details, actions: [:show, :create, :update]
|
322
|
+
|
323
|
+
# Facet rendering is automatic
|
324
|
+
end
|
325
|
+
```
|
326
|
+
|
327
|
+
## Development
|
328
|
+
|
329
|
+
```bash
|
330
|
+
# Run facets tests
|
331
|
+
cd propel_facets
|
332
|
+
bundle exec rake test
|
333
|
+
|
334
|
+
# Test specific functionality
|
335
|
+
bundle exec ruby -Ilib:test test/propel_facets_generator_test.rb
|
336
|
+
```
|
337
|
+
|
338
|
+
## Roadmap
|
339
|
+
|
340
|
+
### Planned Features
|
341
|
+
- **Caching integration** - Rails caching support for rendered facets
|
342
|
+
- **Field naming conventions** - camelCase, kebab-case transformations
|
343
|
+
- **Metadata inclusion** - Pagination, counts, timestamps
|
344
|
+
- **Performance logging** - Monitor facet rendering performance
|
345
|
+
- **Nested depth limits** - Prevent infinite recursion
|
346
|
+
- **Type information** - Include model type data in JSON
|
347
|
+
|
348
|
+
## Contributing
|
349
|
+
|
350
|
+
Bug reports and pull requests are welcome on GitHub.
|
351
|
+
|
352
|
+
## License
|
353
|
+
|
354
|
+
The gem is available as open source under the [MIT License](https://opensource.org/licenses/MIT).
|
@@ -0,0 +1,130 @@
|
|
1
|
+
# PropelFacets
|
2
|
+
|
3
|
+
A Rails generator that provides a flexible system for defining different JSON representations of ActiveRecord models and automatically connecting them to controller actions.
|
4
|
+
|
5
|
+
## Installation
|
6
|
+
|
7
|
+
Add this line to your application's Gemfile:
|
8
|
+
|
9
|
+
```ruby
|
10
|
+
gem 'propel_facets'
|
11
|
+
```
|
12
|
+
|
13
|
+
And then execute:
|
14
|
+
|
15
|
+
```bash
|
16
|
+
$ bundle install
|
17
|
+
```
|
18
|
+
|
19
|
+
Or install it yourself as:
|
20
|
+
|
21
|
+
```bash
|
22
|
+
$ gem install propel_facets
|
23
|
+
```
|
24
|
+
|
25
|
+
## Usage
|
26
|
+
|
27
|
+
Generate the PropelFacets system in your Rails application:
|
28
|
+
|
29
|
+
```bash
|
30
|
+
$ bin/rails generate propel_facets
|
31
|
+
```
|
32
|
+
|
33
|
+
This will create:
|
34
|
+
|
35
|
+
- `app/models/concerns/model_facet.rb` - Model concern for defining facets
|
36
|
+
- `app/controllers/concerns/facet_renderer.rb` - Controller concern for rendering facets
|
37
|
+
- `app/controllers/concerns/strong_params_helper.rb` - Enhanced parameter handling
|
38
|
+
- `lib/api_params.rb` - API parameter utility class
|
39
|
+
- `app/errors/application_error.rb` - Base error class
|
40
|
+
- `app/errors/missing_facet.rb` - Facet-specific error class
|
41
|
+
- `app/models/application_record.rb` - Base model with default facets (if doesn't exist)
|
42
|
+
- `doc/json_facet.md` - Complete documentation
|
43
|
+
|
44
|
+
## Quick Start
|
45
|
+
|
46
|
+
### In Models
|
47
|
+
|
48
|
+
Define different JSON representations using facets:
|
49
|
+
|
50
|
+
```ruby
|
51
|
+
class User < ApplicationRecord
|
52
|
+
# Basic facet with specific fields
|
53
|
+
json_facet :short, fields: [:name, :email, :created_at]
|
54
|
+
|
55
|
+
# Extended facet building on another
|
56
|
+
json_facet :details, base: :short,
|
57
|
+
fields: [:updated_at],
|
58
|
+
methods: [:full_name],
|
59
|
+
include: [:posts]
|
60
|
+
end
|
61
|
+
```
|
62
|
+
|
63
|
+
### In Controllers
|
64
|
+
|
65
|
+
Connect facets to controller actions:
|
66
|
+
|
67
|
+
```ruby
|
68
|
+
class UsersController < ApplicationController
|
69
|
+
include FacetRenderer
|
70
|
+
include StrongParamsHelper
|
71
|
+
|
72
|
+
connect_facet :short, actions: [:index]
|
73
|
+
connect_facet :details, actions: [:show]
|
74
|
+
|
75
|
+
permitted_params :name, :email, :role
|
76
|
+
|
77
|
+
def index
|
78
|
+
users = User.all
|
79
|
+
render json: { data: users.map { |u| resource_json(u) } }
|
80
|
+
end
|
81
|
+
end
|
82
|
+
```
|
83
|
+
|
84
|
+
### Parameter Handling
|
85
|
+
|
86
|
+
For complex JSON parameters:
|
87
|
+
|
88
|
+
```ruby
|
89
|
+
class ProductsController < ApplicationController
|
90
|
+
include StrongParamsHelper
|
91
|
+
|
92
|
+
permitted_params :name, :price, :category
|
93
|
+
permitted_unknown_params :metadata, :settings # For dynamic JSON structures
|
94
|
+
end
|
95
|
+
```
|
96
|
+
|
97
|
+
## Features
|
98
|
+
|
99
|
+
- **Flexible JSON representations** with facet inheritance
|
100
|
+
- **Automatic controller-action mapping**
|
101
|
+
- **Strong parameters with JSON support** including complex structures
|
102
|
+
- **Active Storage attachment handling**
|
103
|
+
- **Comprehensive error handling**
|
104
|
+
- **Rails-like conventions** and familiar patterns
|
105
|
+
|
106
|
+
## Documentation
|
107
|
+
|
108
|
+
After installation, see `doc/json_facet.md` for complete documentation including:
|
109
|
+
|
110
|
+
- Advanced facet options
|
111
|
+
- Parameter handling patterns
|
112
|
+
- Error handling
|
113
|
+
- Best practices
|
114
|
+
|
115
|
+
## Development
|
116
|
+
|
117
|
+
To test the generator:
|
118
|
+
|
119
|
+
```bash
|
120
|
+
$ cd lib/generators/propel_facets
|
121
|
+
$ ruby test/propel_facets_generator_test.rb
|
122
|
+
```
|
123
|
+
|
124
|
+
## Contributing
|
125
|
+
|
126
|
+
Bug reports and pull requests are welcome on GitHub.
|
127
|
+
|
128
|
+
## License
|
129
|
+
|
130
|
+
The gem is available as open source under the [MIT License](https://opensource.org/licenses/MIT).
|
@@ -0,0 +1,68 @@
|
|
1
|
+
Description:
|
2
|
+
PropelFacets is a self-extracting generator gem that provides a flexible system for
|
3
|
+
defining different JSON representations of your ActiveRecord models and automatically
|
4
|
+
connecting them to controller actions.
|
5
|
+
|
6
|
+
Installation:
|
7
|
+
1. Add to Gemfile: gem 'propel_facets', path: 'lib/propel_facets'
|
8
|
+
2. Run: bundle install
|
9
|
+
3. Optionally unpack: bin/rails generate propel_facets:unpack
|
10
|
+
4. Install: bin/rails generate propel_facets:install
|
11
|
+
5. Optionally remove gem from Gemfile (functionality remains)
|
12
|
+
|
13
|
+
Example:
|
14
|
+
bin/rails generate propel_facets:install
|
15
|
+
|
16
|
+
This will create:
|
17
|
+
config/initializers/propel_facets.rb - Configuration file
|
18
|
+
app/models/concerns/model_facet.rb - Model concern for defining facets
|
19
|
+
app/controllers/concerns/facet_renderer.rb - Controller concern for rendering facets
|
20
|
+
app/controllers/concerns/strong_params_helper.rb - Enhanced parameter handling
|
21
|
+
lib/api_params.rb - API parameter utility class
|
22
|
+
app/errors/application_error.rb - Base error class
|
23
|
+
app/errors/missing_facet.rb - Facet-specific error class
|
24
|
+
doc/json_facet.md - Complete documentation
|
25
|
+
app/models/application_record.rb - Base model with default facets (if doesn't exist)
|
26
|
+
|
27
|
+
Unpack Generator:
|
28
|
+
bin/rails generate propel_facets:unpack # Extract generator for customization
|
29
|
+
bin/rails generate propel_facets:unpack --templates-only # Only templates
|
30
|
+
bin/rails generate propel_facets:unpack --models-only # Only model templates
|
31
|
+
bin/rails generate propel_facets:unpack --controllers-only # Only controller templates
|
32
|
+
bin/rails generate propel_facets:unpack --errors-only # Only error templates
|
33
|
+
bin/rails generate propel_facets:unpack --lib-only # Only lib templates
|
34
|
+
bin/rails generate propel_facets:unpack --docs-only # Only documentation
|
35
|
+
|
36
|
+
Quick Start Usage:
|
37
|
+
In models, define facets for different JSON representations:
|
38
|
+
class User < ApplicationRecord
|
39
|
+
json_facet :summary, fields: [:id, :name, :email]
|
40
|
+
json_facet :details, base: :summary, fields: [:created_at], methods: [:full_name]
|
41
|
+
end
|
42
|
+
|
43
|
+
In controllers, connect facets to actions:
|
44
|
+
class UsersController < ApplicationController
|
45
|
+
include FacetRenderer
|
46
|
+
include StrongParamsHelper
|
47
|
+
|
48
|
+
connect_facet :summary, actions: [:index]
|
49
|
+
connect_facet :details, actions: [:show]
|
50
|
+
|
51
|
+
permitted_params :name, :email, :role
|
52
|
+
end
|
53
|
+
|
54
|
+
Configuration:
|
55
|
+
Configure in config/initializers/propel_facets.rb:
|
56
|
+
PropelFacets.configure do |config|
|
57
|
+
config.root = :data # JSON root structure
|
58
|
+
config.api_format = :rest # API format standard
|
59
|
+
config.strict_mode = false # Error handling mode
|
60
|
+
end
|
61
|
+
|
62
|
+
Self-Extracting Architecture:
|
63
|
+
PropelFacets is designed to be installed temporarily, extract its functionality
|
64
|
+
into your application, then be removed. This ensures:
|
65
|
+
- No runtime gem dependencies
|
66
|
+
- Full control over all generated code
|
67
|
+
- Easy customization of all components
|
68
|
+
- Standard Rails patterns throughout
|