dhh-rails-style
This skill should be used when writing Ruby and Rails code in DHH's distinctive 37signals style. It applies when writing Ruby code, Rails applications, creating models, controllers, or any Ruby file. Triggers on Ruby/Rails code generation, refactoring requests, code review, or when the user mentions DHH, 37signals, Basecamp, HEY, or Campfire style. Embodies REST purity, fat models, thin controllers, Current attributes, Hotwire patterns, and the "clarity over cleverness" philosophy.
When & Why to Use This Skill
This Claude skill streamlines Ruby on Rails development by enforcing the distinctive 37signals/DHH coding style. It provides expert guidance on building 'The Rails Way,' emphasizing RESTful architecture, fat models, thin controllers, and Hotwire patterns. By prioritizing clarity over cleverness and minimizing external dependencies, it helps developers build maintainable, production-ready applications consistent with the philosophies behind Basecamp and HEY.
Use Cases
- 1. New Feature Development: Generating Rails models, controllers, and views that adhere to strict RESTful principles and 37signals conventions.
- 2. Code Refactoring: Transforming complex service objects or custom controller actions into clean, resource-oriented code and domain-rich models.
- 3. Modern Frontend Integration: Implementing interactive UI components using Hotwire (Turbo and Stimulus) instead of heavy JavaScript frameworks.
- 4. Automated Code Review: Auditing existing Ruby/Rails codebases to ensure alignment with DHH’s 'clarity over cleverness' philosophy and dependency-light approach.
- 5. Testing Strategy: Writing clean, efficient tests using Minitest and fixtures to ensure high code quality without the overhead of complex testing DSLs.
| name | dhh-rails-style |
|---|---|
| description | This skill should be used when writing Ruby and Rails code in DHH's distinctive 37signals style. It applies when writing Ruby code, Rails applications, creating models, controllers, or any Ruby file. Triggers on Ruby/Rails code generation, refactoring requests, code review, or when the user mentions DHH, 37signals, Basecamp, HEY, or Campfire style. Embodies REST purity, fat models, thin controllers, Current attributes, Hotwire patterns, and the "clarity over cleverness" 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
- 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.
| Response | Reference to Read |
|---|---|
| 1, controller | controllers.md |
| 2, model | models.md |
| 3, view, frontend, turbo, stimulus, css | frontend.md |
| 4, architecture, routing, auth, job, cache | architecture.md |
| 5, test, testing, minitest, fixture | testing.md |
| 6, gem, dependency, library | 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.
## Naming ConventionsVerbs: 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,latestpreloaded(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
## 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 |
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