Loading...

CLI Overview

Quick Start Guide

wheels info

wheels reload

wheels deps

wheels destroy

wheels watch

wheels generate app

wheels generate app-wizard

wheels generate controller

wheels generate model

wheels generate view

wheels generate property

wheels generate route

wheels generate resource

wheels generate api-resource

wheels generate frontend

wheels generate test

wheels generate snippets

wheels scaffold

wheels test

wheels test run

wheels test coverage

wheels test debug

wheels config list

wheels config set

wheels config env

wheels env

wheels env setup

wheels env list

wheels env switch

wheels environment

wheels console

wheels runner

wheels server

wheels server start

wheels server stop

wheels server restart

wheels server status

wheels server log

wheels server open

wheels plugins

wheels plugins list

wheels plugins install

wheels plugins remove

wheels analyze

wheels analyze code

wheels analyze performance

wheels analyze security

wheels security

wheels security scan

wheels optimize

wheels optimize performance

wheels docs

wheels docs generate

wheels docs serve

wheels ci init

wheels docker init

wheels docker deploy

wheels deploy

wheels deploy audit

wheels deploy exec

wheels deploy hooks

wheels deploy init

wheels deploy lock

wheels deploy logs

wheels deploy proxy

wheels deploy push

wheels deploy rollback

wheels deploy secrets

wheels deploy setup

wheels deploy status

wheels deploy stop

Configuration Management

Creating Commands

Service Architecture

Migrations Guide

Testing Guide

Ask or search...
Ctrl K
Loading...

wheels scaffold

This command works correctly without options (parameters). Option support is under development and will be available soon.

Generate complete CRUD scaffolding for a resource.

Synopsis

wheels generate scaffold name=[resourceName] [options]

Alias

wheels g scaffold name=[resourceName] [options]

Description

The wheels scaffold command generates a complete CRUD (Create, Read, Update, Delete) implementation including model, controller, views, tests, and database migration. It's the fastest way to create a fully functional resource.

Arguments

| Argument | Description | Default | |----------|-------------|---------| | name | Resource name (singular) | Required |

Options

| Option | Description | Default | |--------|-------------|---------| | properties | Model properties (format: name:type,name2:type2) | | | belongs-to | Parent model relationships (comma-separated) | | | has-many | Child model relationships (comma-separated) | | | --api | Generate API-only scaffold (no views) | false | | --tests | Generate test files | true | | --migrate | Run migrations after scaffolding | false | | --force | Overwrite existing files | false |

Examples

Basic scaffold

wheels generate scaffold name=product

Scaffold with properties

wheels generate scaffold name=product properties=name:string,price:decimal,stock:integer

Scaffold with associations

wheels scaffold name=order properties=total:decimal,status:string \
  belongsTo=user hasMany=orderItems

API scaffold

wheels generate scaffold name=product api=true properties=name:string,price:decimal

Scaffold with auto-migration

wheels generate scaffold name=category properties=name:string migrate=true

What Gets Generated

Standard Scaffold

  1. Model (/models/Product.cfc)

    • Properties and validations
    • Associations
    • Business logic
  2. Controller (/controllers/Products.cfc)

    • All CRUD actions
    • Flash messages
    • Error handling
  3. Views (/views/products/)

    • index.cfm - List all records
    • show.cfm - Display single record
    • new.cfm - New record form
    • edit.cfm - Edit record form
    • _form.cfm - Shared form partial
  4. Migration (/app/migrator/migrations/[timestamp]_create_products.cfc)

    • Create table
    • Add indexes
    • Define columns
  5. Tests (if enabled)

    • Model tests
    • Controller tests
    • Integration tests

API Scaffold

  1. Model - Same as standard
  2. API Controller - JSON responses only
  3. Migration - Same as standard
  4. API Tests - JSON response tests
  5. No Views - API doesn't need views

Generated Files Example

For wheels scaffold name=product properties=name:string,price:decimal,stock:integer:

Model: /models/Product.cfc

component extends="Model" {

    function init() {
        // Properties
        property(name="name", label="Product Name");
        property(name="price", label="Price");
        property(name="stock", label="Stock Quantity");
        
        // Validations
        validatesPresenceOf("name,price,stock");
        validatesUniquenessOf("name");
        validatesNumericalityOf("price", greaterThan=0);
        validatesNumericalityOf("stock", onlyInteger=true, greaterThanOrEqualTo=0);
    }

}

Controller: /controllers/Products.cfc

component extends="Controller" {

    function init() {
        // Filters
    }

    function index() {
        products = model("Product").findAll(order="name");
    }

    function show() {
        product = model("Product").findByKey(params.key);
        if (!IsObject(product)) {
            flashInsert(error="Product not found.");
            redirectTo(action="index");
        }
    }

    function new() {
        product = model("Product").new();
    }

    function create() {
        product = model("Product").new(params.product);
        if (product.save()) {
            flashInsert(success="Product was created successfully.");
            redirectTo(action="index");
        } else {
            flashInsert(error="There was an error creating the product.");
            renderView(action="new");
        }
    }

    function edit() {
        product = model("Product").findByKey(params.key);
        if (!IsObject(product)) {
            flashInsert(error="Product not found.");
            redirectTo(action="index");
        }
    }

    function update() {
        product = model("Product").findByKey(params.key);
        if (IsObject(product) && product.update(params.product)) {
            flashInsert(success="Product was updated successfully.");
            redirectTo(action="index");
        } else {
            flashInsert(error="There was an error updating the product.");
            renderView(action="edit");
        }
    }

    function delete() {
        product = model("Product").findByKey(params.key);
        if (IsObject(product) && product.delete()) {
            flashInsert(success="Product was deleted successfully.");
        } else {
            flashInsert(error="Product could not be deleted.");
        }
        redirectTo(action="index");
    }

}

