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.
Files changed (25) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +97 -0
  3. data/README.md +239 -4
  4. data/lib/generators/propel_api/controller/controller_generator.rb +26 -0
  5. data/lib/generators/propel_api/core/named_base.rb +97 -1
  6. data/lib/generators/propel_api/core/relationship_inferrer.rb +4 -11
  7. data/lib/generators/propel_api/install/install_generator.rb +39 -2
  8. data/lib/generators/propel_api/resource/resource_generator.rb +205 -63
  9. data/lib/generators/propel_api/templates/config/propel_api.rb.tt +26 -1
  10. data/lib/generators/propel_api/templates/controllers/api_base_controller.rb +75 -0
  11. data/lib/generators/propel_api/templates/controllers/api_controller_graphiti.rb +3 -3
  12. data/lib/generators/propel_api/templates/controllers/api_controller_propel_facets.rb +22 -12
  13. data/lib/generators/propel_api/templates/controllers/example_controller.rb.tt +2 -2
  14. data/lib/generators/propel_api/templates/errors/propel_api_csrf_error.rb +19 -0
  15. data/lib/generators/propel_api/templates/scaffold/facet_controller_template.rb.tt +41 -8
  16. data/lib/generators/propel_api/templates/scaffold/facet_model_template.rb.tt +43 -10
  17. data/lib/generators/propel_api/templates/scaffold/graphiti_controller_template.rb.tt +1 -1
  18. data/lib/generators/propel_api/templates/scaffold/graphiti_resource_template.rb.tt +2 -2
  19. data/lib/generators/propel_api/templates/seeds/seeds_template.rb.tt +65 -17
  20. data/lib/generators/propel_api/templates/tests/controller_test_template.rb.tt +40 -6
  21. data/lib/generators/propel_api/templates/tests/fixtures_template.yml.tt +61 -18
  22. data/lib/generators/propel_api/templates/tests/integration_test_template.rb.tt +154 -42
  23. data/lib/generators/propel_api/templates/tests/model_test_template.rb.tt +20 -0
  24. data/lib/propel_api.rb +1 -1
  25. metadata +24 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 8fb51b38b12561c709712a339a39cf3639cd1e8a16149f72c00f1566ee37bdcf
4
- data.tar.gz: a90352463962e6385b895cf339195b6860f0d5e98ccf1c4e6e3237957f6895cf
3
+ metadata.gz: 8891f7c2c3ace04fe703d6613d1a2595e19ed7ecaf89ecf960c3000bd1b00e0d
4
+ data.tar.gz: c51158c13407e9b91b01eb10d27b8bb89f5c80517855737a684e6f1fba88eac3
5
5
  SHA512:
6
- metadata.gz: a2d01e1bcc8f7a749e8de4101d6f7be9dc5c4a7b2b0f2b7d5dc78e630dbba0102cedee82ff957cd210bde487a66c0b936a546b50c75f38e45db84dabcc74e6d0
7
- data.tar.gz: 94dad0a33d4fd5af9327d42b21faa0a69bcdd7a018d914293db3643e68496b4b4f979d99cb14f8683b0df3040f6f15b55b6c4ff47c72015da9eaf6d336d5fb83
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
- # Extract the base name for polymorphic association
110
- if attribute.name.to_s.end_with?('_parent')
111
- # resource_parent -> resource
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 :#{base_name}, polymorphic: true"
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.0', 'Pagination for Propel Facets API'
144
- add_gem_if_missing 'has_scope', '~> 0.8.0', 'Scope filtering for Propel Facets API'
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