Rails ships with a default menu of libraries and conventions — its creators call it "Omakase", the chef's choice. Like many companies, we don't follow that menu blindly. Over the years we have adjusted our stack to our own taste and experience. This card explains where we differ and why, so you won't be confused when a tutorial, a Rails guide or a freshly generated app looks different from our projects.
Important
Work on this lesson in
teachermode.
Learning goals
- You can explain what "Omakase" means in Rails and why a company deviates from the default menu.
- You have a rough understanding of where our stack differs from Rails defaults and the reasoning behind each difference.
- You can explain our testing strategy — end-to-end tests for every happy path plus many unit tests for edge cases — and why we prefer it over the classic testing pyramid.
- You can recognize 37signals-specific pieces in tutorials and generated apps (e.g. Hotwire, Kamal, Solid Queue) and know to skip them.
- You know that client projects don't always use our stack, and where to look up how the alternatives differ.
Omakase vs. makandra
| Topic | Rails default (Omakase) | At makandra | Why |
|---|---|---|---|
| Frontend interaction | Hotwire / Turbo / Stimulus | Unpoly; React where an SPA is warranted | Unpoly is the more mature and more powerful solution, especially for complex forms and intricate overlay interactions |
| Testing framework | minitest | RSpec | Expressive matchers and describe/context structure make specs read like requirements; the ecosystem (Capybara feature specs, factories, mocking, shoulda matchers) is built around it |
| Testing strategy | Testing pyramid: many unit tests, few or no end-to-end tests | Testing hourglass: an E2E test for every happy path, many unit tests for edge cases | Only an E2E test proves the app works for a user; unit tests are cheap for edge cases; the middle layer (controller and view tests) costs much and proves little |
| Controllers and models | Fat controllers, models with many callbacks | Slim controllers, fat models, core models with few callbacks | Business logic in models is testable without HTTP; controllers stay boring and uniform; callbacks on core models fire everywhere and cause surprises |
| Form models / presenters | No default — a gap in the framework | ActiveType form models and presenters | Screen-specific validations, callbacks and virtual attributes (sign-up, checkout, wizards) don't belong on the core model; ActiveType gives them a home with the full ActiveRecord API |
| Authorization | No default | Consul | One declarative place for what a user may do, usable in controllers, views and tests alike |
| HTML components | Partials only | Partials and ViewComponent | Components have an explicit API, co-locate template, helpers, CSS and JS, and can be unit-tested |
| File uploads | ActiveStorage | CarrierWave | ActiveStorage still has issues; CarrierWave is conceptually simple, stores files in the file system, and can deliver downloads without hitting a Rails controller |
| Background jobs | Solid Queue | GoodJob (Sidekiq in older projects) | Also PostgreSQL-backed, but more mature: cron jobs, concurrency controls, a dashboard, and jobs enqueued in the same transaction as your data |
| JavaScript build | Propshaft, import maps, "no build" | esbuild | No-build means no bundling, no Sass, no JSX, and poor debugging; esbuild bundles, transpiles and fingerprints JS, CSS and images in milliseconds |
| Package manager | yarn | pnpm (movie-db-base still uses yarn 1) | yarn 1 is no longer maintained and yarn 2+ never caught on; pnpm is fast, disk-efficient and feature-rich |
| Deployment | Kamal (containers on your own servers) | Capistrano to servers run by our operations team | We run our own hosting with dedicated servers, monitoring and backups, and our DevOps team takes care of Linux package upgrades; Capistrano deploys straight onto those servers, no containers needed |
"Testing hourglass" is our own term for many unit tests plus an end-to-end test for every happy path; elsewhere, e.g. at Google, "hourglass" names the opposite problem — too many end-to-end tests and too few unit tests. The "why" column is a one-sentence version. Later cards go into each topic; where a card teaches our choice, it links back here and explains the alternative.
Resources
Read what's new to you, skim what's familiar, skip what you already master. Stop when you can meet the learning goals.
Your agent can also generate an overview, a tutorial or an explanation for anything here, tailored to what you already know. Just ask.
The case for the menu
- 📄 Rails is omakase Show archive.org snapshot — DHH, 2012; the original essay, including "substitutions are allowed"
- 📄 The Rails Doctrine: The menu is omakase Show archive.org snapshot
- 📄 Rails 8.0 release notes Show archive.org snapshot and Rails 8: No PaaS required Show archive.org snapshot — what the current defaults are and why 37signals chose them
- ▶️ Rails 8 Unpacked Show archive.org snapshot — official videos on the Rails 8 defaults; watch to recognize them, not to adopt them
The trade-offs, row by row
- 📄 Hotwire vs. HTMX vs. Unpoly Show archive.org snapshot — hands-on, even-handed comparison (2024)
- 📄 Vanilla Rails is plenty Show archive.org snapshot — the 37signals view on models, concerns and form objects; then read the chapter "New rules for Rails" from our book Growing Rails Applications in Practice (in our library) for ours
- 📄 Static vs. unit vs. integration vs. E2E tests Show archive.org snapshot — the "testing trophy", closest to our hourglass; and Fixing a test hourglass Show archive.org snapshot — Google's case against many end-to-end tests, i.e. the other side
- 📄 Minitest vs. RSpec in Rails Show archive.org snapshot — balanced comparison
- 📄 GoodJob README: comparison with other queues Show archive.org snapshot
- 📄 Rendering on the web Show archive.org snapshot — server-rendered vs. client-rendered, with the vocabulary
Discuss with your mentor
Pick three rows of the table. For each, argue the Omakase side first, then ours. Which of our choices would you question, and what would change your mind?