propel_facets 0.1.4 → 0.2.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 +4 -4
- data/CHANGELOG.md +31 -1
- data/better_nesting.md +166 -0
- data/lib/generators/propel_facets/install_generator.rb +12 -0
- data/lib/generators/propel_facets/templates/models/application_record.rb +12 -0
- data/lib/propel_facets.rb +1 -1
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 8764980d8f96e30b33af48655e5f663f462c2a163d414d0dd55122b069454bb8
|
4
|
+
data.tar.gz: 8c1169ffe3ffbbe48fff25ef54c26ffe2a2fd81c1c63257bac4eeda9992497d3
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 8312227990dd32b4026485fd9e331fea3504019342741511214a33754b8e8c67cbe4ce25817fb4f4d319dcf1e4a4e25e305eab590c96a6a8f860d64343021a8c
|
7
|
+
data.tar.gz: 4a8184cff3c9bf000f2b42e71cc7d2fb8f6c00c5b7f6c03a9035eba1079d2820cca44e9518dc86000994b4d475b4dc10d2ddefad3c89e715026889cd1d2f8fd4
|
data/CHANGELOG.md
CHANGED
@@ -14,7 +14,37 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
14
14
|
- Metadata inclusion (pagination, counts, etc.)
|
15
15
|
- Performance logging and optimization tools
|
16
16
|
|
17
|
-
## [0.1
|
17
|
+
## [0.2.1] - 2025-01-14
|
18
|
+
|
19
|
+
### Fixed
|
20
|
+
- **Critical generator bug**: Fixed missing `for_organization` scope in ApplicationRecord installation
|
21
|
+
- Install generator now properly adds `for_organization` scope when ApplicationRecord already exists
|
22
|
+
- Previously only added ModelFacet includes but not the multi-tenancy scope required by PropelApi controllers
|
23
|
+
- Enhanced scope implementation to handle both Organization objects and integer IDs
|
24
|
+
- Resolves `NoMethodError: undefined method 'for_organization' for Model:Class` in fresh Rails installations
|
25
|
+
- Updated both injection method and template files for consistency
|
26
|
+
|
27
|
+
## [0.2.0] - 2025-09-02
|
28
|
+
|
29
|
+
### Added
|
30
|
+
- **Enhanced facet pattern consistency** - Standardized JSON facet definitions across all models
|
31
|
+
- Support for comprehensive User model facets with authentication fields
|
32
|
+
- Improved association handling in facet rendering with proper include directives
|
33
|
+
- Consistent field inclusion patterns for better API consistency
|
34
|
+
|
35
|
+
### Improved
|
36
|
+
- **Compatibility updates** - Enhanced integration with PropelAuthentication 0.2.0 and PropelApi 0.2.0
|
37
|
+
- Updated to work with new security-first architecture
|
38
|
+
- Maintained full compatibility with enhanced JSON facet definitions
|
39
|
+
- Support for `PropelAuthenticationConcern` namespace changes
|
40
|
+
- Seamless integration with configurable tenancy requirements
|
41
|
+
|
42
|
+
### Fixed
|
43
|
+
- **JSON facet rendering** - Enhanced association handling and field inclusion
|
44
|
+
- Proper handling of organization associations in User model facets
|
45
|
+
- Consistent foreign key and association rendering across all model types
|
46
|
+
|
47
|
+
## [0.1.4] - 2025-08-15
|
18
48
|
|
19
49
|
### Added
|
20
50
|
- **Clean controller generation by default** - PropelFacets controller templates now generate production-ready code
|
data/better_nesting.md
ADDED
@@ -0,0 +1,166 @@
|
|
1
|
+
# Feature Implementation Guide: Per-Association Facet Specification in json_facet includes
|
2
|
+
|
3
|
+
## Current State
|
4
|
+
The `json_facet` system currently supports including associations, but all included associations use the same facet determined by the `include_as` parameter:
|
5
|
+
|
6
|
+
```ruby
|
7
|
+
# Current syntax - all associations use :included facet
|
8
|
+
json_facet :details,
|
9
|
+
fields: [:id, :name],
|
10
|
+
include: [:organization, :user, :comments],
|
11
|
+
include_as: :included
|
12
|
+
```
|
13
|
+
|
14
|
+
## Desired Feature
|
15
|
+
Enable specifying different facets for different associations within a single json_facet definition:
|
16
|
+
|
17
|
+
```ruby
|
18
|
+
# Proposed syntax - each association can specify its own facet
|
19
|
+
json_facet :details,
|
20
|
+
fields: [:id, :name],
|
21
|
+
include: {
|
22
|
+
organization: :short, # Use organization's :short facet
|
23
|
+
user: :included, # Use user's :included facet
|
24
|
+
comments: :minimal # Use comment's :minimal facet
|
25
|
+
}
|
26
|
+
```
|
27
|
+
|
28
|
+
## Implementation Approach
|
29
|
+
|
30
|
+
### 1. Modify `json_facet` method (line 74-85)
|
31
|
+
- Detect when `include` is a Hash vs Array
|
32
|
+
- Parse Hash format to extract association → facet mappings
|
33
|
+
- Maintain backward compatibility with Array format
|
34
|
+
|
35
|
+
### 2. Update `facet_serializable_options` method (line 154-161)
|
36
|
+
Current code:
|
37
|
+
```ruby
|
38
|
+
include = actual[:include].reduce({}) do |memo, current|
|
39
|
+
memo.update(current => { facet: include_as }) # Same facet for all
|
40
|
+
end
|
41
|
+
```
|
42
|
+
|
43
|
+
New logic needed:
|
44
|
+
```ruby
|
45
|
+
include = actual[:include].reduce({}) do |memo, current|
|
46
|
+
if current.is_a?(Hash)
|
47
|
+
# Handle { association: :facet_name } format
|
48
|
+
current.each do |assoc, facet|
|
49
|
+
memo.update(assoc => { facet: facet })
|
50
|
+
end
|
51
|
+
else
|
52
|
+
# Backward compatibility: use include_as for array format
|
53
|
+
memo.update(current => { facet: include_as })
|
54
|
+
end
|
55
|
+
memo
|
56
|
+
end
|
57
|
+
```
|
58
|
+
|
59
|
+
### 3. Mixed Syntax Support
|
60
|
+
Support combining both syntaxes in one facet:
|
61
|
+
```ruby
|
62
|
+
json_facet :details,
|
63
|
+
include: [:tags, { organization: :short, user: :minimal }],
|
64
|
+
include_as: :included # Default for array items
|
65
|
+
```
|
66
|
+
|
67
|
+
### 4. Validation & Error Handling
|
68
|
+
- Validate that specified facets exist on target models
|
69
|
+
- Provide meaningful error messages for missing facets
|
70
|
+
- Handle edge cases (nil facets, invalid association names)
|
71
|
+
|
72
|
+
## Example Usage Patterns
|
73
|
+
|
74
|
+
### Basic Usage
|
75
|
+
```ruby
|
76
|
+
class Product < ApplicationRecord
|
77
|
+
json_facet :api_response,
|
78
|
+
fields: [:id, :name, :price],
|
79
|
+
include: {
|
80
|
+
category: :short, # Just id, name
|
81
|
+
reviews: :summary, # rating, comment excerpt
|
82
|
+
seller: :public # name, avatar, rating
|
83
|
+
}
|
84
|
+
end
|
85
|
+
```
|
86
|
+
|
87
|
+
### Mixed with Array Syntax
|
88
|
+
```ruby
|
89
|
+
class BlogPost < ApplicationRecord
|
90
|
+
json_facet :feed_item,
|
91
|
+
fields: [:id, :title, :excerpt],
|
92
|
+
include: [
|
93
|
+
:tags, # Use default :included facet
|
94
|
+
{ author: :author_card } # Use custom :author_card facet
|
95
|
+
],
|
96
|
+
include_as: :included # Default for array items
|
97
|
+
end
|
98
|
+
```
|
99
|
+
|
100
|
+
### Nested Facet Chains
|
101
|
+
```ruby
|
102
|
+
class User < ApplicationRecord
|
103
|
+
json_facet :profile,
|
104
|
+
fields: [:id, :username],
|
105
|
+
include: {
|
106
|
+
organization: :public, # Organization uses its :public facet
|
107
|
+
posts: :feed_summary # Posts use their :feed_summary facet
|
108
|
+
}
|
109
|
+
end
|
110
|
+
|
111
|
+
class Organization < ApplicationRecord
|
112
|
+
json_facet :public,
|
113
|
+
fields: [:id, :name, :logo],
|
114
|
+
include: { industry: :basic } # Nested includes work too
|
115
|
+
end
|
116
|
+
```
|
117
|
+
|
118
|
+
## Backward Compatibility Requirements
|
119
|
+
- Existing `include: [:association]` syntax must continue working
|
120
|
+
- Current `include_as: :facet` behavior must remain unchanged for array includes
|
121
|
+
- No breaking changes to existing APIs
|
122
|
+
|
123
|
+
## Test Cases to Implement
|
124
|
+
|
125
|
+
### 1. Basic Hash Syntax
|
126
|
+
```ruby
|
127
|
+
test "should support hash syntax for per-association facets" do
|
128
|
+
# Test that each association uses its specified facet
|
129
|
+
end
|
130
|
+
```
|
131
|
+
|
132
|
+
### 2. Backward Compatibility
|
133
|
+
```ruby
|
134
|
+
test "should maintain array syntax compatibility" do
|
135
|
+
# Ensure existing code continues working
|
136
|
+
end
|
137
|
+
```
|
138
|
+
|
139
|
+
### 3. Mixed Syntax
|
140
|
+
```ruby
|
141
|
+
test "should support mixed array and hash syntax" do
|
142
|
+
# Test combining both syntaxes in one facet
|
143
|
+
end
|
144
|
+
```
|
145
|
+
|
146
|
+
### 4. Error Handling
|
147
|
+
```ruby
|
148
|
+
test "should handle missing facets gracefully" do
|
149
|
+
# Test behavior when specified facet doesn't exist
|
150
|
+
end
|
151
|
+
```
|
152
|
+
|
153
|
+
### 5. Deep Nesting
|
154
|
+
```ruby
|
155
|
+
test "should support nested facet chains" do
|
156
|
+
# Test that included objects can have their own includes
|
157
|
+
end
|
158
|
+
```
|
159
|
+
|
160
|
+
## Implementation Priority
|
161
|
+
1. **Phase 1**: Basic Hash syntax support
|
162
|
+
2. **Phase 2**: Mixed Array/Hash syntax
|
163
|
+
3. **Phase 3**: Advanced validation and error handling
|
164
|
+
4. **Phase 4**: Performance optimization for complex nested includes
|
165
|
+
|
166
|
+
This feature would provide much more granular control over JSON serialization while maintaining the elegant declarative syntax that makes json_facet powerful.
|
@@ -92,6 +92,18 @@ module PropelFacets
|
|
92
92
|
json_facet :short, base: :included, include_as: :reference
|
93
93
|
json_facet :details, base: :short, include_as: :included
|
94
94
|
|
95
|
+
# Organization scoping for multi-tenancy
|
96
|
+
scope :for_organization, ->(organization_or_id) {
|
97
|
+
case organization_or_id
|
98
|
+
when nil
|
99
|
+
none # No organization = no access
|
100
|
+
when Organization
|
101
|
+
where(organization: organization_or_id)
|
102
|
+
else
|
103
|
+
where(organization_id: organization_or_id)
|
104
|
+
end
|
105
|
+
}
|
106
|
+
|
95
107
|
RUBY
|
96
108
|
end
|
97
109
|
end
|
@@ -10,4 +10,16 @@ class ApplicationRecord < ActiveRecord::Base
|
|
10
10
|
json_facet :included, base: :reference
|
11
11
|
json_facet :short, base: :included, include_as: :reference
|
12
12
|
json_facet :details, base: :short, include_as: :included
|
13
|
+
|
14
|
+
# Organization scoping for multi-tenancy
|
15
|
+
scope :for_organization, ->(organization_or_id) {
|
16
|
+
case organization_or_id
|
17
|
+
when nil
|
18
|
+
none # No organization = no access
|
19
|
+
when Organization
|
20
|
+
where(organization: organization_or_id)
|
21
|
+
else
|
22
|
+
where(organization_id: organization_or_id)
|
23
|
+
end
|
24
|
+
}
|
13
25
|
end
|
data/lib/propel_facets.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: propel_facets
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1
|
4
|
+
version: 0.2.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Propel Team
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2025-
|
11
|
+
date: 2025-09-02 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rails
|
@@ -43,6 +43,7 @@ files:
|
|
43
43
|
- LICENSE
|
44
44
|
- README.md
|
45
45
|
- Rakefile
|
46
|
+
- better_nesting.md
|
46
47
|
- lib/generators/propel_facets/README.md
|
47
48
|
- lib/generators/propel_facets/USAGE
|
48
49
|
- lib/generators/propel_facets/install_generator.rb
|