Add properties to existing model files.
Synopsis
Copy wheels generate property [name] [options]
wheels g property [name] [options]
Description
The wheels generate property
command generates a database migration to add a property to an existing model and scaffolds it into _form.cfm
and show.cfm
views.
Arguments
Argument
Description
Default
Options
Whether to allow null values
Character or integer size limit for column
Precision value for decimal columns
Scale value for decimal columns
Property Syntax
Copy propertyName:type:option1:option2
Data Type Options
biginteger
- Large integer
boolean
- Boolean (true/false)
decimal
- Decimal numbers
string
- Variable character (VARCHAR)
Examples
String property
Copy wheels generate property user column-name=firstname
Creates a string/textField property called firstname
on the User model.
Boolean property with default
Copy wheels generate property user column-name=isActive data-type=boolean default=0
Creates a boolean/checkbox property with default value of 0 (false).
Datetime property
Copy wheels generate property user column-name=lastloggedin data-type=datetime
Creates a datetime property on the User model.
Decimal property with precision
Copy wheels generate property product column-name=price data-type=decimal precision=10 scale=2
Add calculated property
Copy wheels generate property user "fullName:calculated"
Generated Code Examples
Basic Property Addition
Before:
Copy component extends="Model" {
function init() {
// Existing code
}
}
After:
Copy component extends="Model" {
function init() {
// Existing code
// Properties
property(name="email", sql="email");
// Validations
validatesPresenceOf(properties="email");
validatesUniquenessOf(properties="email");
validatesFormatOf(property="email", regEx="^[^@\s]+@[^@\s]+\.[^@\s]+$");
}
}
Multiple Properties
Command:
Copy wheels generate property product "name:string:required description:text price:float:required:default=0.00 inStock:boolean:default=true"
Generated:
Copy component extends="Model" {
function init() {
// Properties
property(name="name", sql="name");
property(name="description", sql="description");
property(name="price", sql="price", default=0.00);
property(name="inStock", sql="in_stock", default=true);
// Validations
validatesPresenceOf(properties="name,price");
validatesNumericalityOf(property="price", allowBlank=false, greaterThanOrEqualTo=0);
}
}
Association Property
Command:
Copy wheels generate property comment "userId:integer:required:belongsTo=user postId:integer:required:belongsTo=post"
Generated:
Copy component extends="Model" {
function init() {
// Associations
belongsTo(name="user", foreignKey="userId");
belongsTo(name="post", foreignKey="postId");
// Properties
property(name="userId", sql="user_id");
property(name="postId", sql="post_id");
// Validations
validatesPresenceOf(properties="userId,postId");
}
}
Calculated Property
Command:
Copy wheels generate property user fullName:calculated --callbacks
Generated:
Copy component extends="Model" {
function init() {
// Properties
property(name="fullName", sql="", calculated=true);
}
// Calculated property getter
function getFullName() {
return this.firstName & " " & this.lastName;
}
}
Migration Generation
When --migrate=true
(default), generates migration:
Migration File
app/migrator/migrations/[timestamp]_add_properties_to_[model].cfc
:
Copy component extends="wheels.migrator.Migration" hint="Add properties to product" {
function up() {
transaction {
addColumn(table="products", columnName="sku", columnType="string", limit=50, null=false);
addColumn(table="products", columnName="price", columnType="decimal", precision=10, scale=2, null=false, default=0.00);
addColumn(table="products", columnName="stock", columnType="integer", null=true, default=0);
addIndex(table="products", columnNames="sku", unique=true);
}
}
function down() {
transaction {
removeIndex(table="products", columnNames="sku");
removeColumn(table="products", columnName="stock");
removeColumn(table="products", columnName="price");
removeColumn(table="products", columnName="sku");
}
}
}
Validation Rules
Automatic Validations
Based on property type and options:
validatesPresenceOf, validatesLengthOf
validatesFormatOf with email regex
validatesNumericalityOf(onlyInteger=true)
validatesInclusionOf(list="true,false,0,1")
validatesFormatOf with date pattern
Custom Validations
Add custom validation rules:
Copy wheels generate property user "age:integer:min=18:max=120"
Generated:
Copy validatesNumericalityOf(property="age", greaterThanOrEqualTo=18, lessThanOrEqualTo=120);
Property Callbacks
Generate with callbacks:
Copy wheels generate property user lastLoginAt:datetime --callbacks
Generated:
Copy function init() {
// Properties
property(name="lastLoginAt", sql="last_login_at");
// Callbacks
beforeUpdate("updateLastLoginAt");
}
private function updateLastLoginAt() {
if (hasChanged("lastLoginAt")) {
// Custom logic here
}
}
Complex Properties
Enum-like Property
Copy wheels generate property order "status:string:default=pending:inclusion=pending,processing,shipped,delivered"
Generated:
Copy property(name="status", sql="status", default="pending");
validatesInclusionOf(property="status", list="pending,processing,shipped,delivered");
File Upload Property
Copy wheels generate property user "avatar:string:fileField"
Generated:
Copy property(name="avatar", sql="avatar");
// In the init() method
afterSave("processAvatarUpload");
beforeDelete("deleteAvatarFile");
private function processAvatarUpload() {
if (hasChanged("avatar") && isUploadedFile("avatar")) {
// Handle file upload
}
}
JSON Property
Copy wheels generate property user "preferences:text:json"
Generated:
Copy property(name="preferences", sql="preferences");
function getPreferences() {
if (isJSON(this.preferences)) {
return deserializeJSON(this.preferences);
}
return {};
}
function setPreferences(required struct value) {
this.preferences = serializeJSON(arguments.value);
}
Property Modifiers
Encrypted Property
Copy wheels generate property user "ssn:string:encrypted"
Generated:
Copy property(name="ssn", sql="ssn");
beforeSave("encryptSSN");
afterFind("decryptSSN");
private function encryptSSN() {
if (hasChanged("ssn") && Len(this.ssn)) {
this.ssn = encrypt(this.ssn, application.encryptionKey);
}
}
private function decryptSSN() {
if (Len(this.ssn)) {
this.ssn = decrypt(this.ssn, application.encryptionKey);
}
}
Slugged Property
Copy wheels generate property post "slug:string:unique:fromProperty=title"
Generated:
Copy property(name="slug", sql="slug");
validatesUniquenessOf(property="slug");
beforeValidation("generateSlug");
private function generateSlug() {
if (!Len(this.slug) && Len(this.title)) {
this.slug = createSlug(this.title);
}
}
private function createSlug(required string text) {
return reReplace(
lCase(trim(arguments.text)),
"[^a-z0-9]+",
"-",
"all"
);
}
Batch Operations
Copy wheels generate property user "
profile.bio:text
profile.website:string
profile.twitter:string
profile.github:string
" --nested
Add Timestamped Properties
Copy wheels generate property post "publishedAt:timestamp deletedAt:timestamp:nullable"
Integration with Existing Code
Preserve Existing Structure
The command intelligently adds properties without disrupting:
Conflict Resolution
Copy wheels generate property user email:string
> Property 'email' already exists. Options:
> 1. Skip this property
> 2. Update existing property
> 3. Add with different name
> Choice:
Best Practices
Add properties incrementally
Always generate migrations
Include appropriate validations
Use semantic property names
Add indexes for query performance
Consider default values carefully
Document complex properties
Common Patterns
Soft Delete
Copy wheels generate property model deletedAt:timestamp:nullable
Versioning
Copy wheels generate property document "version:integer:default=1 versionedAt:timestamp"
Status Tracking
Copy wheels generate property order "status:string:default=pending statusChangedAt:timestamp"
Audit Fields
Copy wheels generate property model "createdBy:integer:belongsTo=user updatedBy:integer:belongsTo=user"
Testing
After adding properties:
Copy # Run migration
wheels dbmigrate latest
# Generate property tests
wheels generate test model user
# Run tests
wheels test
See Also
Last updated 20 hours ago