LogoLogo
HomeAPIBlog
3.0.0-SNAPSHOT
3.0.0-SNAPSHOT
  • INTRODUCTION
    • Getting Started
      • Running Local Development Servers
      • Beginner Tutorial: Hello World
      • Beginner Tutorial: Hello Database
      • Tutorial: Wheels, AJAX, and You
    • Frameworks and Wheels
    • Requirements
    • Manual Installation
    • Upgrading
    • Screencasts
  • Command Line Tools
    • CLI Overview
    • Quick Start Guide
    • Command Reference
      • Core Commands
        • wheels init
        • wheels info
        • wheels reload
        • wheels deps
        • wheels destroy
        • wheels watch
      • Code Generation
        • 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
      • Database Commands
        • wheels dbmigrate info
        • wheels dbmigrate latest
        • wheels dbmigrate up
        • wheels dbmigrate down
        • wheels dbmigrate reset
        • wheels dbmigrate exec
        • wheels dbmigrate create blank
        • wheels dbmigrate create table
        • wheels dbmigrate create column
        • wheels dbmigrate remove table
        • wheels db schema
        • wheels db seed
      • Testing Commands
        • wheels test
        • wheels test run
        • wheels test coverage
        • wheels test debug
      • Configuration Commands
        • wheels config list
        • wheels config set
        • wheels config env
      • Environment Management
        • wheels env
        • wheels env setup
        • wheels env list
        • wheels env switch
      • Plugin Management
        • wheels plugins
        • wheels plugins list
        • wheels plugins install
        • wheels plugins remove
      • Code Analysis
        • wheels analyze
        • wheels analyze code
        • wheels analyze performance
        • wheels analyze security
      • Security Commands
        • wheels security
        • wheels security scan
      • Performance Commands
        • wheels optimize
        • wheels optimize performance
      • Documentation Commands
        • wheels docs
        • wheels docs generate
        • wheels docs serve
      • CI/CD Commands
        • wheels ci init
      • Docker Commands
        • wheels docker init
        • wheels docker deploy
      • Deployment Commands
        • 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
    • CLI Development Guides
      • Creating Commands
      • Service Architecture
      • Migrations Guide
      • Testing Guide
  • Working with Wheels
    • Conventions
    • Configuration and Defaults
    • Directory Structure
    • Switching Environments
    • Testing Your Application
    • Using the Test Environment
    • Contributing to Wheels
    • Submitting Pull Requests
    • Documenting your Code
  • Handling Requests with Controllers
    • Request Handling
    • Rendering Content
    • Redirecting Users
    • Sending Files
    • Sending Email
    • Responding with Multiple Formats
    • Using the Flash
    • Using Filters
    • Verification
    • Event Handlers
    • Routing
    • URL Rewriting
      • Apache
      • IIS
      • Tomcat
      • Nginx
    • Obfuscating URLs
    • Caching
    • Nesting Controllers
    • CORS Requests
  • Displaying Views to Users
    • Pages
    • Partials
    • Linking Pages
    • Layouts
    • Form Helpers and Showing Errors
    • Displaying Links for Pagination
    • Date, Media, and Text Helpers
    • Creating Custom View Helpers
    • Localization
  • Database Interaction Through Models
    • Object Relational Mapping
    • Creating Records
    • Reading Records
    • Updating Records
    • Deleting Records
    • Column Statistics
    • Dynamic Finders
    • Getting Paginated Data
    • Associations
    • Nested Properties
    • Object Validation
    • Object Callbacks
    • Calculated Properties
    • Transactions
    • Dirty Records
    • Soft Delete
    • Automatic Time Stamps
    • Database Migrations
      • Migrations in Production
    • Using Multiple Data Sources
  • Plugins
    • Installing and Using Plugins
    • Developing Plugins
    • Publishing Plugins
  • Project Documentation
    • Overview
  • External Links
    • Source Code
    • Issue Tracker
    • Sponsor Us
    • Community
Powered by GitBook
LogoLogo
On this page
  • Synopsis
  • Description
  • Arguments
  • Options
  • Available Snippets
  • List All Snippets
  • Authentication Snippets
  • Login Form
  • Authentication Filter
  • Model Patterns
  • Soft Delete
  • Audit Trail
  • Controller Patterns
  • CRUD Actions
  • API Controller
  • View Patterns
  • Form with Errors
  • AJAX Form
  • Database Snippets
  • Migration Indexes
  • Seed Data
  • Custom Snippets
  • Create Custom Snippet
  • Output Options
  • Copy to Clipboard
  • Save to File
  • Interactive Mode
  • Best Practices
  • See Also

