propel_api 0.2.1 โ 0.3.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 +97 -0
- data/README.md +239 -4
- data/lib/generators/propel_api/controller/controller_generator.rb +26 -0
- data/lib/generators/propel_api/core/named_base.rb +97 -1
- data/lib/generators/propel_api/core/relationship_inferrer.rb +4 -11
- data/lib/generators/propel_api/install/install_generator.rb +39 -2
- data/lib/generators/propel_api/resource/resource_generator.rb +205 -63
- data/lib/generators/propel_api/templates/config/propel_api.rb.tt +26 -1
- data/lib/generators/propel_api/templates/controllers/api_base_controller.rb +75 -0
- data/lib/generators/propel_api/templates/controllers/api_controller_graphiti.rb +3 -3
- data/lib/generators/propel_api/templates/controllers/api_controller_propel_facets.rb +22 -12
- data/lib/generators/propel_api/templates/controllers/example_controller.rb.tt +2 -2
- data/lib/generators/propel_api/templates/errors/propel_api_csrf_error.rb +19 -0
- data/lib/generators/propel_api/templates/scaffold/facet_controller_template.rb.tt +41 -8
- data/lib/generators/propel_api/templates/scaffold/facet_model_template.rb.tt +43 -10
- data/lib/generators/propel_api/templates/scaffold/graphiti_controller_template.rb.tt +1 -1
- data/lib/generators/propel_api/templates/scaffold/graphiti_resource_template.rb.tt +2 -2
- data/lib/generators/propel_api/templates/seeds/seeds_template.rb.tt +65 -17
- data/lib/generators/propel_api/templates/tests/controller_test_template.rb.tt +40 -6
- data/lib/generators/propel_api/templates/tests/fixtures_template.yml.tt +61 -18
- data/lib/generators/propel_api/templates/tests/integration_test_template.rb.tt +154 -42
- data/lib/generators/propel_api/templates/tests/model_test_template.rb.tt +20 -0
- data/lib/propel_api.rb +1 -1
- metadata +24 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 8891f7c2c3ace04fe703d6613d1a2595e19ed7ecaf89ecf960c3000bd1b00e0d
|
4
|
+
data.tar.gz: c51158c13407e9b91b01eb10d27b8bb89f5c80517855737a684e6f1fba88eac3
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: c22770ffc6b60119d08f3f8d0e8d6d5f3520f9518b9cedf2c2ae0ad5dbe2e1cc5c98577cdf4639f228b66796a60dbbe901fbbaeb69ee5aaecdc96630a418a116
|
7
|
+
data.tar.gz: ea3cbbc43f1f827ceebb10d9e64cc56374ef8d0dbb24e015608bba00bfa1a9608d27edf343c7e2f9677ed049df906a5a1bf45af1161a85bb5d5a85646e67253c
|
data/CHANGELOG.md
CHANGED
@@ -10,9 +10,106 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
10
10
|
### Planned Features
|
11
11
|
- GraphQL adapter support
|
12
12
|
|
13
|
+
## [0.3.1] - 2025-09-11
|
14
|
+
|
15
|
+
### ๐ New Features
|
16
|
+
- **Full Stack and API-Only Rails App Support**: Enhanced architecture for different Rails application types
|
17
|
+
- New dedicated `api_base_controller.rb` template for API-only applications
|
18
|
+
- Improved controller template organization with better separation of concerns
|
19
|
+
- Enhanced CSRF error handling with dedicated `PropelApiCsrfError` class
|
20
|
+
- Better support for both full-stack Rails apps and API-only applications
|
21
|
+
|
22
|
+
### ๐ง Enhanced Polymorphic Support
|
23
|
+
- **Improved Polymorphic Generators**: Enhanced automatic fixture and test generation with --parents flag
|
24
|
+
- Better polymorphic association handling in controller and model generators
|
25
|
+
- Automatic fixture template adoption for polymorphic relationships
|
26
|
+
- Enhanced agency-organization relationship support in polymorphic contexts
|
27
|
+
- **URL/Website/Domain Support**: Enhanced template handling for URL, website, and domain fields
|
28
|
+
- Improved model templates for URL validation and formatting
|
29
|
+
- Better seed data generation for URL-type fields
|
30
|
+
- Enhanced test coverage for URL/domain fields in fixtures and integration tests
|
31
|
+
|
32
|
+
### ๐ ๏ธ Generator Improvements
|
33
|
+
- **Enhanced Core Named Base**: Improved polymorphic association detection and fixture generation
|
34
|
+
- Better template processing for polymorphic relationships
|
35
|
+
- Enhanced fixture name resolution and parent type selection
|
36
|
+
- Improved error handling for polymorphic parent specifications
|
37
|
+
- **Template System Enhancements**: Upgraded all ERB templates for better polymorphic handling
|
38
|
+
- Consistent fixture template adoption across all generators
|
39
|
+
- Better integration with PropelAuthentication fixture patterns
|
40
|
+
- Enhanced test template generation with polymorphic parameter support
|
41
|
+
- **Controller Architecture Improvements**: Enhanced controller template system
|
42
|
+
- Updated Graphiti and PropelFacets controller templates for better inheritance
|
43
|
+
- Improved controller base class organization and method visibility
|
44
|
+
|
45
|
+
### ๐ Bug Fixes
|
46
|
+
- **Gem Installation**: Fixed issues with gems not being included when commented out in Gemfile
|
47
|
+
- **Integration Test Templates**: Enhanced error handling and parameter validation in generated integration tests
|
48
|
+
|
49
|
+
### โ ๏ธ Breaking Changes
|
50
|
+
- **REQUIRED --parents for Polymorphic**: Polymorphic associations now require explicit `--parents Parent1,Parent2` declaration. Auto-discovery fallback has been removed. Generator will block with confirmation if --parents is missing.
|
51
|
+
|
52
|
+
## [0.3.0] - 2025-01-15
|
53
|
+
|
54
|
+
### ๐ Major Features Added
|
55
|
+
- **Full Polymorphic Association Support**: Complete implementation of polymorphic relationships in API resources
|
56
|
+
- New `--parents` command-line option for specifying valid parent models
|
57
|
+
- Automatic generation of correct fixtures, tests, and API parameters
|
58
|
+
- Support for quote-free polymorphic syntax: `field_name:polymorphic`
|
59
|
+
- Enhanced fixture generation using Rails' `fixture_name (ModelName)` syntax
|
60
|
+
|
61
|
+
### โ ๏ธ Breaking Changes
|
62
|
+
- **Generator Syntax Change**: Tenancy associations are not automatically created you must pass organization:references and/or agency:references and configure the tenancy in the PropelApi configurations, any automated workflows or CI/CD that generate resources assuming the organization and/or agency references will be auto-injected will break with generator calls.
|
63
|
+
- **Required --parents Option**: Polymorphic resources now require `--parents field_name:Parent1,Parent2` for proper test generation
|
64
|
+
- **Fixture Format Change**: Polymorphic fixtures now use `field_name: fixture_name (ParentClass)` instead of hardcoded IDs
|
65
|
+
- **Test Template Updates**: All test templates now include polymorphic-aware parameter generation
|
66
|
+
|
67
|
+
### ๐ง Generator Improvements
|
68
|
+
- **Enhanced Resource Generator**:
|
69
|
+
- Added polymorphic syntax conversion (`field_name:polymorphic` โ `field_name:references{polymorphic}`)
|
70
|
+
- Improved argument processing to handle polymorphic parent specifications
|
71
|
+
- Fixed migration generation to use processed attributes instead of raw ARGV
|
72
|
+
- **Smart Fixture References**:
|
73
|
+
- Automatic fixture name resolution (e.g., uses `marketing_agency` instead of `one` for Agency models)
|
74
|
+
- Dynamic parent type selection for varied test data
|
75
|
+
- Proper Rails fixture syntax for polymorphic associations
|
76
|
+
|
77
|
+
### ๐งช Test Generation Enhancements
|
78
|
+
- **Model Tests**:
|
79
|
+
- Polymorphic association validation with proper parent type checking
|
80
|
+
- Automatic setup of polymorphic parent variables (`@field_name`)
|
81
|
+
- Correct assertions for polymorphic relationships
|
82
|
+
- **Controller Tests**:
|
83
|
+
- Automatic inclusion of both `field_name_id` and `field_name_type` in test parameters
|
84
|
+
- Proper polymorphic parent setup in test fixtures
|
85
|
+
- **Integration Tests**:
|
86
|
+
- Enhanced error handling tests with polymorphic parameter support
|
87
|
+
- Multi-tenancy isolation tests work correctly with polymorphic associations
|
88
|
+
- Comprehensive API workflow testing
|
89
|
+
|
90
|
+
### ๐๏ธ Architecture Improvements
|
91
|
+
- **Named Base Enhancements**:
|
92
|
+
- New `polymorphic_associations` helper method
|
93
|
+
- Enhanced `polymorphic_parent_for_fixture` with fixture name resolution
|
94
|
+
- Improved parent type parsing and validation
|
95
|
+
- **Template System**:
|
96
|
+
- All ERB templates now polymorphic-aware
|
97
|
+
- Consistent handling of polymorphic vs. regular references
|
98
|
+
- Better error handling and edge case management
|
99
|
+
|
100
|
+
### ๐ Bug Fixes
|
101
|
+
- **Migration Constraints**: Fixed polymorphic migrations to use `polymorphic: true` instead of incorrect `foreign_key: true`
|
102
|
+
- **Fixture Loading**: Resolved issues with hardcoded IDs causing fixture loading failures
|
103
|
+
- **Test Isolation**: Fixed multi-tenancy tests failing due to missing polymorphic associations
|
104
|
+
- **API Parameter Generation**: Corrected missing `_type` parameters in generated API calls
|
105
|
+
|
13
106
|
## [0.2.1] - 2025-01-14
|
14
107
|
|
15
108
|
### Fixed
|
109
|
+
- **Critical Pagy pagination bug**: Fixed `NoMethodError: undefined method 'items' for Pagy`
|
110
|
+
- API controller templates now use correct `pagy.limit` instead of non-existent `pagy.items`
|
111
|
+
- Fixes pagination metadata generation in API responses
|
112
|
+
- Affects all generated API controllers with pagination
|
16
113
|
- **Dependency update**: Improved compatibility with PropelFacets 0.2.1
|
17
114
|
- API controllers now work correctly with fixed `for_organization` scope installation
|
18
115
|
- Resolves `NoMethodError` when using generated controllers in fresh Rails installations
|
data/README.md
CHANGED
@@ -49,13 +49,16 @@ After installation, you can remove the gem from your Gemfile. All functionality
|
|
49
49
|
|
50
50
|
```bash
|
51
51
|
# Basic resource with PropelFacets
|
52
|
-
rails generate propel_api User name:string email:string role:string
|
52
|
+
rails generate propel_api:resource User name:string email:string role:string
|
53
53
|
|
54
54
|
# Resource with associations
|
55
|
-
rails generate propel_api Article title:string content:text user:references category:references
|
55
|
+
rails generate propel_api:resource Article title:string content:text user:references category:references
|
56
56
|
|
57
|
-
# Polymorphic associations
|
58
|
-
rails generate propel_api Comment content:text commentable:references
|
57
|
+
# ๐ NEW: Polymorphic associations (v0.3.0) - REQUIRES --parents flag
|
58
|
+
rails generate propel_api:resource Comment content:text commentable:references{polymorphic} --parents Post,Video,Product
|
59
|
+
|
60
|
+
# Polymorphic with tenancy
|
61
|
+
rails generate propel_api:resource Review rating:integer comment:text review_parent:polymorphic --parents Product,Agency
|
59
62
|
|
60
63
|
# With Graphiti adapter
|
61
64
|
rails generate propel_api Product name:string price:decimal --adapter=graphiti
|
@@ -70,6 +73,238 @@ This generates:
|
|
70
73
|
- **Fixtures** with realistic test data
|
71
74
|
- **Seeds** with Faker-generated sample data
|
72
75
|
|
76
|
+
## ๐ Polymorphic Association Support (v0.3.0)
|
77
|
+
|
78
|
+
PropelApi now provides comprehensive support for polymorphic associations with automatic test generation and intelligent fixture management.
|
79
|
+
|
80
|
+
### Quick Start with Polymorphic Resources
|
81
|
+
|
82
|
+
```bash
|
83
|
+
# Generate a Comment that can belong to Posts, Videos, or Products
|
84
|
+
rails generate propel_api:resource Comment body:text commentable:references{polymorphic} --parents Post,Video,Product
|
85
|
+
|
86
|
+
# Generate a Review with full tenancy support
|
87
|
+
rails generate propel_api:resource Review rating:integer comment:text review_parent:references{polymorphic} --parents Product,Agency
|
88
|
+
```
|
89
|
+
|
90
|
+
### Key Features
|
91
|
+
|
92
|
+
#### โจ Simple, Intuitive Syntax
|
93
|
+
- Additional support `field_name:polymorphic` instead of Rails' verbose `field_name:references{polymorphic}`
|
94
|
+
- No need for complex quote escaping or nested syntax
|
95
|
+
|
96
|
+
#### ๐ฏ Required Parent Specification
|
97
|
+
- `--parents Parent1,Parent2,Parent3` defines valid parent models (REQUIRED for polymorphic associations)
|
98
|
+
- Automatically generates varied test data using different parent types
|
99
|
+
- Generator will block with confirmation if --parents is not provided
|
100
|
+
|
101
|
+
#### ๐งช Complete Test Coverage
|
102
|
+
- **Model Tests**: Proper polymorphic association validation and parent type checking
|
103
|
+
- **Controller Tests**: Automatic inclusion of both `_id` and `_type` parameters
|
104
|
+
- **Integration Tests**: Full API workflow testing with polymorphic data
|
105
|
+
- **Fixtures**: Uses Rails' clean `fixture_name (ModelName)` syntax
|
106
|
+
|
107
|
+
#### ๐ง Generated Code Quality
|
108
|
+
```ruby
|
109
|
+
# Generated Model
|
110
|
+
class Comment < ApplicationRecord
|
111
|
+
belongs_to :commentable, polymorphic: true
|
112
|
+
# ... other associations and validations
|
113
|
+
end
|
114
|
+
|
115
|
+
# Generated Migration
|
116
|
+
def change
|
117
|
+
create_table :comments do |t|
|
118
|
+
t.text :body
|
119
|
+
t.references :commentable, polymorphic: true, null: false
|
120
|
+
# ... other fields
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
# Generated Fixtures (clean Rails syntax)
|
125
|
+
one:
|
126
|
+
commentable: one (Post)
|
127
|
+
body: "Great post!"
|
128
|
+
|
129
|
+
two:
|
130
|
+
commentable: featured_video (Video)
|
131
|
+
body: "Amazing video content!"
|
132
|
+
```
|
133
|
+
|
134
|
+
#### ๐ API-Ready Controllers
|
135
|
+
Controllers automatically include proper parameter handling:
|
136
|
+
```ruby
|
137
|
+
class Api::V1::CommentsController < Api::V1::ApiController
|
138
|
+
permitted_params :body, :commentable_id, :commentable_type
|
139
|
+
end
|
140
|
+
```
|
141
|
+
|
142
|
+
### Breaking Changes from v0.2.x
|
143
|
+
|
144
|
+
โ ๏ธ **Migration Required**: The polymorphic syntax and test generation has been completely rewritten for better reliability and Rails compatibility.
|
145
|
+
|
146
|
+
- **Old**: `rails generate propel_api:resource Comment body:text commentable:references{polymorphic}`
|
147
|
+
- **New**: `rails generate propel_api:resource Comment body:text commentable:polymorphic --parents commentable:Post,Video`
|
148
|
+
|
149
|
+
The new approach provides:
|
150
|
+
- More reliable test generation
|
151
|
+
- Better fixture management
|
152
|
+
- Cleaner, more maintainable code
|
153
|
+
- Full Rails compatibility
|
154
|
+
|
155
|
+
## ๐ API Explorer for Development
|
156
|
+
|
157
|
+
PropelApi includes a comprehensive test application with multiple API resources perfect for development and testing. The dummy app provides a fully functional API with authentication, multi-tenancy, and polymorphic associations.
|
158
|
+
|
159
|
+
### Quick Start with the Test API
|
160
|
+
|
161
|
+
```bash
|
162
|
+
# Navigate to the test application
|
163
|
+
cd test/dummy
|
164
|
+
|
165
|
+
# Set up the database
|
166
|
+
rails db:setup
|
167
|
+
|
168
|
+
# Start the development server
|
169
|
+
rails server
|
170
|
+
|
171
|
+
# Your API is now running at http://localhost:3000
|
172
|
+
```
|
173
|
+
|
174
|
+
### Available API Endpoints
|
175
|
+
|
176
|
+
The dummy app provides these fully functional endpoints:
|
177
|
+
|
178
|
+
#### Authentication
|
179
|
+
- `POST /api/v1/signup` - User registration
|
180
|
+
- `POST /api/v1/login` - User authentication
|
181
|
+
- `GET /api/v1/me` - Current user info
|
182
|
+
- `DELETE /api/v1/logout` - Logout
|
183
|
+
- `POST /api/v1/reset` - Password reset request
|
184
|
+
- `PATCH /api/v1/reset` - Password reset update
|
185
|
+
|
186
|
+
#### Core Resources
|
187
|
+
- `GET|POST /api/v1/users` - User management
|
188
|
+
- `GET|POST /api/v1/organizations` - Organization management
|
189
|
+
- `GET|POST|PATCH|DELETE /api/v1/products` - Product CRUD
|
190
|
+
- `GET|POST|PATCH|DELETE /api/v1/comments` - Comment CRUD
|
191
|
+
- `GET|POST|PATCH|DELETE /api/v1/attachments` - File attachments
|
192
|
+
- `GET|POST|PATCH|DELETE /api/v1/reviews` - Reviews (polymorphic!)
|
193
|
+
|
194
|
+
### Setting Up API Explorer Tools
|
195
|
+
|
196
|
+
#### Option 1: Postman Collection
|
197
|
+
|
198
|
+
Create a Postman collection with these base settings:
|
199
|
+
|
200
|
+
```json
|
201
|
+
{
|
202
|
+
"info": {
|
203
|
+
"name": "PropelApi Development",
|
204
|
+
"schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json"
|
205
|
+
},
|
206
|
+
"variable": [
|
207
|
+
{
|
208
|
+
"key": "base_url",
|
209
|
+
"value": "http://localhost:3000/api/v1",
|
210
|
+
"type": "string"
|
211
|
+
},
|
212
|
+
{
|
213
|
+
"key": "auth_token",
|
214
|
+
"value": "",
|
215
|
+
"type": "string"
|
216
|
+
}
|
217
|
+
]
|
218
|
+
}
|
219
|
+
```
|
220
|
+
|
221
|
+
#### Option 2: Insomnia Workspace
|
222
|
+
|
223
|
+
1. Create a new workspace in Insomnia
|
224
|
+
2. Set base URL: `http://localhost:3000/api/v1`
|
225
|
+
3. Create environment variables:
|
226
|
+
- `base_url`: `http://localhost:3000/api/v1`
|
227
|
+
- `auth_token`: (will be populated after login)
|
228
|
+
|
229
|
+
#### Option 3: cURL Scripts
|
230
|
+
|
231
|
+
```bash
|
232
|
+
# Login and get token
|
233
|
+
TOKEN=$(curl -s -X POST http://localhost:3000/api/v1/login \
|
234
|
+
-H "Content-Type: application/json" \
|
235
|
+
-d '{"data": {"email_address": "test@example.com", "password": "password123"}}' \
|
236
|
+
| jq -r '.token')
|
237
|
+
|
238
|
+
# Use token for authenticated requests
|
239
|
+
curl -H "Authorization: Bearer $TOKEN" \
|
240
|
+
-H "Content-Type: application/json" \
|
241
|
+
http://localhost:3000/api/v1/me
|
242
|
+
```
|
243
|
+
|
244
|
+
### API Response Format
|
245
|
+
|
246
|
+
All PropelApi endpoints follow consistent JSON:API-inspired formatting:
|
247
|
+
|
248
|
+
```json
|
249
|
+
{
|
250
|
+
"data": {
|
251
|
+
"id": 1,
|
252
|
+
"name": "Example Product",
|
253
|
+
"price": 99.99,
|
254
|
+
"organization": {
|
255
|
+
"id": 1,
|
256
|
+
"name": "Test Organization"
|
257
|
+
}
|
258
|
+
},
|
259
|
+
"meta": {
|
260
|
+
"total": 1,
|
261
|
+
"page": 1,
|
262
|
+
"limit": 25
|
263
|
+
}
|
264
|
+
}
|
265
|
+
```
|
266
|
+
|
267
|
+
### Testing Polymorphic Associations
|
268
|
+
|
269
|
+
The Reviews resource demonstrates polymorphic associations:
|
270
|
+
|
271
|
+
```bash
|
272
|
+
# Create a review for a product
|
273
|
+
curl -X POST http://localhost:3000/api/v1/reviews \
|
274
|
+
-H "Authorization: Bearer $TOKEN" \
|
275
|
+
-H "Content-Type: application/json" \
|
276
|
+
-d '{
|
277
|
+
"data": {
|
278
|
+
"rating": 5,
|
279
|
+
"comment": "Great product!",
|
280
|
+
"reviewable_id": 1,
|
281
|
+
"reviewable_type": "Product"
|
282
|
+
}
|
283
|
+
}'
|
284
|
+
|
285
|
+
# Create a review for an agency
|
286
|
+
curl -X POST http://localhost:3000/api/v1/reviews \
|
287
|
+
-H "Authorization: Bearer $TOKEN" \
|
288
|
+
-H "Content-Type: application/json" \
|
289
|
+
-d '{
|
290
|
+
"data": {
|
291
|
+
"rating": 4,
|
292
|
+
"comment": "Good service!",
|
293
|
+
"reviewable_id": 1,
|
294
|
+
"reviewable_type": "Agency"
|
295
|
+
}
|
296
|
+
}'
|
297
|
+
```
|
298
|
+
|
299
|
+
### Development Tips
|
300
|
+
|
301
|
+
1. **Seed Data**: Run `rails db:seed` to populate with realistic test data
|
302
|
+
2. **Test User**: Default login is `test@example.com` / `password123`
|
303
|
+
3. **Admin User**: Admin login is `admin@example.com` / `password123`
|
304
|
+
4. **Multi-tenancy**: All resources are scoped to organizations automatically
|
305
|
+
5. **Error Handling**: All endpoints return consistent error formats
|
306
|
+
6. **Validation**: Try invalid data to see validation error responses
|
307
|
+
|
73
308
|
### Generate Controllers for Existing Models
|
74
309
|
|
75
310
|
```bash
|
@@ -48,6 +48,11 @@ module PropelApi
|
|
48
48
|
type: :boolean,
|
49
49
|
default: false,
|
50
50
|
desc: "Include usage comments in generated controller"
|
51
|
+
|
52
|
+
class_option :parents,
|
53
|
+
type: :hash,
|
54
|
+
default: {},
|
55
|
+
desc: "Specify parent types for polymorphic associations (e.g., --parents commentable:Post,Photo,Video)"
|
51
56
|
|
52
57
|
def validate_model_exists
|
53
58
|
# Ensure attributes are parsed before validation
|
@@ -64,6 +69,9 @@ module PropelApi
|
|
64
69
|
if !options[:all_attributes] && (@attributes.nil? || @attributes.empty?) && model_file_exists
|
65
70
|
show_auto_introspection_warning
|
66
71
|
end
|
72
|
+
# Process polymorphic parent information if provided
|
73
|
+
process_polymorphic_parents if options[:parents].present?
|
74
|
+
|
67
75
|
# Validate attributes if not using introspection
|
68
76
|
validate_attributes_exist unless should_auto_introspect?
|
69
77
|
end
|
@@ -110,6 +118,24 @@ module PropelApi
|
|
110
118
|
|
111
119
|
private
|
112
120
|
|
121
|
+
def process_polymorphic_parents
|
122
|
+
# Convert _type attributes to polymorphic associations for template processing
|
123
|
+
options[:parents].each do |field_name, parent_list|
|
124
|
+
# Check if we have the corresponding _id and _type attributes
|
125
|
+
type_attr = @attributes.find { |attr| attr.name == "#{field_name}_type" }
|
126
|
+
id_attr = @attributes.find { |attr| attr.name == "#{field_name}_id" }
|
127
|
+
|
128
|
+
if type_attr && id_attr
|
129
|
+
# Add a mock polymorphic attribute to @attributes for template processing
|
130
|
+
@attributes << OpenStruct.new(
|
131
|
+
name: field_name,
|
132
|
+
type: :references,
|
133
|
+
polymorphic?: true
|
134
|
+
)
|
135
|
+
end
|
136
|
+
end
|
137
|
+
end
|
138
|
+
|
113
139
|
def route_name
|
114
140
|
file_name.pluralize
|
115
141
|
end
|
@@ -93,7 +93,7 @@ module PropelApi
|
|
93
93
|
attributes << attr_data
|
94
94
|
end
|
95
95
|
end
|
96
|
-
|
96
|
+
|
97
97
|
# Look for basic validations that might indicate attributes
|
98
98
|
# Exclude association names (they're already handled above as foreign keys)
|
99
99
|
# NOTE: Only add validated attributes if they weren't already detected by schema introspection
|
@@ -514,5 +514,101 @@ module PropelApi
|
|
514
514
|
|
515
515
|
content
|
516
516
|
end
|
517
|
+
|
518
|
+
# Helper methods for templates to detect tenancy attributes
|
519
|
+
# These are shared between ResourceGenerator and ControllerGenerator
|
520
|
+
def has_organization_reference?
|
521
|
+
return false unless defined?(@attributes) && @attributes
|
522
|
+
@attributes.any? { |attr| attr.name == 'organization' && attr.type == :references }
|
523
|
+
end
|
524
|
+
|
525
|
+
def has_agency_reference?
|
526
|
+
return false unless defined?(@attributes) && @attributes
|
527
|
+
@attributes.any? { |attr| attr.name == 'agency' && attr.type == :references }
|
528
|
+
end
|
529
|
+
|
530
|
+
def has_user_reference?
|
531
|
+
return false unless defined?(@attributes) && @attributes
|
532
|
+
@attributes.any? { |attr| (attr.name == 'user' && attr.type == :references) || attr.name == 'user_id' }
|
533
|
+
end
|
534
|
+
|
535
|
+
# Polymorphic associations helper methods
|
536
|
+
def polymorphic_parent_types
|
537
|
+
@polymorphic_parent_types ||= parse_polymorphic_parent_types
|
538
|
+
end
|
539
|
+
|
540
|
+
def polymorphic_associations
|
541
|
+
return [] unless defined?(@attributes) && @attributes
|
542
|
+
|
543
|
+
@polymorphic_associations ||= begin
|
544
|
+
polymorphic_attrs = @attributes.select { |attr| attr.type == :references && attr.respond_to?(:polymorphic?) && attr.polymorphic? }
|
545
|
+
|
546
|
+
polymorphic_attrs.map do |attr|
|
547
|
+
parent_types = polymorphic_parent_types[attr.name.to_s] || discover_available_models.first(1)
|
548
|
+
|
549
|
+
# Create one association entry per polymorphic field with all parent types
|
550
|
+
{
|
551
|
+
field_name: attr.name,
|
552
|
+
id_field: "#{attr.name}_id",
|
553
|
+
type_field: "#{attr.name}_type",
|
554
|
+
parent_types: parent_types,
|
555
|
+
# For fixture generation, we'll use the first parent type for fixture "one", second for "two", etc.
|
556
|
+
primary_parent_type: parent_types.first,
|
557
|
+
primary_parent_table: parent_types.first.underscore.pluralize
|
558
|
+
}
|
559
|
+
end
|
560
|
+
end
|
561
|
+
end
|
562
|
+
|
563
|
+
# Helper method for fixture generation to get the appropriate parent type for each fixture
|
564
|
+
def polymorphic_parent_for_fixture(field_name, fixture_index)
|
565
|
+
poly_assoc = polymorphic_associations.find { |assoc| assoc[:field_name].to_s == field_name.to_s }
|
566
|
+
return nil unless poly_assoc
|
567
|
+
|
568
|
+
parent_types = poly_assoc[:parent_types]
|
569
|
+
parent_type = parent_types[fixture_index % parent_types.length] || parent_types.first
|
570
|
+
|
571
|
+
# Determine the fixture name based on parent type and fixture index
|
572
|
+
fixture_name = case parent_type.underscore
|
573
|
+
when 'agency'
|
574
|
+
['marketing_agency', 'tech_agency', 'sales_agency'][fixture_index] || 'marketing_agency'
|
575
|
+
else
|
576
|
+
['one', 'two', 'three'][fixture_index] || 'one'
|
577
|
+
end
|
578
|
+
|
579
|
+
{
|
580
|
+
id_field: poly_assoc[:id_field],
|
581
|
+
type_field: poly_assoc[:type_field],
|
582
|
+
parent_type: parent_type,
|
583
|
+
parent_table: parent_type.underscore.pluralize,
|
584
|
+
fixture_name: fixture_name
|
585
|
+
}
|
586
|
+
end
|
587
|
+
|
588
|
+
private
|
589
|
+
|
590
|
+
def parse_polymorphic_parent_types
|
591
|
+
return {} unless defined?(options) && options[:parents]
|
592
|
+
|
593
|
+
parsed_types = {}
|
594
|
+
options[:parents].each do |field_name, parent_list|
|
595
|
+
parsed_types[field_name] = parent_list.split(',').map(&:strip).map(&:camelize)
|
596
|
+
end
|
597
|
+
parsed_types
|
598
|
+
end
|
599
|
+
|
600
|
+
def discover_available_models
|
601
|
+
# Auto-discover available models from app/models directory
|
602
|
+
models_dir = File.join(destination_root, 'app/models')
|
603
|
+
return ['Post'] unless File.directory?(models_dir) # Fallback
|
604
|
+
|
605
|
+
model_files = Dir[File.join(models_dir, '*.rb')]
|
606
|
+
model_files.map do |file|
|
607
|
+
File.basename(file, '.rb').camelize
|
608
|
+
end.reject do |model|
|
609
|
+
# Skip common non-domain models
|
610
|
+
%w[ApplicationRecord Concerns].include?(model)
|
611
|
+
end.sort
|
612
|
+
end
|
517
613
|
end
|
518
614
|
end
|
@@ -106,20 +106,13 @@ class RelationshipInferrer
|
|
106
106
|
end
|
107
107
|
|
108
108
|
def polymorphic_belongs_to(attribute)
|
109
|
-
#
|
110
|
-
|
111
|
-
|
112
|
-
base_name = attribute.name.to_s.gsub(/_parent$/, '')
|
113
|
-
elsif attribute.name.to_s.end_with?('able')
|
114
|
-
# commentable -> commentable
|
115
|
-
base_name = attribute.name.to_s
|
116
|
-
else
|
117
|
-
base_name = attribute.name.to_s
|
118
|
-
end
|
109
|
+
# Keep the full attribute name for polymorphic associations
|
110
|
+
# Don't strip the '_parent' suffix - it's needed to match the schema columns
|
111
|
+
association_name = attribute.name.to_s
|
119
112
|
|
120
113
|
# Polymorphic associations default to required (Rails convention)
|
121
114
|
# Add 'optional: true' manually if optional behavior is needed
|
122
|
-
"belongs_to :#{
|
115
|
+
"belongs_to :#{association_name}, polymorphic: true"
|
123
116
|
end
|
124
117
|
|
125
118
|
|
@@ -31,6 +31,12 @@ module PropelApi
|
|
31
31
|
else
|
32
32
|
say "Installing API controller with #{@adapter} adapter", :green
|
33
33
|
say "Using namespace: #{namespace_display} version: #{version_display}", :blue
|
34
|
+
|
35
|
+
# Create Api::BaseController first
|
36
|
+
create_api_base_controller
|
37
|
+
|
38
|
+
# Optionally enhance CSRF error messages (non-breaking)
|
39
|
+
add_csrf_error_handling
|
34
40
|
end
|
35
41
|
|
36
42
|
case @adapter
|
@@ -107,6 +113,37 @@ module PropelApi
|
|
107
113
|
|
108
114
|
private
|
109
115
|
|
116
|
+
def create_api_base_controller
|
117
|
+
template "controllers/api_base_controller.rb", "app/controllers/api/base_controller.rb"
|
118
|
+
say "Created Api::BaseController for CSRF-free API endpoints", :green
|
119
|
+
end
|
120
|
+
|
121
|
+
def add_csrf_error_handling
|
122
|
+
# Copy the error handler
|
123
|
+
template "errors/propel_api_csrf_error.rb", "app/errors/propel_api_csrf_error.rb"
|
124
|
+
|
125
|
+
# Inject rescue_from into ApplicationController
|
126
|
+
inject_into_class "app/controllers/application_controller.rb", ApplicationController, <<-RUBY
|
127
|
+
# Enhanced CSRF error handling for JSON requests - added by PropelAPI
|
128
|
+
rescue_from ActionController::InvalidAuthenticityToken, with: :handle_propel_csrf_error
|
129
|
+
|
130
|
+
private
|
131
|
+
|
132
|
+
def handle_propel_csrf_error
|
133
|
+
if request.format.json? || request.content_type&.include?('application/json')
|
134
|
+
PropelApiCsrfError.handle_csrf_error_for_json(self)
|
135
|
+
else
|
136
|
+
raise ActionController::InvalidAuthenticityToken
|
137
|
+
end
|
138
|
+
end
|
139
|
+
RUBY
|
140
|
+
|
141
|
+
say "Enhanced ApplicationController with helpful API guidance", :green
|
142
|
+
rescue => e
|
143
|
+
say "Could not inject CSRF error handling into ApplicationController: #{e.message}", :yellow
|
144
|
+
say "You can manually add the rescue_from handler if desired", :blue
|
145
|
+
end
|
146
|
+
|
110
147
|
def copy_propel_facets_controller
|
111
148
|
template "controllers/api_controller_propel_facets.rb", api_controller_path
|
112
149
|
copy_example_controller
|
@@ -140,8 +177,8 @@ module PropelApi
|
|
140
177
|
|
141
178
|
def add_propel_facets_gems
|
142
179
|
add_gem_if_missing 'faker', '~> 3.5', 'Realistic seed data generation'
|
143
|
-
add_gem_if_missing 'pagy', '~> 9.
|
144
|
-
add_gem_if_missing 'has_scope', '~> 0.8.
|
180
|
+
add_gem_if_missing 'pagy', '~> 9.4', 'Pagination for Propel Facets API'
|
181
|
+
add_gem_if_missing 'has_scope', '~> 0.8.2', 'Scope filtering for Propel Facets API'
|
145
182
|
add_gem_if_missing 'ransack', '~> 4.0', 'Advanced search for Propel Facets API'
|
146
183
|
|
147
184
|
say "Don't forget to run: bundle install", :yellow
|