Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -55,13 +55,21 @@ At the end of Part 1 you had a running `blog` app with a `/hello` route. There's

`Main.cfc` has `index` and `hello` actions. `config/routes.cfm` has a `/hello` named route alongside the wildcard and root. The SQLite database file exists but has no application tables. You'll fix all of that here.

## Hand-write the Post model
## Generate the Post model

Normally you'd run `wheels generate model Post title:string body:text` and Wheels would write both the model CFC and a migration. On the `wheels` CLI version this tutorial targets (`0.3.5-SNAPSHOT`), the generator needs snippet templates that a fresh `wheels new` doesn't ship with. The generator will gain those templates in a future CLI release. For now, you'll hand-write the files — it's three small files, and it's a useful exercise.
`wheels generate model Post title:string body:text` writes both the model CFC and a migration for you. The generator output is intentionally slim — it doesn't include the `enum` for `status` or the `publishedAt` field this tutorial uses, so you'll augment it after.

<Steps>

1. Create `app/models/Post.cfc`:
1. Run the generator:

```bash
wheels generate model Post title:string body:text
```

That creates `app/models/Post.cfc` (a near-empty `component extends="Model"`) and a migration file under `app/migrator/migrations/` with a current timestamp.

2. Replace the contents of `app/models/Post.cfc` with the version below — it adds the `status` enum we'll use to filter posts:

```cfm {test:compile}
component extends="Model" {
Expand All @@ -82,13 +90,15 @@ Normally you'd run `wheels generate model Post title:string body:text` and Wheel

You'll use the `published()` scope in a minute.

## Write the migration
## Augment the migration

Migrations are ordered, reversible schema changes. Each one is a CFC in `app/migrator/migrations/` whose filename starts with a timestamp (`YYYYMMDDHHMMSS_description.cfc`). `wheels migrate latest` runs every pending migration in timestamp order.

The generator already wrote a migration for you with `title` and `body` columns. We need to add `status` and `publishedAt` so the model and table line up.

<Steps>

1. Create `app/migrator/migrations/20260419120000_create_posts_table.cfc`:
1. Open the migration file the generator created (it's the most recent one in `app/migrator/migrations/`, named `<timestamp>_create_posts_table.cfc`) and replace its contents with the version below. We're using a fixed timestamp here (`20260419120000`) so the filename in the rest of this tutorial matches what you have on disk — feel free to keep the generator's timestamp instead.

```cfm {test:compile}
component extends="wheels.migrator.Migration" hint="Create posts table" {
Expand Down Expand Up @@ -168,9 +178,13 @@ Wheels loads seed data from `app/db/seeds.cfm` (shared) and optionally `app/db/s

<Steps>

1. Create `app/db/seeds.cfm`:
1. Create the `app/db/` directory (it isn't scaffolded by `wheels new`), then create `app/db/seeds.cfm`:

```cfm {test:compile}
```bash title="your shell"
mkdir -p app/db
```

```cfm title="app/db/seeds.cfm" {test:compile}
<cfscript>
seedOnce(modelName="Post", uniqueProperties="title", properties={
title: "Hello world",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -70,36 +70,34 @@ Because scaffolds follow convention, a plain `.resources("posts")` line in `conf

Route model binding kicks in on the actions that take a key. For `show`, `edit`, `update`, and `delete`, Wheels finds the `Post` matching `params.key` before your action runs and hands it to you as `params.post`. No `findByKey` in the controller.

<Aside type="note">
On the `wheels` CLI version this tutorial targets (`0.3.5-SNAPSHOT`), `wheels generate scaffold` needs snippet templates that a fresh `wheels new` doesn't ship with. A future release will bundle them. For now you'll hand-write the files the generator would produce — mechanical, but it cements the shape of a scaffold in your head.
</Aside>

## Delete Part 2's handiwork

Drop the hand-written controller and views. The model, migration, seed file, and the `resources("posts")` route stay.

```bash title="your shell"
wheels destroy controller Posts
wheels destroy Posts controller
```

If your CLI doesn't support `destroy` (same snippet-template gap as `generate`), remove the files directly:
The argument order is `<name> [type]` — `Posts controller`, not `controller Posts`. If you'd rather skip the CLI and remove the files yourself:

```bash title="your shell"
rm app/controllers/Posts.cfc
rm -r app/views/posts
```

Leave `app/models/Post.cfc`, `app/migrator/migrations/20260419120000_create_posts_table.cfc`, `app/db/seeds.cfm`, and `config/routes.cfm` alone.
Leave `app/models/Post.cfc`, `app/migrator/migrations/<timestamp>_create_posts_table.cfc`, `app/db/seeds.cfm`, and `config/routes.cfm` alone.

## Generate the scaffold

The one-line version — what you'd run on a future CLI with the snippets bundled:
`wheels generate scaffold` creates the controller, the seven CRUD views, and (if it didn't already exist) the model and migration in one shot.

```bash title="your shell"
wheels generate scaffold Post title:string body:text status:enum
```

If that errors with `Template not found: ModelContent.txt`, hand-write the files in the sections below. They're what the generator would produce.
<Aside type="caution">
The scaffold generator will refuse to overwrite an existing `app/models/Post.cfc` and bail before producing the controller and views. Since chapter 2 already wrote the model, you'll see `Scaffold failed: Model already exists`. When that happens, hand-write the files in the sections below — they're what the generator would have produced. (A future release will add a `--skip-existing` flag so the scaffold can reuse the existing model.)
</Aside>

### The controller

Expand Down
Loading