Was this helpful?

Edit on GitHub
Export as PDF
  1. Command Line Tools
  2. Command Reference
  3. Code Generation

wheels generate snippets

Generate code snippets and boilerplate code for common patterns.

Synopsis

wheels generate snippets [pattern] [options]
wheels g snippets [pattern] [options]

Description

The wheels generate snippets command creates code snippets for common Wheels patterns and best practices. It provides ready-to-use code blocks that can be customized for your specific needs, helping you implement standard patterns quickly and consistently.

Arguments

Argument
Description
Default

pattern

Snippet pattern to generate

Shows available patterns

Options

Option
Description
Default

--list

List all available snippets

false

--category

Filter by category

All categories

--output

Output format (console, file, clipboard)

console

--customize

Interactive customization

false

--force

Overwrite existing files

false

--help

Show help information

Available Snippets

List All Snippets

wheels generate snippets --list

Output:

Available Snippets:
━━━━━━━━━━━━━━━━━━━

Authentication:
  - login-form          Login form with remember me
  - auth-filter         Authentication filter
  - password-reset      Password reset flow
  - user-registration   User registration with validation

Model Patterns:
  - soft-delete         Soft delete implementation
  - audit-trail         Audit trail with timestamps
  - sluggable          URL-friendly slugs
  - versionable        Version tracking
  - searchable         Full-text search

Controller Patterns:
  - crud-actions       Complete CRUD actions
  - api-controller     JSON API controller
  - nested-resource    Nested resource controller
  - admin-controller   Admin area controller

View Patterns:
  - form-with-errors   Form with error handling
  - pagination-links   Pagination navigation
  - search-form        Search form with filters
  - ajax-form          AJAX form submission

Database:
  - migration-indexes  Common index patterns
  - seed-data         Database seeding
  - constraints       Foreign key constraints

Authentication Snippets

Login Form

wheels generate snippets login-form

Generates:

<!--- views/sessions/new.cfm --->
<h1>Login</h1>

#errorMessagesFor("user")#

#startFormTag(action="create", class="login-form")#
    
    <div class="form-group">
        #textField(
            objectName="user",
            property="email",
            label="Email",
            class="form-control",
            placeholder="email@example.com",
            required=true,
            autofocus=true
        )#
    </div>
    
    <div class="form-group">
        #passwordField(
            objectName="user",
            property="password",
            label="Password",
            class="form-control",
            required=true
        )#
    </div>
    
    <div class="form-group">
        #checkBox(
            objectName="user",
            property="rememberMe",
            label="Remember me",
            value="1"
        )#
    </div>
    
    <div class="form-group">
        #submitTag(value="Login", class="btn btn-primary")#
        #linkTo(text="Forgot password?", route="forgotPassword", class="btn btn-link")#
    </div>
    
#endFormTag()#

<!--- controllers/Sessions.cfc --->
component extends="Controller" {
    
    function new() {
        user = model("User").new();
    }
    
    function create() {
        user = model("User").findOne(where="email='#params.user.email#'");
        
        if (IsObject(user) && user.authenticate(params.user.password)) {
            session.userId = user.id;
            
            if (params.user.rememberMe == 1) {
                cookie.rememberToken = user.generateRememberToken();
                cookie.userId = encrypt(user.id, application.encryptionKey);
            }
            
            flashInsert(success="Welcome back, #user.firstName#!");
            redirectTo(route="dashboard");
        } else {
            user = model("User").new(email=params.user.email);
            flashInsert(error="Invalid email or password.");
            renderView(action="new");
        }
    }
    
    function delete() {
        StructDelete(session, "userId");
        StructDelete(cookie, "rememberToken");
        StructDelete(cookie, "userId");
        
        flashInsert(success="You have been logged out.");
        redirectTo(route="home");
    }
    
}

Authentication Filter

wheels generate snippets auth-filter

Generates:

// In Controller.cfc or specific controller

function init() {
    filters(through="authenticate", except="new,create");
    filters(through="rememberUser", only="new");
}

private function authenticate() {
    if (!isLoggedIn()) {
        storeLocation();
        flashInsert(notice="Please log in to continue.");
        redirectTo(route="login");
    }
}

private function isLoggedIn() {
    return StructKeyExists(session, "userId") && session.userId > 0;
}

