Start Here
Tutorial: Build a Blog
You’ll build a complete blog application. Posts with titles and bodies. Comments under each post. Users who sign up, log in, and can only edit their own content. Forms that validate inline without page reloads. One browser test that clicks through the whole flow.
By the end you’ve touched every part of Wheels that matters in day-to-day work: models, migrations, seeds, scaffolds, validations, associations, forms, routes, filters, Turbo Frames, Turbo Streams, authentication, and tests.
You’ll learn: everything in The Basics and most of Digging Deeper. This tutorial is the single best introduction to Wheels 4.0.
What you’ll build
Section titled “What you’ll build”A blog for an individual author. The final app supports:
- Posts — a title, body, status (draft / published / archived), and publication date
- Comments — readers can comment on published posts without signing up
- Users — authors sign up with email and password, then manage their own posts
- Turbo UI — form errors appear inline, new comments append without page reloads, page transitions have zero flash
- Tests — one model spec, one controller spec, one browser spec clicking through the full flow
Technology stack
Section titled “Technology stack”- Framework: Wheels 4.0 on Lucee 7 (via the bundled
wheelsCLI) - Database: SQLite, zero setup. Same engine the tutorial runs against in CI.
- Frontend: Turbo Drive for page transitions, Turbo Frames for inline errors, Turbo Streams for comment updates. Loaded from a CDN script tag in Part 4; the installable
wheels-hotwirepackage (wheels packages add wheels-hotwire) is the canonical home once you’re past the tutorial. - Styling: simple.css, wired into the generated
app/views/layout.cfmbywheels new. Classless — semantic HTML renders polished without any markup changes. Thewheels-basecoatpackage is available as an optional shadcn/ui-quality component-kit upgrade after the tutorial. - Auth: Wheels’ built-in
SessionStrategyfor session cookies. Hand-rolled version shown first for understanding, built-in version shown second for shipping. - Tests: WheelsTest (BDD), plus one Playwright-driven browser spec.
The seven parts
Section titled “The seven parts”| Part | Topic | Time |
|---|---|---|
| 1. Hello, Wheels | Scaffold an app. Add a route, a controller action, a view. | 20 min |
| 2. Your First Model | Generate a Post model. Run a migration. Seed data. Build the index and show actions by hand. | 25 min |
| 3. CRUD Scaffold | Throw it away. Run wheels generate scaffold. Tour the generated files and meet Wheels’ package system. | 25 min |
| 4. Validations and Turbo Frames | Add model validations. Wrap the form in a <turbo-frame> so errors come back inline. | 30 min |
| 5. Comments and Turbo Streams | Add a Comment model. Associate it with Post. Nested routes. Submit comments via Turbo Streams. | 35 min |
| 6. Authentication | Hand-roll sessions first to understand the mental model. Then replace with wheels.auth.SessionStrategy. | 45 min |
| 7. Testing and Deploying | Model spec, controller spec, one browser spec. Deployment overview. What to read next. | 35 min |
| Bonus: Style with wheels-basecoat | Optional. Install the basecoat package and convert the post view to shadcn/ui-quality components. Meets the Wheels package system end-to-end. | 30 min |
How each part works
Section titled “How each part works”- “Where we left off” — the first section of every part after Part 1. A file tree and schema summary so you can resume without reading the previous part end-to-end.
- Numbered steps — each change to the code is a numbered step in a
<Steps>block. You’ll see the file path, the before state when relevant, and the final content. - Checkpoint — before moving on, a concrete check you can run (usually
curlagainst a URL orwheels test). - Troubleshooting — three common failure modes with fixes, including the error message you’d see.
Conventions used throughout
Section titled “Conventions used throughout”- SQLite. All development runs against SQLite in
db/development.sqlite. Zero setup. Matches the CI testing platform. - Real names. Code examples use
Post,Comment,user.email,publishedAt— notFoo,Bar, orsomeField. - Complete code. Each block shows the whole function or view, not a fragment. You can always copy a block and have the feature work.
- Validated. Code blocks annotated with
{test:compile}or{test:cli}are validated by the doc site’s verify-docs harness against a realwheelsCLI. Blocks without an annotation (shell transcripts, illustrative excerpts) are reviewed but not executed.
Ready to start
Section titled “Ready to start” Part 1: Hello, Wheels 20 minutes — scaffold an app, add a route
Part 2: Your First Model 25 minutes — generators, migrations, seeds, finders
Part 3: CRUD Scaffold 25 minutes — packages, scaffold, Turbo Drive
Part 4: Validations and Turbo Frames 30 minutes — validations, inline errors, filters
Part 5: Comments and Turbo Streams 35 minutes — associations, nested routes, streams
Part 6: Authentication 45 minutes — hand-rolled first, then built-in
Part 7: Testing and Deploying 35 minutes — WheelsTest, browser tests, deployment
Bonus: Style with wheels-basecoat 30 minutes — optional. Install a package, swap the styling, meet the package system end-to-end.