Write Ruby and Rails code in DHH's distinctive 37signals style. Use this skill when writing Ruby code, Rails applications, creating models, controllers, or any Ruby file. Triggers on Ruby/Rails code generation, refactoring requests, or when the user mentions DHH, 37signals, Basecamp, HEY, Fizzy, or Campfire style.
Write Ruby and Rails code in DHH's distinctive 37signals style. Use this skill when writing Ruby code, Rails applications, creating models, controllers, or any Ruby file. Triggers on Ruby/Rails code generation, refactoring requests, or when the user mentions DHH, 37signals, Basecamp, HEY, Fizzy, or Campfire style.
DHH Ruby/Rails Style Guide
Write Ruby and Rails code following DHH's philosophy: clarity over cleverness, convention over configuration, developer happiness above all.
Use Current for request context, never pass current_user everywhere:
classCurrent < ActiveSupport::CurrentAttributes
attribute :user, :sessionend# Usage anywhere in appCurrent.user.can_administer?(@message)
Ruby Syntax Preferences
DHH-specific style (for general Ruby style, see ruby-coder skill):
# Symbol arrays with spaces inside brackets
before_action :set_message, only: %i[ show edit update destroy ]
# Expression-less case for cleaner conditionalscasewhen params[:before].present?
@room.messages.page_before(params[:before])
when params[:after].present?
@room.messages.page_after(params[:after])
else@room.messages.last_page
end
Query Optimization
Prefer pluck(:name) over map(&:name) and messages.count over messages.to_a.count -- push work to the database.
StringInquirer for Predicates
Use .inquiry on string enums for readable conditionals:
No index or show with ID needed—resource is implicit from Current.user.
Compute at Write Time
Perform data manipulation during saves, not during presentation:
# WRONG: Compute on readdefdisplay_name"#{first_name}#{last_name}".titleize
end# CORRECT: Compute on write
before_save :set_display_nameprivatedefset_display_nameself.display_name = "#{first_name}#{last_name}".titleize
end
Benefits: enables pagination, caching, and reduces view complexity.
Delegate for Lazy Loading
Use delegate to enable lazy loading through associations:
classMessage < ApplicationRecord
belongs_to :session
delegate :user, to::sessionend# Lazy loads user through session
message.user
Naming Conventions
Element
Convention
Example
Setter methods
set_ prefix
set_message, set_room
Parameter methods
{model}_params
message_params
Association names
Semantic, not generic
creator not user
Scopes
Chainable, descriptive
with_creator, page_before
Predicates
End with ?
direct?, can_administer?
Current user resources
My:: namespace
My::ProfilesController
Hotwire/Turbo Patterns
Broadcasting is model responsibility:
# In modeldefbroadcast_create
broadcast_append_to room, :messages, target:"messages"end
For detailed Hotwire patterns, use hotwire-coder skill.
Error Handling
Rescue specific exceptions, fail fast with bang methods: