Rails Code Generation Standards
Practical standards for AI-assisted Rails development from Evil Martians. Generated code should be so simple and clear that reading it feels like reading well-written documentation.
Core Principles
- •Follow Rails conventions - Leverage the framework, don't fight it
- •Use domain language - Name models after business concepts (Participant vs User, Cloud vs GeneratedImage)
- •Keep logic at appropriate layers - Models for business logic, controllers for HTTP, jobs for async
- •Write readable code - Code should be self-documenting without comments
- •Normalize data properly - One concern per table, use foreign keys and constraints
Quick Reference
File Structure
app/models/ # Including namespaced classes (Cloud::CardGenerator) app/controllers/ # Namespaced for auth scoping (Participant::CloudsController) app/jobs/ # Background work with ActiveJob app/forms/ # Multi-model operations only app/policies/ # Complex authorization (ActionPolicy) app/views/ # ERB + ViewComponent app/frontend/ # Stimulus controllers, styles config/configs/ # Anyway Config classes
Critical: No app/services/, app/contexts/, or app/operations/ folders. Extract complex operations to namespaced model classes.
Model Organization Order
- •Gems/DSL extensions
- •Associations (with
counter_cache: true) - •Enums (for state machines)
- •Normalizations (Rails 7.1+)
- •Validations
- •Scopes
- •Callbacks
- •Delegations
- •Public methods
- •Private methods
Controller Target
5-10 lines per action. No business logic. Guard clauses for early returns.
def create return head :forbidden unless current_participant.can_create_cloud? @cloud = current_participant.clouds.create!(cloud_params) CloudProcessingJob.perform_later(@cloud) redirect_to @cloud end
Technology Stack
Required gems: Rails, Puma, Propshaft, PostgreSQL, Hotwire (Turbo + Stimulus), ViewComponent, Vite Rails, SolidQueue, ActionPolicy, Anyway Config, RSpec + FactoryBot, Standard, Nanoid + FriendlyID, HTTParty
Forbidden: Devise, CanCanCan, ActiveAdmin, service object gems, state machine gems, dry-types/Virtus
Building Block References
Consult these reference files for detailed patterns:
| Reference | Content |
|---|---|
references/stack.md | Complete gem list, file structure, forbidden patterns |
references/models.md | Model organization, enums, validations, extraction patterns |
references/controllers.md | Thin controllers, namespacing, guard clauses |
references/database.md | Schema design, constraints, indexes, migrations |
references/jobs.md | ActiveJob::Continuable, workflow orchestration |
references/views.md | Hotwire, ViewComponent, Stimulus patterns |
references/forms-queries.md | Form objects, query objects, when to use |
references/testing.md | RSpec organization, what to test |
references/configuration.md | Anyway Config patterns, environment variables |
references/anti-patterns.md | Common mistakes with alternatives, deployment checklist |
Decision Flowchart
Where does this logic belong?
- •Single model operation → Model method
- •Multi-model transaction → Form object
- •External API call → Namespaced model class (e.g.,
Cloud::CardGenerator) - •Async work → Job (orchestrates, doesn't execute)
- •Complex query → Query object or scope
- •Authorization → Policy (ActionPolicy)
- •Configuration → Anyway Config class
When to extract from model?
- •Method > 15 lines → Extract to namespaced class
- •Calls external API → Extract to namespaced class
- •Shared across models → Extract to concern or module
Code Generation Checklist
Before generating Rails code, verify:
- • Models named after business domain concepts?
- • Model follows organization order?
- • States implemented as enums?
- • Controllers under 10 lines per action?
- • Complex logic extracted appropriately?
- • Database normalized with FK constraints?
- • Counter caches on has_many associations?
- • Workflows orchestrated through jobs?
- • Configuration via Anyway Config (not ENV)?
- • Tests organized by type (model/request/system)?
Usage
When generating Rails code:
- •Check
references/stack.mdto verify gem choices - •Follow patterns in the relevant building block reference
- •Consult
references/anti-patterns.mdto avoid common mistakes - •Run through the checklist above before finalizing
For specific patterns, read the appropriate reference file based on what component is being generated.