private function currentUser() {
    if (!StructKeyExists(request, "currentUser")) {
        if (isLoggedIn()) {
            request.currentUser = model("User").findByKey(session.userId);
        } else {
            request.currentUser = false;
        }
    }
    return request.currentUser;
}

private function rememberUser() {
    if (!isLoggedIn() && StructKeyExists(cookie, "rememberToken")) {
        user = model("User").findOne(
            where="rememberToken='#cookie.rememberToken#' AND rememberTokenExpiresAt > NOW()"
        );
        
        if (IsObject(user)) {
            session.userId = user.id;
            user.updateRememberToken();
        }
    }
}

private function storeLocation() {
    if (request.method == "GET") {
        session.returnTo = request.cgi.path_info;
        if (Len(request.cgi.query_string)) {
            session.returnTo &= "?" & request.cgi.query_string;
        }
    }
}

private function redirectBackOrTo(required string route) {
    if (StructKeyExists(session, "returnTo")) {
        local.returnTo = session.returnTo;
        StructDelete(session, "returnTo");
        redirectTo(location=local.returnTo);
    } else {
        redirectTo(route=arguments.route);
    }
}

Model Patterns

Soft Delete

wheels generate snippets soft-delete

Generates:

// In Model init()
property(name="deletedAt", sql="deleted_at");

// Soft delete callbacks
beforeDelete("softDelete");
afterFind("excludeDeleted");

// Default scope
function excludeDeleted() {
    if (!StructKeyExists(arguments, "includeSoftDeleted") || !arguments.includeSoftDeleted) {
        if (StructKeyExists(this, "deletedAt") && !IsNull(this.deletedAt)) {
            return false; // Exclude from results
        }
    }
}

// Soft delete implementation
private function softDelete() {
    this.deletedAt = Now();
    this.save(validate=false, callbacks=false);
    return false; // Prevent actual deletion
}

// Scopes
function active() {
    return this.findAll(where="deleted_at IS NULL", argumentCollection=arguments);
}

function deleted() {
    return this.findAll(where="deleted_at IS NOT NULL", argumentCollection=arguments);
}

function withDeleted() {
    return this.findAll(includeSoftDeleted=true, argumentCollection=arguments);
}

// Restore method
function restore() {
    this.deletedAt = "";
    return this.save(validate=false);
}

// Permanent delete
function forceDelete() {
    return this.delete(callbacks=false);
}

Audit Trail

wheels generate snippets audit-trail --customize

Interactive customization:

? Include user tracking? (Y/n) › Y
? Track IP address? (y/N) › Y
? Track changes in JSON? (Y/n) › Y

Generates:

// models/AuditLog.cfc
component extends="Model" {
    
    function init() {
        belongsTo("user");
        
        property(name="modelName", sql="model_name");
        property(name="recordId", sql="record_id");
        property(name="action", sql="action");
        property(name="changes", sql="changes");
        property(name="userId", sql="user_id");
        property(name="ipAddress", sql="ip_address");
        property(name="userAgent", sql="user_agent");
        
        validatesPresenceOf("modelName,recordId,action");
    }
    
}

// In audited model
function init() {
    afterCreate("logCreate");
    afterUpdate("logUpdate");
    afterDelete("logDelete");
}

private function logCreate() {
    createAuditLog("create", this.properties());
}

private function logUpdate() {
    if (hasChanged()) {
        createAuditLog("update", this.changedProperties());
    }
}

private function logDelete() {
    createAuditLog("delete", {id: this.id});
}

private function createAuditLog(required string action, required struct data) {
    model("AuditLog").create({
        modelName: ListLast(GetMetaData(this).name, "."),
        recordId: this.id,
        action: arguments.action,
        changes: SerializeJSON(arguments.data),
        userId: request.currentUser.id ?: "",
        ipAddress: request.remoteAddress,
        userAgent: request.userAgent
    });
}

private function changedProperties() {
    local.changes = {};
    local.properties = this.properties();
    
    for (local.key in local.properties) {
        if (hasChanged(local.key)) {
            local.changes[local.key] = {
                from: this.changedFrom(local.key),
                to: local.properties[local.key]
            };
        }
    }
    
    return local.changes;
}

// Audit log migration
component extends="wheels.migrator.Migration" {
    
    function up() {
        createTable(name="audit_logs") {
            t.increments("id");
            t.string("model_name", null=false);
            t.integer("record_id", null=false);
            t.string("action", null=false);
            t.text("changes");
            t.integer("user_id");
            t.string("ip_address");
            t.string("user_agent");
            t.timestamps();
            
            t.index(["model_name", "record_id"]);
            t.index("user_id");
            t.index("created_at");
        };
    }
    
    function down() {
        dropTable("audit_logs");
    }
    
}

