PropelApi
A comprehensive Rails generator that creates complete API resources with models, controllers, tests, and realistic seed data. Supports both PropelFacets (JSON Facet) and Graphiti serialization engines with fixed route insertion, proper indentation, and comprehensive dynamic filtering system.
๐ NEW in v0.3.3: Dynamic Filtering System
PropelApi now includes a complete automatic URL query string filtering and scoping system using the has_scope gem. This provides powerful, database-agnostic filtering across all data types with zero configuration required.
Quick Filtering Examples
# String filtering
GET /api/v1/meetings?title_contains=Project&status_in=active,pending
# Numeric filtering
GET /api/v1/meetings?max_participants_gte=50&max_participants_lte=200
# Boolean filtering
GET /api/v1/meetings?recording_enabled_eq=true&ai_research_enabled_eq=false
# DateTime filtering
GET /api/v1/meetings?start_time_after=2024-01-01T00:00:00Z&start_time_before=2024-12-31T23:59:59Z
# Range filtering
GET /api/v1/meetings?max_participants_range=150,350
# Combined filtering with sorting and pagination
GET /api/v1/meetings?title_contains=Project&max_participants_gte=50&order_by=start_time&page=1&limit=20
Supported Filter Operators
| Data Type | Operators | Examples |
|---|---|---|
| String | _eq, _contains, _starts_with, _ends_with, _in |
name_eq=Acme, title_contains=Project |
| Numeric | _eq, _gt, _lt, _gte, _lte, _range, _in |
max_participants_gte=50, price_range=100,500 |
| Boolean | _eq (supports true/false, 1/0, yes/no, on/off) |
recording_enabled_eq=true |
| DateTime | _before, _after, _year, _month, _day, _date |
start_time_after=2024-01-01, created_at_year=2024 |
| Date | Same as DateTime | event_date_after=2024-01-01 |
| Time | Same as DateTime | start_time_hour=14 |
Automatic Features
- Zero Configuration: Filtering works automatically for all generated resources
- Database Agnostic: Works with SQLite, PostgreSQL, and MySQL
- Security Built-in: SQL injection protection and input validation
- Multi-tenancy Ready: Automatic organization scoping
- Performance Optimized: Efficient queries with proper indexing support
Installation
PropelApi 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.
Step 1: Add to Gemfile as a Path Gem
# In your Gemfile
gem 'propel_api', path: 'propel_api'
Step 2: Bundle Install
bundle install
Step 3: Unpack the Generator (Optional)
If you want to customize the generator templates:
rails generate propel_api:unpack
This extracts the generator into lib/generators/propel_api/ for customization.
Step 4: Install PropelApi
rails generate propel_api:install --adapter=propel_facets
# or
rails generate propel_api:install --adapter=graphiti
This installs the API controller base class with your chosen serialization adapter.
Step 5: Remove Gem Dependency (Optional)
After installation, you can remove the gem from your Gemfile. All functionality remains in your application.
Usage
Generate Complete API Resources
# Basic resource with PropelFacets
rails generate propel_api:resource User name:string email:string role:string
# Resource with associations
rails generate propel_api:resource Article title:string content:text user:references category:references
# ๐ NEW: Polymorphic associations (v0.3.0) - REQUIRES --parents flag
rails generate propel_api:resource Comment content:text commentable:references{polymorphic} --parents commentable:Post,Video,Product
# Polymorphic with tenancy
rails generate propel_api:resource Review rating:integer comment:text review_parent:polymorphic --parents review_parent:Product,Agency
# With Graphiti adapter
rails generate propel_api Product name:string price:decimal --adapter=graphiti
This generates:
- Model with associations and facets/resources
- Migration with proper constraints
- Controller with full CRUD operations
- Routes with proper namespacing and correct indentation
- Tests (model, controller, integration)
- Fixtures with realistic test data
- Seeds with Faker-generated sample data
๐ Polymorphic Association Support (v0.3.0)
PropelApi now provides comprehensive support for polymorphic associations with automatic test generation and intelligent fixture management.
Quick Start with Polymorphic Resources
# Generate a Comment that can belong to Posts, Videos, or Products
rails generate propel_api:resource Comment body:text commentable:references{polymorphic} --parents commentable:Post,Video,Product
# Generate a Review with full tenancy support
rails generate propel_api:resource Review rating:integer comment:text review_parent:references{polymorphic} --parents review_parent:Product,Agency
Key Features
โจ Simple, Intuitive Syntax
- Additional support
field_name:polymorphicinstead of Rails' verbosefield_name:references{polymorphic} - No need for complex quote escaping or nested syntax
๐ฏ Required Parent Specification
--parents field_name:Parent1,Parent2,Parent3defines valid parent models (REQUIRED for polymorphic associations)- Field name must match the polymorphic association name (e.g.,
commentable,schedule_parent) - Automatically generates varied test data using different parent types
- Generator will block with confirmation if --parents is not provided
๐งช Complete Test Coverage
- Model Tests: Proper polymorphic association validation and parent type checking
- Controller Tests: Automatic inclusion of both
_idand_typeparameters - Integration Tests: Full API workflow testing with polymorphic data
- Fixtures: Uses Rails' clean
fixture_name (ModelName)syntax
๐ง Generated Code Quality
# Generated Model
class Comment < ApplicationRecord
belongs_to :commentable, polymorphic: true
# ... other associations and validations
end
# Generated Migration
def change
create_table :comments do |t|
t.text :body
t.references :commentable, polymorphic: true, null: false
# ... other fields
end
end
# Generated Fixtures (clean Rails syntax)
one:
commentable: one (Post)
body: "Great post!"
two:
commentable: featured_video (Video)
body: "Amazing video content!"
๐ API-Ready Controllers
Controllers automatically include proper parameter handling:
class Api::V1::CommentsController < Api::V1::ApiController
permitted_params :body, :commentable_id, :commentable_type
end
--parents Flag Usage Guide
โ ๏ธ IMPORTANT: The --parents flag requires specific syntax to work correctly.
โ Correct Syntax:
# Single polymorphic field
--parents field_name:Parent1,Parent2,Parent3
# Real examples:
--parents commentable:Post,Photo,Video
--parents schedule_parent:User,Room,MeetingLink
--parents review_parent:Product,Agency
# Multiple polymorphic fields
--parents commentable:Post,Photo schedule_parent:User,Room
โ Incorrect Syntax (Will Fail):
# Missing field name (Thor can't parse this)
--parents Post,Photo,Video
# Array brackets (not supported)
--parents commentable:[Post,Photo,Video]
# JSON-like syntax (not supported)
--parents "{commentable: [Post,Photo,Video]}"
๐ Key Rules:
- Always include field name:
field_name:Parent1,Parent2 - Field name must match polymorphic association: If your field is
commentable:polymorphic, use--parents commentable:... - Use commas to separate parent types:
Post,Photo,VideonotPost Photo Video - Whitespace is automatically cleaned:
Post, Photo, Videoworks fine
Complete Usage Examples
# Standard resource with polymorphic association
rails generate propel_api:resource Comment content:text commentable:polymorphic --parents commentable:Post,Photo,Video
# Multi-tenant polymorphic resource
rails generate propel_api:resource Review rating:integer organization:references agency:references review_parent:polymorphic --parents review_parent:Product,Agency,User
# Schedule system with polymorphic parent
rails generate propel_api:resource Schedule name:string start_time:datetime schedule_parent:polymorphic --parents schedule_parent:User,Room,MeetingLink
# Multiple polymorphic associations in one resource
rails generate propel_api:resource Attachment file_name:string attachable:polymorphic owner:polymorphic --parents attachable:Post,Comment,Email owner:User,Agency
Breaking Changes from v0.2.x
โ ๏ธ Migration Required: The polymorphic syntax and test generation has been completely rewritten for better reliability and Rails compatibility.
- Old:
rails generate propel_api:resource Comment body:text commentable:references{polymorphic} - New:
rails generate propel_api:resource Comment body:text commentable:polymorphic --parents commentable:Post,Video
The new approach provides:
- More reliable test generation
- Better fixture management
- Cleaner, more maintainable code
- Full Rails compatibility
๐ API Explorer for Development
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.
Quick Start with the Test API
# Navigate to the test application
cd test/dummy
# Set up the database
rails db:setup
# Start the development server
rails server
# Your API is now running at http://localhost:3000
Available API Endpoints
The dummy app provides these fully functional endpoints:
Authentication
POST /api/v1/signup- User registrationPOST /api/v1/login- User authenticationGET /api/v1/me- Current user infoDELETE /api/v1/logout- LogoutPOST /api/v1/reset- Password reset requestPATCH /api/v1/reset- Password reset update
Core Resources
GET|POST /api/v1/users- User managementGET|POST /api/v1/organizations- Organization managementGET|POST|PATCH|DELETE /api/v1/products- Product CRUDGET|POST|PATCH|DELETE /api/v1/comments- Comment CRUDGET|POST|PATCH|DELETE /api/v1/attachments- File attachmentsGET|POST|PATCH|DELETE /api/v1/reviews- Reviews (polymorphic!)
Setting Up API Explorer Tools
Option 1: Postman Collection
Create a Postman collection with these base settings:
{
"info": {
"name": "PropelApi Development",
"schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json"
},
"variable": [
{
"key": "base_url",
"value": "http://localhost:3000/api/v1",
"type": "string"
},
{
"key": "auth_token",
"value": "",
"type": "string"
}
]
}
Option 2: Insomnia Workspace
- Create a new workspace in Insomnia
- Set base URL:
http://localhost:3000/api/v1 - Create environment variables:
base_url:http://localhost:3000/api/v1auth_token: (will be populated after login)
Option 3: cURL Scripts
# Login and get token
TOKEN=$(curl -s -X POST http://localhost:3000/api/v1/login \
-H "Content-Type: application/json" \
-d '{"data": {"email_address": "[email protected]", "password": "password123"}}' \
| jq -r '.token')
# Use token for authenticated requests
curl -H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
http://localhost:3000/api/v1/me
API Response Format
All PropelApi endpoints follow consistent JSON:API-inspired formatting:
{
"data": {
"id": 1,
"name": "Example Product",
"price": 99.99,
"organization": {
"id": 1,
"name": "Test Organization"
}
},
"meta": {
"total": 1,
"page": 1,
"limit": 25
}
}
Testing Polymorphic Associations
The Reviews resource demonstrates polymorphic associations:
# Create a review for a product
curl -X POST http://localhost:3000/api/v1/reviews \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"data": {
"rating": 5,
"comment": "Great product!",
"reviewable_id": 1,
"reviewable_type": "Product"
}
}'
# Create a review for an agency
curl -X POST http://localhost:3000/api/v1/reviews \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"data": {
"rating": 4,
"comment": "Good service!",
"reviewable_id": 1,
"reviewable_type": "Agency"
}
}'
Development Tips
- Seed Data: Run
rails db:seedto populate with realistic test data - Test User: Default login is
[email protected]/password123 - Admin User: Admin login is
[email protected]/password123 - Multi-tenancy: All resources are scoped to organizations automatically
- Error Handling: All endpoints return consistent error formats
- Validation: Try invalid data to see validation error responses
Generate Controllers for Existing Models
# Auto-detect model attributes (with warning)
rails generate propel_api:controller User
# Explicitly auto-detect all attributes
rails generate propel_api:controller User --all-attributes
# Specify specific attributes
rails generate propel_api:controller User name:string email:string
# Custom namespace and version
rails generate propel_api:controller User --namespace=admin_api --version=v2
API Controller Usage
PropelFacets Adapter
class Api::V1::UsersController < Api::V1::ApiController
permitted_params :name, :email, :role
connect_facet :short, actions: [:index]
connect_facet :details, actions: [:show, :create, :update]
end
Graphiti Adapter
class Api::V1::UsersController < Api::V1::ApiController
self.resource = UserResource
end
Configuration Options
Configure PropelApi defaults in config/initializers/propel_api.rb:
PropelApi.configure do |config|
# Default serialization adapter: 'propel_facets' or 'graphiti'
config.adapter = 'propel_facets'
# Default API namespace: 'api', 'admin_api', etc.
config.namespace = 'api'
# Default API version: 'v1', 'v2', etc.
config.version = 'v1'
end
Features
โ Fixed Route Insertion
- Proper indentation - Routes are inserted with correct spacing
- Namespace support - Works with nested namespaces (api/v1)
- No duplicates - Prevents duplicate route insertion
- Correct positioning - Routes inserted in the right location
Automatic Resource Generation
- Smart associations - Automatically infers relationships from field types
- Polymorphic support - Handles
commentable:referencespatterns - Proper constraints - Makes organization required, others optional
- Realistic test data - Uses Faker for meaningful sample data
Dual Serialization Support
- PropelFacets - Flexible JSON views with inheritance and facet system
- Graphiti - JSON:API compliant with automatic resource generation
- Adapter switching - Change serialization strategy per project needs
Complete Test Coverage
- Model tests - Validations, associations, business logic
- Controller tests - CRUD operations, parameter handling
- Integration tests - End-to-end API workflows
- Fixtures - Realistic test data for reliable testing
Production-Ready Features
- Pagination - Built-in with Pagy (PropelFacets) or Graphiti
- Filtering - HasScope integration for PropelFacets
- Authentication - Ready for PropelAuth integration
- Error handling - Proper JSON error responses
Self-Extracting Architecture
PropelApi follows a self-extracting pattern that provides:
- No runtime dependencies - all code lives in your application
- Full control - modify any component after installation
- No black boxes - transparent, readable Rails code
- Easy maintenance - standard Rails patterns throughout
After installation, you can:
- Remove the gem from your Gemfile
- Customize all generated code
- Maintain and extend functionality independently
- Switch between PropelFacets and Graphiti adapters
Advanced Usage
Custom Namespaces and Versions
# Admin API with different namespace
rails generate propel_api:install --namespace=admin_api --version=v2
# No namespace/version
rails generate propel_api:install --namespace=none --version=none
Model Attribute Detection
PropelApi provides intelligent attribute detection with security filtering:
# Manual attributes (no filtering)
rails generate propel_api:controller User name:string email:string
# Auto-detect with explicit flag
rails generate propel_api:controller User --all-attributes
# Auto-detect with warning (when no attributes specified)
rails generate propel_api:controller User
Security Filtering: Sensitive attributes are automatically filtered:
- Passwords, tokens, keys, secrets
- Timestamps and Rails internals
- Large content fields
- Binary data
Customize filtering in config/initializers/propel_api.rb:
PropelApi.attribute_filter.add_sensitive_pattern(/private_.*/)
PropelApi.attribute_filter.add_excluded_pattern(/legacy_.*/)
Relationship Patterns
# Standard belongs_to/has_many
rails generate propel_api Article title:string user:references
# Polymorphic associations (commentable -> Comment belongs_to :commentable, polymorphic: true)
rails generate propel_api Comment content:text commentable:references
# Resource parent pattern (resource_parent -> Attachment belongs_to :resource, polymorphic: true)
rails generate propel_api Attachment name:string resource_parent:references
Route Generation Examples
Nested Namespace (api/v1)
# Input routes.rb:
Rails.application.routes.draw do
namespace :api do
namespace :v1 do
# Add your API routes here
end
end
end
# After: rails generate propel_api:controller User
Rails.application.routes.draw do
namespace :api do
namespace :v1 do
resources :users # โ Correctly indented with 4 spaces
end
end
end
Single Namespace
# After: rails generate propel_api:controller User --namespace=api --version=none
Rails.application.routes.draw do
namespace :api do
resources :users # โ Correctly indented with 2 spaces
end
end
Seed Data Generation
# Generated seeds use Faker for realistic data
User.create!([
{ name: Faker::Name.name, email: Faker::Internet.email, role: 'admin' },
{ name: Faker::Name.name, email: Faker::Internet.email, role: 'user' }
])
Dependencies
PropelFacets Adapter
propel_facets- JSON facet system (install separately)pagy- Paginationhas_scope- Filteringransack- Advanced search
Graphiti Adapter
graphiti- JSON:API resource frameworkgraphiti-rails- Rails integrationvandal_ui- Interactive API documentation
Route Insertion Technical Details
PropelApi includes completely fixed route insertion that handles:
Indentation Rules
- Nested namespaces (api/v1): 4 spaces for resources
- Single namespaces (api): 2 spaces for resources
- Rails route method: Automatically adds 2 spaces to each line
Insertion Logic
- Detects existing namespace structures
- Inserts at correct position (after namespace opening)
- Prevents duplicate routes
- Maintains proper Rails formatting
Error Prevention
- Validates route placement before insertion
- Shows warnings for duplicate routes
- Maintains file structure integrity
Documentation
After installation:
- API examples:
doc/api_controller_example.rb - Configuration:
config/initializers/propel_api.rb - Generated tests show usage patterns
- Seed files demonstrate data creation
Development
# Run generator tests
cd propel_api
bundle exec rake test
# Test route insertion specifically
bundle exec ruby -Ilib:test test/generators/propel_api/route_insertion_test.rb
Contributing
Bug reports and pull requests are welcome on GitHub.
License
The gem is available as open source under the MIT License.