Skip to content

Command Line Tools

wheels generate model

Generate a model with properties, validations, and associations.

Terminal window
wheels generate model name=<modelName> [options]
#Can also be used as:
wheels g model name=<modelName> [options]
  • Named parameters: param=value (e.g., name=User, properties=name:string,email:string)
  • Flag parameters: --flag equals flag=true (e.g., --migration equals migration=true)
  • Param with value: --param=value equals param=value (e.g., --primaryKey=uuid)

Recommended: Use flags for options: wheels generate model name=User --properties="name:string,email:string" --migration

The wheels generate model command creates a new model CFC file with optional properties, associations, and database migrations. Models represent database tables and contain business logic, validations, and relationships.

ArgumentDescriptionDefault
nameModel name (singular)Required
  • Must be singular (User, not Users)
  • Must be PascalCase (User, BlogPost)
  • Cannot contain spaces or special characters
  • Must be valid CFML component name
OptionDescriptionValid ValuesDefault
propertiesModel properties (format: name:type,name2:type2)Property format: name:type[,name2:type2] where type is valid column type""
belongsToParent model relationships (comma-separated)Valid model names (PascalCase), comma-separated""
hasManyChild model relationships (comma-separated)Valid model names (PascalCase), comma-separated""
hasOneOne-to-one relationships (comma-separated)Valid model names (PascalCase), comma-separated""
primaryKeyPrimary key column name(s)Valid column name (alphanumeric, underscore)id
tableNameCustom database table nameValid table name (alphanumeric, underscore)""
descriptionModel descriptionAny descriptive text""
migrationGenerate database migrationtrue, falsetrue
forceOverwrite existing filestrue, falsefalse
  • Relationship model names must follow model naming conventions
  • Models referenced in relationships should exist or be created
  • Comma-separated values cannot contain spaces around commas
TypeDatabase TypeCFML Type
stringVARCHAR(255)string
textTEXTstring
integerINTEGERnumeric
bigintegerBIGINTnumeric
floatFLOATnumeric
decimalDECIMAL(10,2)numeric
booleanBOOLEANboolean
dateDATEdate
datetimeDATETIMEdate
timestampTIMESTAMPdate
binaryBLOBbinary
uuidVARCHAR(35)string
Terminal window
wheels generate model name=User

Creates:

  • /models/User.cfc
  • Migration file (if enabled)
Terminal window
wheels generate model name=User --properties="firstName:string,lastName:string,email:string,age:integer"
Terminal window
wheels generate model name=Post --belongsTo="User" --hasMany="Comments"
Terminal window
wheels generate model name=Setting --migration=false
Terminal window
wheels generate model name=Product --properties="name:string,price:decimal,stock:integer,active:boolean" --belongsTo="Category,Brand" --hasMany="Reviews,OrderItems"
Terminal window
# Error: Model name cannot be empty
wheels generate model name=""
# Result: Invalid model name error
# Error: Model name should be singular
wheels generate model name=Users
# Result: Warning about plural name
# Error: Invalid characters
wheels generate model name="Blog Post"
# Result: Invalid model name error
Terminal window
# Error: Invalid property type
wheels generate model name=User --properties="name:varchar,age:int"
# Result: Use 'string' instead of 'varchar', 'integer' instead of 'int'
# Error: Missing property type
wheels generate model name=User --properties="name,email:string"
# Result: Property format must be 'name:type'

Important Validation Rules:

  • Model names must be singular and PascalCase (User, not Users or user)
  • Property format: name:type,name2:type2 (no spaces)
  • Relationship names must be PascalCase (User, not user)
  • Use valid property types from the table above
component extends="Model" {
function init() {
// Table name (optional if following conventions)
table("users");
// Validations
validatesPresenceOf("email");
validatesUniquenessOf("email");
validatesFormatOf("email", regex="^[^@]+@[^@]+\.[^@]+$");
// Callbacks
beforeCreate("setDefaultValues");
}
private function setDefaultValues() {
if (!StructKeyExists(this, "createdAt")) {
this.createdAt = Now();
}
}
}
component extends="Model" {
function init() {
// Properties
property(name="firstName", label="First Name");
property(name="lastName", label="Last Name");
property(name="email", label="Email Address");
property(name="age", label="Age");
// Validations
validatesPresenceOf("firstName,lastName,email");
validatesUniquenessOf("email");
validatesFormatOf("email", regex="^[^@]+@[^@]+\.[^@]+$");
validatesNumericalityOf("age", onlyInteger=true, greaterThan=0, lessThan=150);
}
}
component extends="Model" {
function init() {
// Associations
belongsTo("user");
hasMany("comments", dependent="deleteAll");
// Nested properties
nestedProperties(associations="comments", allowDelete=true);
// Validations
validatesPresenceOf("title,content,userId");
validatesLengthOf("title", maximum=255);
}
}
// Presence
validatesPresenceOf("name,email");
// Uniqueness
validatesUniquenessOf("email,username");
// Format
validatesFormatOf("email", regex="^[^@]+@[^@]+\.[^@]+$");
validatesFormatOf("phone", regex="^\d{3}-\d{3}-\d{4}$");
// Length
validatesLengthOf("username", minimum=3, maximum=20);
validatesLengthOf("bio", maximum=500);
// Numerical
validatesNumericalityOf("age", onlyInteger=true, greaterThan=0);
validatesNumericalityOf("price", greaterThan=0);
// Inclusion/Exclusion
validatesInclusionOf("status", list="active,inactive,pending");
validatesExclusionOf("username", list="admin,root,system");
// Confirmation
validatesConfirmationOf("password");
// Custom
validate("customValidation");
belongsTo("user");
belongsTo(name="author", modelName="user", foreignKey="authorId");
hasMany("comments");
hasMany(name="posts", dependent="deleteAll", orderBy="createdAt DESC");
hasOne("profile");
hasOne(name="address", dependent="delete");
hasMany("categorizations");
hasMany(name="categories", through="categorizations");
// Before callbacks
beforeCreate("method1,method2");
beforeUpdate("method3");
beforeSave("method4");
beforeDelete("method5");
beforeValidation("method6");
// After callbacks
afterCreate("method7");
afterUpdate("method8");
afterSave("method9");
afterDelete("method10");
afterValidation("method11");
afterFind("method12");
afterInitialization("method13");
  1. Naming: Use singular names (User, not Users)
  2. Properties: Define all database columns with correct types
  3. Validations: Add comprehensive validations in model code
  4. Associations: Define all relationships using PascalCase
  5. Callbacks: Use for automatic behaviors
  6. Indexes: Add to migration for performance
  7. Validation: Always validate parameters before running command
function init() {
softDeletes();
}
function init() {
property(name="fullName", sql="firstName + ' ' + lastName");
}
function scopeActive() {
return where("active = ?", [true]);
}
function scopeRecent(required numeric days=7) {
return where("createdAt >= ?", [DateAdd("d", -arguments.days, Now())]);
}
function init() {
beforeCreate("setDefaults");
}
private function setDefaults() {
if (!StructKeyExists(this, "status")) {
this.status = "pending";
}
if (!StructKeyExists(this, "priority")) {
this.priority = 5;
}
}

Generate model tests:

Terminal window
wheels generate model name=User --properties="email:string,name:string"
wheels generate test type=model name=User