Controller Patterns

CRUD Actions

wheels generate snippets crud-actions

Generates complete CRUD controller with error handling, pagination, and filters.

API Controller

wheels generate snippets api-controller

Generates:

component extends="Controller" {
    
    function init() {
        provides("json");
        filters(through="setApiHeaders");
        filters(through="authenticateApi");
        filters(through="logApiRequest", except="index,show");
    }
    
    private function setApiHeaders() {
        header name="X-API-Version" value="1.0";
        header name="X-RateLimit-Limit" value="1000";
        header name="X-RateLimit-Remaining" value=getRateLimitRemaining();
    }
    
    private function authenticateApi() {
        local.token = getAuthToken();
        
        if (!Len(local.token)) {
            renderUnauthorized("Missing authentication token");
        }
        
        request.apiUser = model("ApiKey").authenticate(local.token);
        
        if (!IsObject(request.apiUser)) {
            renderUnauthorized("Invalid authentication token");
        }
    }
    
    private function getAuthToken() {
        // Check Authorization header
        if (StructKeyExists(getHttpRequestData().headers, "Authorization")) {
            local.auth = getHttpRequestData().headers.Authorization;
            if (Left(local.auth, 7) == "Bearer ") {
                return Mid(local.auth, 8, Len(local.auth));
            }
        }
        
        // Check X-API-Key header
        if (StructKeyExists(getHttpRequestData().headers, "X-API-Key")) {
            return getHttpRequestData().headers["X-API-Key"];
        }
        
        // Check query parameter
        if (StructKeyExists(params, "api_key")) {
            return params.api_key;
        }
        
        return "";
    }
    
    private function renderUnauthorized(required string message) {
        renderWith(
            data={
                error: {
                    code: 401,
                    message: arguments.message
                }
            },
            status=401
        );
    }
    
    private function renderError(required string message, numeric status = 400) {
        renderWith(
            data={
                error: {
                    code: arguments.status,
                    message: arguments.message
                }
            },
            status=arguments.status
        );
    }
    
    private function renderSuccess(required any data, numeric status = 200) {
        renderWith(
            data={
                success: true,
                data: arguments.data
            },
            status=arguments.status
        );
    }
    
    private function renderPaginated(required any query) {
        renderWith(
            data={
                success: true,
                data: arguments.query,
                pagination: {
                    page: arguments.query.currentPage,
                    perPage: arguments.query.perPage,
                    total: arguments.query.totalRecords,
                    pages: arguments.query.totalPages
                }
            }
        );
    }
    
}

View Patterns

Form with Errors

wheels generate snippets form-with-errors

AJAX Form

wheels generate snippets ajax-form

Generates:

<!--- View file --->
<div id="contact-form-container">
    #startFormTag(
        action="send",
        id="contact-form",
        class="ajax-form",
        data={
            remote: true,
            method: "post",
            success: "handleFormSuccess",
            error: "handleFormError"
        }
    )#
        
        <div class="form-messages" style="display: none;"></div>
        
        <div class="form-group">
            #textField(
                name="name",
                label="Name",
                class="form-control",
                required=true
            )#
        </div>
        
        <div class="form-group">
            #emailField(
                name="email",
                label="Email",
                class="form-control",
                required=true
            )#
        </div>
        
        <div class="form-group">
            #textArea(
                name="message",
                label="Message",
                class="form-control",
                rows=5,
                required=true
            )#
        </div>
        
        <div class="form-group">
            #submitTag(
                value="Send Message",
                class="btn btn-primary",
                data={loading: "Sending..."}
            )#
        </div>
        
    #endFormTag()#
</div>

<script>
// AJAX form handler
document.addEventListener('DOMContentLoaded', function() {
    const form = document.getElementById('contact-form');
    
    form.addEventListener('submit', function(e) {
        e.preventDefault();
        
        const submitBtn = form.querySelector('[type="submit"]');
        const originalText = submitBtn.value;
        const loadingText = submitBtn.dataset.loading;
        
        // Disable form
        submitBtn.disabled = true;
        submitBtn.value = loadingText;
        
        // Send AJAX request
        fetch(form.action, {
            method: form.method,
            body: new FormData(form),
            headers: {
                'X-Requested-With': 'XMLHttpRequest'
            }
        })
        .then(response => response.json())
        .then(data => {
            if (data.success) {
                handleFormSuccess(data);
            } else {
                handleFormError(data);
            }
        })
        .catch(error => {
            handleFormError({message: 'Network error. Please try again.'});
        })
        .finally(() => {
            submitBtn.disabled = false;
            submitBtn.value = originalText;
        });
    });
});

