wheels generate model
Generate a model with properties, validations, and associations.
Synopsis
wheels generate model name=<modelName> [options]
#Can also be used as:
wheels g model name=<modelName> [options]
Parameter Syntax
CommandBox supports multiple parameter formats:
Named parameters:
name=value
(e.g.,name=User
,properties=name:string,email:string
)Flag parameters:
--flag
equalsflag=true
(e.g.,--migration
equalsmigration=true
)Flag with value:
--flag=value
equalsflag=value
(e.g.,--primaryKey=uuid
)
Note: Flag syntax (--flag
) avoids positional/named parameter conflicts and is recommended for boolean options.
Description
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.
Arguments
name
Model name (singular)
Required
Options
properties
Model properties (format: name:type,name2:type2)
Property format: name:type[,name2:type2]
where type is valid column type
""
belongsTo
Parent model relationships (comma-separated)
Valid model names (PascalCase), comma-separated
""
hasMany
Child model relationships (comma-separated)
Valid model names (PascalCase), comma-separated
""
hasOne
One-to-one relationships (comma-separated)
Valid model names (PascalCase), comma-separated
""
primaryKey
Primary key column name(s)
Valid column name (alphanumeric, underscore)
id
tableName
Custom database table name
Valid table name (alphanumeric, underscore)
""
description
Model description
Any descriptive text
""
migration
Generate database migration
true
, false
true
force
Overwrite existing files
true
, false
false
Parameter Validation
Required Parameters
name
: Cannot be empty, must be valid CFML component name (alphanumeric, starts with letter)
Property Types Validation
Valid property types for the properties
parameter:
string
VARCHAR(255)
Default string type
text
TEXT
For longer text content
integer
INTEGER
Whole numbers
biginteger
BIGINT
Large whole numbers
float
FLOAT
Decimal numbers
decimal
DECIMAL(10,2)
Precise decimal numbers
boolean
BOOLEAN
true/false values
date
DATE
Date values
datetime
DATETIME
Date and time values
timestamp
TIMESTAMP
Timestamp values
binary
BLOB
Binary data
uuid
VARCHAR(35)
UUID strings
Model Name Validation
Must be singular (User, not Users)
Must be PascalCase (User, BlogPost)
Cannot contain spaces or special characters
Must be valid CFML component name
Relationship Validation
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
Examples
Basic model
wheels generate model name=User
Creates:
/models/User.cfc
Migration file (if enabled)
Model with properties
wheels generate model name=User --properties="firstName:string,lastName:string,email:string,age:integer"
Model with associations
wheels generate model name=Post --belongsTo="User" --hasMany="Comments"
Model without migration
wheels generate model name=Setting --migration=false
Complex model
wheels generate model name=Product --properties="name:string,price:decimal,stock:integer,active:boolean" --belongsTo="Category,Brand" --hasMany="Reviews,OrderItems"
Validation Examples
✅ Valid Examples
# Valid model name and properties
wheels generate model name=User --properties="firstName:string,lastName:string,email:string,age:integer"
# Valid relationships
wheels generate model name=Post --belongsTo="User,Category" --hasMany="Comments,Tags"
# Valid property types
wheels generate model name=Product --properties="name:string,description:text,price:decimal,inStock:boolean,createdAt:datetime"
❌ Invalid Examples and Errors
Invalid Model Names
# 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
Invalid Property Types
# 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'
Invalid Relationships
# Error: Invalid model name format
wheels generate model name=Post --belongsTo="user,blog_category"
# Result: Use PascalCase: 'User,BlogCategory'
# Error: Spaces in comma-separated values
wheels generate model name=Post --belongsTo="User, Category"
# Result: Remove spaces: 'User,Category'
Property Types
string
VARCHAR(255)
string
text
TEXT
string
integer
INTEGER
numeric
biginteger
BIGINT
numeric
float
FLOAT
numeric
decimal
DECIMAL(10,2)
numeric
boolean
BOOLEAN
boolean
date
DATE
date
datetime
DATETIME
date
timestamp
TIMESTAMP
date
binary
BLOB
binary
uuid
VARCHAR(35)
string
Generated Code
Basic Model
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();
}
}
}
Model with Properties
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);
}
}
Model with Associations
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);
}
}
Validations
Common validation methods:
// 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");
Associations
Belongs To
belongsTo("user");
belongsTo(name="author", modelName="user", foreignKey="authorId");
Has Many
hasMany("comments");
hasMany(name="posts", dependent="deleteAll", orderBy="createdAt DESC");
Has One
hasOne("profile");
hasOne(name="address", dependent="delete");
Many to Many
hasMany("categorizations");
hasMany(name="categories", through="categorizations");
Callbacks
Lifecycle callbacks:
// 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");
Generated Migration
When --migration
is enabled:
component extends="wheels.migrator.Migration" {
function up() {
transaction {
t = createTable("users");
t.string("firstName");
t.string("lastName");
t.string("email");
t.integer("age");
t.timestamps();
t.create();
addIndex(table="users", columnNames="email", unique=true);
}
}
function down() {
transaction {
dropTable("users");
}
}
}
Common Validation Errors
Model Name Errors
Empty name:
name=""
→ Provide a valid model namePlural names:
name=Users
→ Use singular form:name=User
Invalid characters:
name="Blog Post"
→ Use PascalCase:name=BlogPost
Lowercase:
name=user
→ Use PascalCase:name=User
Property Format Errors
Missing colon:
properties="name,email:string"
→properties="name:string,email:string"
Invalid types:
properties="name:varchar"
→properties="name:string"
Extra spaces:
properties="name: string"
→properties="name:string"
Missing type:
properties="name:"
→properties="name:string"
Boolean Parameter Errors
Invalid boolean:
--migration=yes
→--migration=true
or--migration=false
Mixed syntax:
migration=true --force
→--migration=true --force
Relationship Format Errors
Lowercase models:
belongsTo="user"
→belongsTo="User"
Extra spaces:
belongsTo="User, Category"
→belongsTo="User,Category"
Invalid separators:
belongsTo="User;Category"
→belongsTo="User,Category"
Best Practices
Naming: Use singular names (User, not Users)
Properties: Define all database columns with correct types
Validations: Add comprehensive validations in model code
Associations: Define all relationships using PascalCase
Callbacks: Use for automatic behaviors
Indexes: Add to migration for performance
Validation: Always validate parameters before running command
Common Patterns
Soft Deletes
function init() {
softDeletes();
}
Calculated Properties
function init() {
property(name="fullName", sql="firstName + ' ' + lastName");
}
Scopes
function scopeActive() {
return where("active = ?", [true]);
}
function scopeRecent(required numeric days=7) {
return where("createdAt >= ?", [DateAdd("d", -arguments.days, Now())]);
}
Default Values
function init() {
beforeCreate("setDefaults");
}
private function setDefaults() {
if (!StructKeyExists(this, "status")) {
this.status = "pending";
}
if (!StructKeyExists(this, "priority")) {
this.priority = 5;
}
}
Testing
Generate model tests:
wheels generate model name=User --properties="email:string,name:string"
wheels generate test model name=User
Troubleshooting
Command Fails with "Invalid model name"
Check that name is not empty:
name=User
Ensure PascalCase format:
name=User
(notname=user
)Use singular form:
name=User
(notname=Users
)Remove special characters:
name=BlogPost
(notname="Blog Post"
)
Properties Not Generated in Migration
Check property format:
properties="name:string,email:string"
Ensure valid property types (see Property Types table above)
Remove extra spaces:
name:string
(notname: string
)Use comma separators:
name:string,email:string
Relationships Not Working
Use PascalCase model names:
belongsTo="User"
(notbelongsTo="user"
)Remove spaces after commas:
belongsTo="User,Category"
Ensure referenced models exist or will be created
Migration Not Generated
Check
--migration=false
wasn't setEnsure you have write permissions in the directory
Verify migration directory exists:
/app/migrator/migrations/
Boolean Parameters Not Working
Use
--flag
forflag=true
:--force
equalsforce=true
Use
--flag=false
for false values:--migration=false
Don't mix syntaxes: Use all flags or all named parameters
See Also
wheels dbmigrate create table - Create migrations
wheels generate property - Add properties to existing models
wheels generate controller - Generate controllers
wheels scaffold - Generate complete CRUD
Last updated
Was this helpful?