Command Line Tools
wheels generate controller
wheels generate controller
Section titled “wheels generate controller”Generate a controller with actions and optional views.
Synopsis
Section titled “Synopsis”wheels generate controller name=<controllerName> [options]
#Can also be used as:wheels g controller name=<controllerName> [options]CommandBox Parameter Syntax
Section titled “CommandBox Parameter Syntax”- Positional parameters:
wheels generate controller Products(controller name) - Named parameters:
param=value(e.g.,name=Products,actions=index,show) - Flag parameters:
--flagequalsflag=true(e.g.,--crudequalscrud=true) - Params with value:
--param=valueequalsparam=value(e.g.,--actions=index,show)
Recommended Format:
- Positional for name:
wheels generate controller Products - Flags for options:
wheels generate controller Products --crud --force
Not Allowed:
- Use
--actions(plural) not--action(singular) - Don’t mix positional and named parameters (causes errors)
Description
Section titled “Description”The wheels generate controller command creates a new controller CFC file with specified actions and optionally generates corresponding view files. It supports both traditional and RESTful controller patterns.
Arguments
Section titled “Arguments”| Argument | Description | Default |
|---|---|---|
name | Name of the controller to create (usually plural) | Required |
Options
Section titled “Options”| Option | Description | Default |
|---|---|---|
actions | Actions to generate (comma-delimited) - HIGHEST PRIORITY, overrides --crud | index |
crud | Generate CRUD controller with actions (index, show, new, create, edit, update, delete) and scaffold-style views (index, show, new, edit, _form) | false |
api | Generate API controller (no views generated, only JSON/XML endpoints) | false |
noViews | Skip view generation (only generate controller) | false |
description | Controller description comment | "" |
force | Overwrite existing files | false |
How It Works
Section titled “How It Works”Decision Tree
Section titled “Decision Tree”ACTION GENERATION:├─ Has --actions? → Use those actions ONLY (highest priority, overrides --crud)├─ Has --api? → Generate 5 actions (index, show, create, update, delete)├─ Has --crud? → Generate 7 actions (index, show, new, create, edit, update, delete)└─ Default → Generate 1 action (index)
VIEW GENERATION:├─ Has --api? → NO VIEWS (JSON/XML responses)├─ Has --noViews? → NO VIEWS (explicitly skipped)├─ Has --crud? → 5 VIEWS (index, show, new, edit, _form)└─ Default → CREATE 1 VIEW PER ACTIONCommon Use Cases
Section titled “Common Use Cases”| What You Want | Command | Actions | Views |
|---|---|---|---|
| Traditional web app (scaffold-style) | --crud | 7 | 5 (index, show, new, edit, _form) |
| REST API (JSON/XML) | --api | 5 | None |
| Single page controller | (no flags) | 1 (index) | 1 (index) |
| Custom actions with views | --actions=dashboard,export | 2 | 2 (dashboard, export) |
| Controller only (no views) | --crud --noViews | 7 | None |
—crud vs —api
Section titled “—crud vs —api”| Aspect | —crud | —api |
|---|---|---|
| Purpose | Traditional web application | API endpoints |
| Actions | 7 (includes new, edit forms) | 5 (no form actions) |
| Views | 5 scaffold-style views | None |
| Response | HTML pages with forms | JSON/XML data |
| Use Case | User-facing web apps | Mobile apps, SPAs, integrations |
Examples
Section titled “Examples”Basic controller
Section titled “Basic controller”wheels generate controller ProductsCreates: Products.cfc with index action and index.cfm view
Controller with custom actions
Section titled “Controller with custom actions”wheels generate controller Products --actions=dashboard,reports,exportCreates: Products.cfc with 3 custom actions and 3 views
CRUD controller (scaffold-style)
Section titled “CRUD controller (scaffold-style)”wheels generate controller Products --crudCreates: Products.cfc with 7 CRUD actions + 5 views (index, show, new, edit, _form)
API controller (no views)
Section titled “API controller (no views)”wheels generate controller Orders --apiCreates: Orders.cfc with 5 API actions, no views
Controller without views
Section titled “Controller without views”wheels generate controller Products --crud --noViewsCreates: Products.cfc with 7 actions, no views
Priority override example
Section titled “Priority override example”wheels generate controller Products --crud --actions=dashboardCreates: Products.cfc with only dashboard action (—actions overrides —crud)
Generated Code
Section titled “Generated Code”Basic Controller
Section titled “Basic Controller”component extends="Controller" {
/** * Controller config settings **/ function config() {
}
/** * index action */ function index() { // TODO: Implement index action }}Controller with Description
Section titled “Controller with Description”/** * Handles user management operations */component extends="Controller" {
/** * Controller config settings **/ function config() {
}
/** * index action */ function index() { // TODO: Implement index action }}RESTful Controller
Section titled “RESTful Controller”component extends="Controller" {
function config() { verifies(except="index,new,create", params="key", paramsTypes="integer", handler="objectNotFound"); }
/** * View all Products **/ function index() { products=model("product").findAll(); }
/** * View Product **/ function show() { product=model("product").findByKey(params.key); }
/** * Add New Product **/ function new() { product=model("product").new(); }
/** * Create Product **/ function create() { product=model("product").create(params.product); if(product.hasErrors()){ renderView(action="new"); } else { redirectTo(action="index", success="Product successfully created"); } }
/** * Edit Product **/ function edit() { product=model("product").findByKey(params.key); }
/** * Update Product **/ function update() { product=model("product").findByKey(params.key); if(product.update(params.product)){ redirectTo(action="index", success="Product successfully updated"); } else { renderView(action="edit"); } }
/** * Delete Product **/ function delete() { product=model("product").deleteByKey(params.key); redirectTo(action="index", success="Product successfully deleted"); }
/** * Redirect away if verifies fails, or if an object can't be found **/ function objectNotFound() { redirectTo(action="index", error="That Product wasn't found"); }
}API Controller
Section titled “API Controller”/** * API endpoint for order processing */component extends="wheels.Controller" {
function init() { provides("json"); filters(through="setJsonResponse"); }
/** * GET /orders * Returns a list of all orders */ function index() { local.orders = model("order").findAll(); renderWith(data={ orders=local.orders }); }
/** * GET /orders/:key * Returns a specific order by ID */ function show() { local.order = model("order").findByKey(params.key);
if (IsObject(local.order)) { renderWith(data={ order=local.order }); } else { renderWith(data={ error="Record not found" }, status=404); } }
/** * POST /orders * Creates a new order */ function create() { local.order = model("order").new(params.order);
if (local.order.save()) { renderWith(data={ order=local.order }, status=201); } else { renderWith(data={ error="Validation failed", errors=local.order.allErrors() }, status=422); } }
/** * PUT /orders/:key * Updates an existing order */ function update() { local.order = model("order").findByKey(params.key);
if (IsObject(local.order)) { local.order.update(params.order);
if (local.order.hasErrors()) { renderWith(data={ error="Validation failed", errors=local.order.allErrors() }, status=422); } else { renderWith(data={ order=local.order }); } } else { renderWith(data={ error="Record not found" }, status=404); } }
/** * DELETE /orders/:key * Deletes a order */ function delete() { local.order = model("order").findByKey(params.key);
if (IsObject(local.order)) { local.order.delete(); renderWith(data={}, status=204); } else { renderWith(data={ error="Record not found" }, status=404); } }
/** * Set Response to JSON */ private function setJsonResponse() { params.format = "json"; }
}View Generation
Section titled “View Generation”Views are automatically generated for non-API controllers:
index.cfm
Section titled “index.cfm”<h1>Products</h1>
<p>#linkTo(text="New Product", action="new")#</p>
<table> <thead> <tr> <th>Name</th> <th>Actions</th> </tr> </thead> <tbody> <cfloop query="products"> <tr> <td>#products.name#</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>Naming Conventions
Section titled “Naming Conventions”- Controller names: PascalCase, typically plural (Products, Users)
- Action names: camelCase (index, show, createProduct)
- File locations:
- Controllers:
/controllers/ - Nested:
/controllers/admin/Products.cfc - Views:
/views/{controller}/
- Controllers:
Routes Configuration
Section titled “Routes Configuration”Add routes in /config/routes.cfm:
Traditional Routes
Section titled “Traditional Routes”<cfscript>mapper() .get(name="products", to="products##index") .get(name="product", to="products##show") .post(name="products", to="products##create") .wildcard().end();</cfscript>RESTful Resources
Section titled “RESTful Resources”<cfscript>mapper() .resources("products") .wildcard().end();</cfscript>Testing
Section titled “Testing”Generate tests alongside controllers:
wheels generate controller name=products --crudwheels generate test controller name=productsBest Practices
Section titled “Best Practices”- Use plural names for resource controllers
- Keep controllers focused on single resources
- Use
--crudfor standard web app CRUD operations (with views and forms) - Use
--apifor API endpoints (JSON/XML, no views) - Use
--actionswhen you need custom actions (HIGHEST PRIORITY - overrides--crud) - Implement proper error handling
- Add authentication in
config()method - Use filters for common functionality
Common Patterns
Section titled “Common Patterns”Authentication Filter
Section titled “Authentication Filter”function config() { filters(through="authenticate", except="index,show");}
private function authenticate() { if (!session.isLoggedIn) { redirectTo(controller="sessions", action="new"); }}Pagination
Section titled “Pagination”function index() { products = model("Product").findAll( page=params.page ?: 1, perPage=25, order="createdAt DESC" );}Search
Section titled “Search”function index() { if (StructKeyExists(params, "q")) { products = model("Product").findAll( where="name LIKE :search OR description LIKE :search", params={search: "%#params.q#%"} ); } else { products = model("Product").findAll(); }}See Also
Section titled “See Also”- wheels generate model - Generate models
- wheels generate view - Generate views
- wheels scaffold - Generate complete CRUD
- wheels generate test - Generate controller tests