function handleFormSuccess(data) {
    const form = document.getElementById('contact-form');
    const messages = form.querySelector('.form-messages');
    
    // Show success message
    messages.className = 'form-messages alert alert-success';
    messages.textContent = data.message || 'Message sent successfully!';
    messages.style.display = 'block';
    
    // Reset form
    form.reset();
    
    // Hide message after 5 seconds
    setTimeout(() => {
        messages.style.display = 'none';
    }, 5000);
}

function handleFormError(data) {
    const form = document.getElementById('contact-form');
    const messages = form.querySelector('.form-messages');
    
    // Show error message
    messages.className = 'form-messages alert alert-danger';
    messages.textContent = data.message || 'An error occurred. Please try again.';
    messages.style.display = 'block';
    
    // Show field errors
    if (data.errors) {
        Object.keys(data.errors).forEach(field => {
            const input = form.querySelector(`[name="${field}"]`);
            if (input) {
                input.classList.add('is-invalid');
                const error = document.createElement('div');
                error.className = 'invalid-feedback';
                error.textContent = data.errors[field].join(', ');
                input.parentNode.appendChild(error);
            }
        });
    }
}
</script>

<!--- Controller action --->
function send() {
    contact = model("Contact").new(params);
    
    if (contact.save()) {
        if (isAjax()) {
            renderWith(data={
                success: true,
                message: "Thank you! We'll be in touch soon."
            });
        } else {
            flashInsert(success="Thank you! We'll be in touch soon.");
            redirectTo(route="home");
        }
    } else {
        if (isAjax()) {
            renderWith(data={
                success: false,
                message: "Please correct the errors below.",
                errors: contact.allErrors()
            }, status=422);
        } else {
            renderView(action="new");
        }
    }
}

Database Snippets

Migration Indexes

wheels generate snippets migration-indexes

Generates common index patterns:

// Performance indexes
t.index("email"); // Single column
t.index(["last_name", "first_name"]); // Composite
t.index("created_at"); // Timestamp queries

// Unique constraints
t.index("email", unique=true);
t.index(["user_id", "role_id"], unique=true);

// Foreign key indexes
t.index("user_id");
t.index("category_id");

// Full-text search
t.index("title", type="fulltext");
t.index(["title", "content"], type="fulltext");

// Partial indexes (PostgreSQL)
t.index("email", where="deleted_at IS NULL");

// Expression indexes
t.index("LOWER(email)", name="idx_email_lower");

Seed Data

wheels generate snippets seed-data

Custom Snippets

Create Custom Snippet

wheels generate snippets --create=my-pattern

Creates template in ~/.wheels/snippets/my-pattern/:

my-pattern/
├── snippet.json
├── files/
│   ├── controller.cfc
│   ├── model.cfc
│   └── view.cfm
└── README.md

snippet.json:

{
    "name": "my-pattern",
    "description": "Custom pattern description",
    "category": "custom",
    "author": "Your Name",
    "version": "1.0.0",
    "variables": [
        {
            "name": "modelName",
            "prompt": "Model name?",
            "default": "MyModel"
        }
    ],
    "files": [
        {
            "source": "files/controller.cfc",
            "destination": "controllers/${controllerName}.cfc"
        }
    ]
}

Output Options

Copy to Clipboard

wheels generate snippets login-form --output=clipboard

Save to File

wheels generate snippets api-controller --output=file --path=./controllers/Api.cfc

Interactive Mode

wheels generate snippets --customize

Best Practices

  1. Review generated code: Customize for your needs

  2. Understand the patterns: Don't blindly copy

  3. Keep snippets updated: Maintain with framework updates

  4. Share useful patterns: Contribute back to community

  5. Document customizations: Note changes made

  6. Test generated code: Ensure it works in your context

  7. Use consistent patterns: Across your application

See Also

Previouswheels generate testNextwheels scaffold

Last updated 2 days ago

Was this helpful?

- Generate controllers

- Generate models

- Generate complete resources

wheels generate controller
wheels generate model
wheels scaffold