<essential_principles>
Core Philosophy
"The best code is the code you don't write. The second best is the code that's obviously correct."
Vanilla Rails is plenty:
- •Rich domain models over service objects
- •CRUD controllers over custom actions
- •Concerns for horizontal code sharing
- •Records as state instead of boolean columns
- •Database-backed everything (no Redis)
- •Build solutions before reaching for gems
What they deliberately avoid:
- •devise (custom ~150-line auth instead)
- •pundit/cancancan (simple role checks in models)
- •sidekiq (Solid Queue uses database)
- •redis (database for everything)
- •view_component (partials work fine)
- •GraphQL (REST with Turbo sufficient)
- •factory_bot (fixtures are simpler)
- •rspec (Minitest ships with Rails)
- •Tailwind (native CSS with layers)
Development Philosophy:
- •Ship, Validate, Refine - prototype-quality code to production to learn
- •Fix root causes, not symptoms
- •Write-time operations over read-time computations
- •Database constraints over ActiveRecord validations </essential_principles>
- •Controllers - REST mapping, concerns, Turbo responses, API patterns
- •Models - Concerns, state records, callbacks, scopes, POROs
- •Views & Frontend - Turbo, Stimulus, CSS, partials
- •Architecture - Routing, multi-tenancy, authentication, jobs, caching
- •Testing - Minitest, fixtures, integration tests
- •Gems & Dependencies - What to use vs avoid
- •Code Review - Review code against DHH style
- •General Guidance - Philosophy and conventions
Specify a number or describe your task. </intake>
<routing> | Response | Reference to Read | |----------|-------------------| | 1, "controller" | [controllers.md](./references/controllers.md) | | 2, "model" | [models.md](./references/models.md) | | 3, "view", "frontend", "turbo", "stimulus", "css" | [frontend.md](./references/frontend.md) | | 4, "architecture", "routing", "auth", "job", "cache" | [architecture.md](./references/architecture.md) | | 5, "test", "testing", "minitest", "fixture" | [testing.md](./references/testing.md) | | 6, "gem", "dependency", "library" | [gems.md](./references/gems.md) | | 7, "review" | Read all references, then review code | | 8, general task | Read relevant references based on context |After reading relevant references, apply patterns to the user's code. </routing>
<quick_reference>
Naming Conventions
Verbs: card.close, card.gild, board.publish (not set_style methods)
Predicates: card.closed?, card.golden? (derived from presence of related record)
Concerns: Adjectives describing capability (Closeable, Publishable, Watchable)
Controllers: Nouns matching resources (Cards::ClosuresController)
Scopes:
- •
chronologically,reverse_chronologically,alphabetically,latest - •
preloaded(standard eager loading name) - •
indexed_by,sorted_by(parameterized) - •
active,unassigned(business terms, not SQL-ish)
REST Mapping
Instead of custom actions, create new resources:
POST /cards/:id/close → POST /cards/:id/closure DELETE /cards/:id/close → DELETE /cards/:id/closure POST /cards/:id/archive → POST /cards/:id/archival
Ruby Syntax Preferences
# Symbol arrays with spaces inside brackets
before_action :set_message, only: %i[ show edit update destroy ]
# Private method indentation
private
def set_message
@message = Message.find(params[:id])
end
# Expression-less case for conditionals
case
when params[:before].present?
messages.page_before(params[:before])
else
messages.last_page
end
# Bang methods for fail-fast
@message = Message.create!(params)
# Ternaries for simple conditionals
@room.direct? ? @room.users : @message.mentionees
Key Patterns
State as Records:
Card.joins(:closure) # closed cards Card.where.missing(:closure) # open cards
Current Attributes:
belongs_to :creator, default: -> { Current.user }
Authorization on Models:
class User < ApplicationRecord
def can_administer?(message)
message.creator == self || admin?
end
end
</quick_reference>
<reference_index>
Domain Knowledge
All detailed patterns in references/:
| File | Topics |
|---|---|
| controllers.md | REST mapping, concerns, Turbo responses, API patterns, HTTP caching |
| models.md | Concerns, state records, callbacks, scopes, POROs, authorization, broadcasting |
| frontend.md | Turbo Streams, Stimulus controllers, CSS layers, OKLCH colors, partials |
| architecture.md | Routing, authentication, jobs, Current attributes, caching, database patterns |
| testing.md | Minitest, fixtures, unit/integration/system tests, testing patterns |
| gems.md | What they use vs avoid, decision framework, Gemfile examples |
| </reference_index> |
<success_criteria> Code follows DHH style when:
- •Controllers map to CRUD verbs on resources
- •Models use concerns for horizontal behavior
- •State is tracked via records, not booleans
- •No unnecessary service objects or abstractions
- •Database-backed solutions preferred over external services
- •Tests use Minitest with fixtures
- •Turbo/Stimulus for interactivity (no heavy JS frameworks)
- •Native CSS with modern features (layers, OKLCH, nesting)
- •Authorization logic lives on User model
- •Jobs are shallow wrappers calling model methods </success_criteria>
Important Disclaimers:
- •LLM-generated guide - may contain inaccuracies
- •Code examples from Fizzy are licensed under the O'Saasy License
- •Not affiliated with or endorsed by 37signals