View: /views/products/index.cfm

<h1>Products</h1>

#flashMessages()#

<p>#linkTo(text="New Product", action="new", class="btn btn-primary")#</p>

<table class="table">
    <thead>
        <tr>
            <th>Name</th>
            <th>Price</th>
            <th>Stock</th>
            <th>Actions</th>
        </tr>
    </thead>
    <tbody>
        <cfloop query="products">
            <tr>
                <td>#encodeForHtml(products.name)#</td>
                <td>#dollarFormat(products.price)#</td>
                <td>#products.stock#</td>
                <td>
                    #linkTo(text="Show", action="show", key=products.id)#
                    #linkTo(text="Edit", action="edit", key=products.id)#
                    #linkTo(text="Delete", action="delete", key=products.id, 
                            method="delete", confirm="Are you sure?")#
                </td>
            </tr>
        </cfloop>
    </tbody>
</table>

Form Partial: /views/products/_form.cfm

#errorMessagesFor("product")#

#textField(objectName="product", property="name", label="Product Name")#
#textField(objectName="product", property="price", label="Price")#
#textField(objectName="product", property="stock", label="Stock Quantity")#

Migration: /app/migrator/migrations/[timestamp]_create_products.cfc

component extends="wheels.migrator.Migration" {

    function up() {
        transaction {
            t = createTable("products");
            t.string("name");
            t.decimal("price", precision=10, scale=2);
            t.integer("stock");
            t.timestamps();
            t.create();
            
            addIndex(table="products", columns="name", unique=true);
        }
    }

    function down() {
        transaction {
            dropTable("products");
        }
    }

}

Routes Configuration

Add to /config/routes.cfm:

<cfset resources("products")>

This creates all RESTful routes:

  • GET /products - index
  • GET /products/new - new
  • POST /products - create
  • GET /products/[key] - show
  • GET /products/[key]/edit - edit
  • PUT/PATCH /products/[key] - update
  • DELETE /products/[key] - delete

Post-Scaffold Steps

  1. Run migration (if not using --migrate):

    wheels dbmigrate latest
    
  2. Add routes to /config/routes.cfm:

    <cfset resources("products")>
    
  3. Restart application:

    wheels reload
    
  4. Test the scaffold:

    • Visit /products to see the index
    • Create, edit, and delete records
    • Run generated tests

Customization

In controller's index():

function index() {
    if (StructKeyExists(params, "search")) {
        products = model("Product").findAll(
            where="name LIKE :search",
            params={search: "%#params.search#%"}
        );
    } else {
        products = model("Product").findAll();
    }
}

Adding Pagination

function index() {
    products = model("Product").findAll(
        page=params.page ?: 1,
        perPage=20,
        order="createdAt DESC"
    );
}

Adding Filters

function init() {
    filters(through="authenticate", except="index,show");
}

Template Customization

The scaffold command uses templates to generate code. You can customize these templates to match your project's coding standards and markup preferences.

Template Override System

The CLI uses a template override system that allows you to customize the generated code:

  1. CLI Templates - Default templates are located in the CLI module at /cli/templates/
  2. App Templates - Custom templates in your application at /app/snippets/ override the CLI templates

This means you can modify the generated code structure by creating your own templates in the /app/snippets/ directory.

How It Works

When generating code, the CLI looks for templates in this order:

  1. First checks /app/snippets/[template-name]
  2. Falls back to /cli/templates/[template-name] if not found in app

Customizing Templates

To customize scaffold output:

  1. Copy the template you want to customize from /cli/templates/ to /app/snippets/
  2. Modify the template to match your project's needs
  3. Run scaffold - it will use your custom template

Example for customizing the form template:

# Create the crud directory in your app
mkdir -p app/snippets/crud

# Copy the form template
cp /path/to/wheels/cli/templates/crud/_form.txt app/snippets/crud/

# Edit the template to match your markup
# The CLI will now use your custom template

Available Templates

Templates used by scaffold command:

  • crud/index.txt - Index/list view
  • crud/show.txt - Show single record view
  • crud/new.txt - New record form view
  • crud/edit.txt - Edit record form view
  • crud/_form.txt - Form partial shared by new/edit
  • ModelContent.txt - Model file structure
  • ControllerContent.txt - Controller file structure

Template Placeholders

Templates use placeholders that get replaced during generation:

  • |ObjectNameSingular| - Lowercase singular name (e.g., "product")
  • |ObjectNamePlural| - Lowercase plural name (e.g., "products")
  • |ObjectNameSingularC| - Capitalized singular name (e.g., "Product")
  • |ObjectNamePluralC| - Capitalized plural name (e.g., "Products")
  • |FormFields| - Generated form fields based on properties
  • <!--- CLI-Appends-Here ---> - Marker for future CLI additions

Best Practices

  1. Properties: Define all needed properties upfront
  2. Associations: Include relationships in initial scaffold
  3. Validation: Add custom validations after generation
  4. Testing: Always generate and run tests
  5. Routes: Use RESTful resources when possible
  6. Security: Add authentication/authorization
  7. Templates: Customize templates in /app/snippets/ to match your project standards

Comparison with Individual Generators

Scaffold generates everything at once:

# Scaffold does all of this:
wheels generate model product properties="name:string,price:decimal"
wheels generate controller products --rest
wheels generate view products index,show,new,edit,_form
wheels generate test model product
wheels generate test controller products
wheels dbmigrate create table products

See Also