Archive for the ‘Community’ Category


Creating a Basic CRUD Interface with Wheels 3.0

Accompanying Video

This blog post has an accompanying video posted to YouTube.

Welcome to the next installment in our Wheels 3.0 tutorial series! Today, we’ll guide you through creating a basic CRUD (Create, Read, Update, Delete) interface using the Wheels CLI. If you’re just joining us and don’t have the Wheels CLI installed yet, be sure to catch up with our previous video detailing the setup of your development environment.

Setting Up Your Wheels Project

To get started, we activate the `WHEELS NEW` command, which launches a wizard designed to help us build a new Wheels project efficiently. First, provide a name for your application—I’ll be using “myapp” as the demonstration name.

During the setup, you’ll be prompted to select which Wheels version to install, and we’ll choose the second option for Wheels 3.0. For development purposes, we’ll leave the reload password empty, but remember to set a secure password before moving to production. Next, the wizard will ask for a datasource name, which defaults to our application name and suits our needs.

You’ll then be asked to select a CFML engine for deployment, and we’ll stick with the default, the latest version of Lucee. Since we opted for the Lucee engine, it offers the use of a built-in H2 database—a great development option that avoids setting up a separate database server. We’ll go ahead and select “yes” to use it.

You’ll have the option to include the Bootstrap CSS framework to enhance the appearance of your app. Finally, decide whether you want a box.json file for uploading the project to Forgebox.io. For this project, I’ll choose “no.”

After confirming our settings, the wizard will download the specified 3.0 template, along with any necessary dependencies, setup the H2 database, integrate Bootstrap, and start the server. Once the installation is complete, we can explore what’s been set up.

Exploring the CLI Setup

The CLI generates a default Wheels installation skeleton, which it modifies based on our inputs, such as updating configuration files and creating essentials like the URL rewrite file and a server.json file.

Upon successful installation, the confirmation screen assures us with a set of configurations displayed on the Info tab. This includes details like application and datasource names, and confirms the H2 database driver installation with the ready-to-use datasource.

Creating a User Model

Now, it’s time to create users through the CLI. In CommandBox, we use the `wheels scaffold` command to begin creating a User model. We’ll bypass the database migration initially but note how this step has generated skeleton view files, a model file, and a controller in the app. This default setup is crucial for the business logic and user interactions.

To give the user model some structure, we use the command line to add properties like first name, last name, and email to the User model, although we’ll skip database migrations for these incremental property additions.

Consolidating Migration Files

Before executing database migrations, it’s wise to consolidate the migration files generated. Inside the app’s migrator/migrations folder are several CFC files. We aim to merge these into a single file, ensuring the `up` and `down` functions are properly matched—creating a table in `up` and dropping it in `down`.

Once consolidated, enhance the migration script by adding string-based columns for first and last names with a character limit, and a longer limit for emails, ensuring database integrity and conformity.

Running Migrations

Migrations can be executed via the CLI or the application’s user interface. Using the UI, navigate to the Migrator tab and run the migrations in sequence or opt for ‘Migrate to Latest’ to process all migrations.

Given that model configurations are cached, reload the application post-migration to let the framework update model configurations based on new database structures.

Finalizing the Application

Lastly, make the User index the default application page rather than the Congratulations page. Modify the routes.cfm file to direct URLs to the users index route by default. Reload the application to apply this routing change, and upon revisiting the default route, the Users page should now load by default.

This tutorial concludes our hands-on exploration of CRUD interface creation in Wheels 3.0 using CLI. We covered project setup, database configuration, scaffolding models, property additions, migration management, and front-end interfacing—all culminating in a functional application displaying user data.

Wheels 3.0: Setting Up Your Development Environment

Accompanying Video

This blog post has an accompanying video posted to YouTube.

Introduction

The forthcoming release of the Wheels 3.0 framework is creating waves in the development community, promising transformative enhancements and simplified workflows. In this blog post, we will focus on establishing the foundational environment crucial for executing Wheels projects efficiently. We’ll guide you through project creation using both the current and the upcoming 3.0 versions of the framework and will explore the differences in their directory structures. Let’s dive right in!

Installing CommandBox

The cornerstone of our setup is CommandBox, a versatile tool that modernizes the CFML developer’s workflow. CommandBox serves as a command line shell, a package manager, and a seamless interface to start a CFML engine in any given directory, without the need to juggle complex application server installations. CommandBox is accessible for Mac, Windows, and Linux OS, with installation methods varying accordingly. For Mac users like me, Homebrew is the chosen method for installation, while Windows users can turn to Chocolaty or a native installer, and Linux enthusiasts can rely on built-in package managers.

CommandBox and Wheels CLI Setup

Once CommandBox is installed, jump into the CommandBox shell via the `BOX` command in the terminal window. Note that the first launch involves downloading several packages which could take some time. Following the setup, install the Wheels CLI commands into CommandBox using `INSTALL WHEELS-CLI`. Although I’ve already completed this step earlier, executing this ensures you are equipped with the right tools to proceed.

Creating Projects with Wheels

With CommandBox ready, embark on creating two projects using the `WHEELS NEW` command. This command initiates a wizard that will actively guide you through the process of setting up a new Wheels project.

1. Creating a Current Version Project

  • Naming the Project: First, supply a name for the project, for instance, “CURRENT”, which creates a directory embodying the project files.
  • Template Selection: Choose the template corresponding to the current version and proceed with the default options.
  • Project Initialization: Conclude the process with a “Yes” to affirm configuration and initiate project setup. The CLI will create the project directory and integrate necessary files. Launch the server with `START` and witness the “Congratulations” page, assuring correct installation.

2. Creating a Wheels 3.0 Version Project

  • Naming the Project: Again, deploy `WHEELS NEW` to name your project.
  • Template Selection: This time, select the “Bleeding Edge” template for a Wheels 3.0 implementation. Confirm defaults and proceed to build your project.
  • Project Initialization: Use the `START` command to usher in a new CFML application server, culminating in a fresh “Congratulations” page highlighting the new branding and 3.0 framework base.

Exploring Directory Structures

A crucial step is to delve into the structural differences between the two projects:

  • Current Version: This project exhibits a larger assortment of directories and files at its root, which poses an increased potential attack surface.
  • Wheels 3.0: The new framework refines this exposure significantly, only housing four directories at the root. Key directories like config, controllers, and views reside under the `app` directory, while static resources like images and stylesheets find home under the `public` directory. The `vendor` directory now accommodates core framework files, enhancing security by mapping only the public folder to the webroot of the application server.

Conclusion

Setting up an environment for Wheels 3.0 marks the beginning of an exciting journey in CFML development. From installing CommandBox to exploring framework nuances, we have geared up for advanced Wheels projects.

Celebrating 20 Years of CFWheels: A Look Back and a Step Forward as Wheels.dev

As we ring in the new year, we’re thrilled to celebrate a monumental milestone: 20 years of CFWheels! This anniversary isn’t just a celebration of two decades of innovation, growth, and community; it’s also a moment to embrace the future with a new name—Wheels.dev.

A Legacy of Innovation

When CFWheels Beta was launched in 2005, the web development world was a vastly different place. ColdFusion was a dominant force, and frameworks like Rails were just beginning to reshape how developers approached web application development. Inspired by Rails, CFWheels set out to bring the same elegance and productivity to ColdFusion developers, becoming one of the first MVC frameworks in the ColdFusion ecosystem.

Over the years, CFWheels has empowered countless developers to build robust, maintainable web applications. Its commitment to simplicity, convention over configuration, and an active community made it a go-to choice for many.

The Community: The Heart of CFWheels

None of this would have been possible without you—the community. From contributors who improved the framework, to developers who adopted it for their projects, to those who joined discussions and shared knowledge—you are the reason CFWheels has thrived for 20 years.

Your passion and dedication have shaped the framework into what it is today. As we move forward, the community remains at the heart of everything we do.

Why the Name Change?

After two decades, the web development landscape has evolved dramatically, and so have we. While ColdFusion remains a core technology, the framework has grown to be more versatile and forward-thinking. The name Wheels.dev reflects this evolution:

  • Broader Appeal: The new name positions Wheels as a modern, technology-agnostic framework that’s ready to integrate with emerging technologies.
  • Simplicity and Clarity: “Wheels.dev” is concise, memorable, and speaks to developers everywhere.
  • Future-Proofing: This change signifies our commitment to staying relevant and adaptable in the ever-changing web development world.

What’s Next for Wheels.dev?

The transition to Wheels.dev is more than just a rebranding—it’s a signal of exciting changes to come. Here’s a glimpse at what’s ahead:

  • Revamped Directory Structure: The application directory structure has been modernized to adhere to best practices and more secure.
  • Enhanced Documentation: A revamped website with improved documentation to make onboarding and learning easier than ever.
  • Modern Features: Continued updates that embrace modern development practices, including support for APIs, cloud deployments, and integrations with other technologies.
  • Community Engagement: More opportunities to connect with fellow developers through forums, meetups, and contributions.

Looking Back, Moving Forward

As we celebrate 20 years of innovation, we’re filled with gratitude for everything the CFWheels journey has brought us. At the same time, we’re excited to step into the future as Wheels.dev.

To our community, past and present: thank you for believing in us, contributing to the framework, and building incredible projects with CFWheels. Together, we’ve created something truly special, and the best is yet to come.

Here’s to the next chapter as Wheels.dev—building faster, smarter, and together!

Stay connected: We will be building out the new site at Wheels.dev over the next few weeks, explore the new site and learn more about what’s ahead.

Building search forms with tableless models in CFWheels

This blog article was originally posted on Chris’ personal blog and is republished here with his permission.

In this post, I hope to persuade you that you will rarely ever need the Tag-based form helpers (textFieldTagselectTag, etc.) in your CFWheels apps ever again.

“How?” you ask.

The answer: through the use of a wonderful feature that we affectionately call tableless models.

How you’re probably used to coding search forms in CFWheels

So let’s code up an index form using the Tag-based helpers that you’re probably accustomed to using in this situation. The view’s job is to display a list of invoice records along with a form for narrowing by start date and end date:

<cfoutput>

#startFormTag(route="invoices", method="get")#
  #textFieldTag(name="startDate", value=params.startDate)#
  #textFieldTag(name="endDate", value=params.endDate)#
  #submitTag(value="Filter Invoices")#
#endFormTag()#

<table>
  <thead>
    <tr>
      <th>Invoice</th>
      <th>Date</th>
      <th>Amount</th>
    </tr>
  </thead>
  <tbody>
    <cfloop query="invoices">
      <tr>
        <td>#h(id)#</td>
        <td>#DateFormat(createdAt)#</td>
        <td>#DollarFormat(amount)#</td>
      </tr>
    </cfloop>
  </tbody>
</table>

</cfoutput>

This is pretty common, and I wouldn’t go as far to say that it’s wrong.

Let’s code what we need in the controller to wire everything up.

component extends="Controller" {
  function index() {
    param name="params.startDate" default="";
    param name="params.endDate" default="";
    
    local.where = [];
    
    if (IsDate(params.startDate)) {
      ArrayAppend(local.where, "createdAt >= '#params.startDate#'");
    }
    
    if (IsDate(params.endDate)) {
      local.nextDay = DateAdd("d", 1, params.endDate);
      local.nextDay = DateFormat(local.nextDay, "m/d/yyyy");
      ArrayAppend(local.where, "createdAt < '#local.nextDay#'");
    }
    
    invoices = model("invoice").findAll(where=ArrayToList(local.where, " AND "));
  }
}

But wait! We can’t have a startDate that occurs after the endDate. We better add a check for that in the controller:

component extends="Controller" {
  function index() {
    param name="params.startDate" default="";
    param name="params.endDate" default="";
    
    local.where = [];
    
    // Let's make sure the start date and end date jive.
    if (IsDate(params.startDate) && IsDate(params.endDate) && params.startDate > params.endDate) {
      flashInsert(error="The start date must be on or before the end date.");
    }
    
    if (IsDate(params.startDate)) {
      ArrayAppend(local.where, "createdAt >= '#params.startDate#'");
    }
    
    if (IsDate(params.endDate)) {
      local.nextDay = DateAdd("d", 1, params.endDate);
      local.nextDay = DateFormat(local.nextDay, "m/d/yyyy");
      ArrayAppend(local.where, "createdAt < '#local.nextDay#'");
    }
    
    invoices = model("invoice").findAll(where=ArrayToList(local.where, " AND "));
  }
}

That index action is getting pretty beefy at this point. And now we’re starting to validate our data in the controller, which can quickly turn into a tangled mess after we’ve added another field or two to the form.

Cleaning up the search form with tableless models

As it turns out, models in CFWheels come with a bunch of really helpful methods for validating data. And even though we’re not using this form to save data to a database, we can still use the model validations to validate our data. Hooray!

All that we need to do is create a CFC in our models folder that represents this particular form. The initializer will contain a call to table(false), which tells CFWheels to not try to connect it to a database.

In addition to table(false), we can call all of the model validation initializers that we need to validate the data.

Lastly, we need to create a method that validates data passed into the model and runs the query if all is well.

Here is the finished product in models/InvoiceSearchForm.cfc:

component extends="Model" {
  function config() {
    // Make it tableless
    table(false);
    
    // Validations
    validatesFormatOf(properties="startDate,endDate", type="date", allowBlank=true);
    validate("startDateBeforeEndDateValidation");
  }
  
  boolean function run() {
    // Run validations and abort if failed.
    if (!this.valid()) {
      this.results = QueryNew("");
      return false;
    }
    
    // Continue with query if validation passed.
    local.where = [];
    
    if (IsDate(this.startDate)) {
      ArrayAppend(local.where, "createdAt >= '#this.startDate#'");
    }
    
    if (IsDate(this.endDate)) {
      local.nextDay = DateAdd("d", 1, this.endDate);
      local.nextDay = DateFormat(local.nextDay, "m/d/yyyy");
      ArrayAppend(local.where, "createdAt < '#local.nextDay#'");
    }
    
    this.results = model("invoice").findAll(where=ArrayToList(local.where, " AND "));
    return true;
  }
  
  private function startDateBeforeEndDateValidation() {
    if (IsDate(this.startDate) && IsDate(this.endDate) && this.startDate > this.endDate) {
      this.addError("startDate", "Start Date must be on or before End Date");
    }
  }
}

Notice that startDate and endDate become properties on the model in the this scope. This allows us to validate those properties and refer to them in an object-oriented manner.

When the run method is called, there will be a results property set on the object containing the search query.

Next, we rewire the controller to this much simpler form:

component extends="Controller" {
  function index() {
    // Note that moving this into an object named `search` will change the
    // `params` struct slightly.
    param name="params.search.startDate" default="";
    param name="params.search.endDate" default="";
    
    // We pass the `params.search` struct in as properties on the search form
    // object.
    search = model("invoiceSearchForm").new(argumentCollection=params.search);
    
    // This runs the search and adds an error message if validation fails.
    if (!search.run()) {
      flashInsert(error="There was an error with your search filters");
    }
  }
}

Much cleaner, huh? Excluding whitespace and comments, this reduces the contents of the index action from 16 lines of actual code to 5.

This methodology also improves the view because we can now use textField instead of textFieldTag, and we can display validation errors near the affected form fields:

<cfoutput>

#startFormTag(route="invoices", method="get")#
  #textField(objectName="search", property="startDate")#
  #errorMessageOn(objectName="search", property="startDate")#
  
  #textField(objectName="search", property="endDate")#
  #errorMessageOn(objectName="search", property="endDate")#
  
  #submitTag(value="Filter Invoices")#
#endFormTag()#

<table>
  <thead>
    <tr>
      <th>Invoice</th>
      <th>Date</th>
      <th>Amount</th>
    </tr>
  </thead>
  <tbody>
    <cfloop query="search.results">
      <tr>
        <td>#h(id)#</td>
        <td>#DateFormat(createdAt)#</td>
        <td>#DollarFormat(amount)#</td>
      </tr>
    </cfloop>
  </tbody>
</table>

</cfoutput>

As a bonus, our InvoiceSearchForm model allows us to do things like set the labels/error message labels on the form fields using property, and allows us to do most of what models allow us to do: namely validations and callbacks.

component extends="Model" {
  function config() {
    table(false);
    
    // Set property labels for form fields and related error messages.
    property(name="startDate", label="Start");
    property(name="endDate", label="End");
    
    //...
  }

  //...
}

I find this to be a nice pattern because it ties the form to the model in a fairly clean, object-oriented way: the model represents the form, so it makes sense for it to define how labels on the form should appear.

Other uses for tableless models

Here are some other ideas where tableless models are a Good Idea™:

Authentication forms
The model takes care of all authentication logic.

Password change/reset forms
Move interface-based concepts like validatesConfirmationOf out of the table-based user model and into a tableless model.

Database transactions involving multiple models
Nested properties have their limits and logic related to them can really pollute your table-based models. Handle all of the logic in a model that’s intimately involved with the form.

Reports
Have you ever found yourself in a situation where you needed to run a query involving multiple database tables, but it was unclear which model to write the query in? Tableless models are a perfect way to avoid making a random decision.

NoSQL and API integration
Are you saving your data somewhere other than a relational database? You can still model the business logic using CFWheels models.

Props

Most of this inspiration came from a similar concept known as Form Objects in Ruby on Rails. (There is a great Railscast about Form Objectshere too.)

Also, major kudos to Tony Petruzzi for adding this awesome feature into CFWheels, which made its way into the v1.3 release.

CFWheels v2.5.0 Released

This is a major milestone release of CFWheels v2.5.0 that has been in the works for over a year. As you can see nearly 34 PRs have been merged into the codebase which include many enhancements and bug fixes. In addition many changes have been made to the tooling used in the project.

Here are some of the highlights:

  • We have begun to publish SNAPSHOTS to ForgeBox.io on each successful commit to the develop branch.
  • The GitHub Actions CI scripts use the same configuration files as the local Docker testing suite. If you are inclined to contribute to the CFWheels project you will most likely want to be able to run the test suite locally in Docker containers to test your changes before you submit a PR. To run the local test suite simply type docker compose up in the root of your project. The source code is injected into the containers dynamically so it makes it easier to make changes and see them appear in the docker containers without rebuilding the containers. Look for more details on this to come in the future.
  • Every commit is now tested across a matrix of 20 combinations of CF Engines and Databases. The matrix includes CF Engines (Lucee 5, Lucee 6, Adobe ColdFusion 2016, Adobe ColdFusion 2018, Adobe ColdFusion 2021, and Adobe ColdFusion 2023) and databases (H2, MS SQL Server, PostgreSQL, and MySQL).
  • Each successful commit automatically builds two packages on ForgeBox. One for the default template and one for the core CFWheels folder.

Upgrading an Existing Project

The changes in this version are confined to the wheels directory so simply swapping out your wheels directory should be all you need to do to upgrade.

Changelog

Model Enhancements

  • PR-1183-Allow datasource argument in finders #1183 – [Adam Chapman]
  • PR-1201-Issue ORM create() fails object validation for not null columns with defaults #929 validate not nullable columns with default #1201 – [Adam Chapman]
  • PR-1202-Remove old oracle test workaround #1202 – [Adam Chapman]
  • PR-1205-issue-1182-adds-simplelock-to-sql-caching #1205 – [Adam Chapman]
  • PR-1222-Findall() performance bottleneck #1222 – [Adam Chapman]
  • PR-1223-refactor-queryCallback-with-inbuilt-query-functions #1223 – [Adam Chapman]
  • PR-1226-Invalid column not throwing exception in select argument #1226 – [Zain Ul Abideen]
  • PR-1265-improve-performance-refactor-out-listfind #1265 – [Adam Chapman]
  • PR-1260-Adds support for native query returnType #1260 – [Adam Chapman]
  • PR-1249-Removed the original IF/ELSE condition that invalidates calculated props and added condition #1240 – [Zain Ul Abideen]

View Enhancements

  • PR-1254-issue 908 enable paginationLinks() to set active class on parent #1254 – [Zain Ul Abideen]

Bug Fixes

  • PR-1227-Return a numeric value if the primary key is Numeric #1227 – [Zain Ul Abideen]
  • PR-1257-Checkbox bug when checkedvalue is not true #1257 – [Adam Chapman]
  • PR-1246-set the default route if it is not passed in the function #1246 – [Zain Ul Abideen]
  • PR-1256-issue 889 unable to duplicate component #1256 – [Zain Ul Abideen]
  • PR-1253-Issue 580 select ambiguous column name using the wheels alias #1253 – [Zain Ul Abideen]
  • PR-1245-Added afterFind callback hook in the findAll function in case of structs #1245 – [Zain Ul Abideen]
  • PR-1302-Check for Reload Password when setting a url IP exception #1302 – Peter Amiri

Miscellaneous

  • PR-1175-restoreTestRunnerApplicationScope setting #1175 – [Adam Chapman]
  • PR-1176-fix text in core readme file #1176 – [Per Djurner]
  • PR-1177-fix text in base template readme file #1177 – [Per Djurner]
  • PR-1178-fix text in default template file #1178 – [Per Djurner]
  • PR-1185-adds-root-docker-volume #1185 – [Adam Chapman]
  • PR-1200-Update the docker-compose command to docker compose v2 syntax #1200 – [Adam Chapman, Peter Amiri]
  • PR-1204-Add Lucee 6 to test matrix on local Docker test suite #1204 – [Peter Amiri]
  • PR-1203-ensure testing params maintained #1203 – [Adam Chapman]
  • PR-1228-Adding addClass attribute in the function textField #1228 – [Zain Ul Abideen]
  • PR-1230-Add Adobe 2021 Support to local Docker and GitHub Actions testing – #1230 – Peter Amiri
  • PR-1264-update Lucee 6 version used for tests to latest #1264 – [Zac Spitzer – * New Contributor *]
  • PR-1241-Fix spelling and remove whitespace from link #1241 – [John Bampton]
  • PR-1247-show the current git branch in the debug layout #1247 – [Michael Diederich]
  • PR-1250-Added test framework functions in the docs #1250 – [Zain Ul Abideen]
  • PR-1255-issue 1179 Downloaded the CDN files and changed paths in files #1255 – [Zain Ul Abideen]

Guides

  • PR-1198-Documentation-fixes #1198 – [Adam Chapman]

Download Zip File

CFWheels on CF Alive the Sequel

Back in February of 2019 David Belanger and Tom King from the CFWheels core team sat down with Michaela Light on the ColdFusion Alive Podcast to have a chat about CFWheels. A few weeks ago Peter Amiri had a chance to speak to Michaela Light about recent developments in the CFWheels community, how to contribute to the project, and the road map ahead.

Episode 122 of the ColdFusion Alive Podcast

You can view the episode notes on the TeraTech website.

The CFWheels Channel on CFML Slack Has Been Archived

Back in May 2022 we posted a blog article announcing that CFWheels has moved to GitHub Discussions. At the time this effected the retirement of the Google mailing list and redirecting the links on the home page to the new GitHub Discussions site. Now the time has come to also retire the CFWheels channel on the CFML Slack instance.

Feel free to go back and read the original post from May that laid out the reasoning for this move but we thought it was important to reiterate our thought process once again. At the core, the reasons for this move are to move our discussions closer to the code, allowing the poster and respondent to more easily link to specific branches, files, and even lines of code. Issues can be converted to discussions if they warrant further community input or discussions promoted to an issue once an issue or feature has had open consultation and next steps identified. Discussions can be marked as answered and the specific answer identified for future reference. And most importantly, all these discussions, collaborations, and consultations are searchable and discoverable by search engines so the community as a whole reaps the benefits.

We have seen how the move to GitHub discussions by other open source communities has benefited their community and brought their discussions closer to the codebase. We hope this move by us will be similarly fruitful.

CFWheels v2.4.0 Released

This version is the accumulation of bug fixes and minor enhancements over the last quarter. This release welcomes John Bampton and Coleman Sperando, two first time contributors to the project.

Download Zip

If updating from CFWheels 2.3.x:

It should be an easy upgrade, just swap out the wheels folder.

If you installed CFWheels with CommandBox and have a box.sjon file:

Enter install cfwheels in the root of your site to update your wheels folder to the latest.

Changelog

Bug Fixes

  • issue-1091-wheels-paths-in-error-template #1091 – [Adam Chapman]
  • issue-1082-validations should not trim properties #1082 – [Adam Chapman]
  • issue-1088-Adds SQL parsing regex tweak which correctly handles whitespace #1088 – [Adam Chapman, Adam Cameron]

Miscellaneous

  • Adds cfformat ignore marker comments around core “view” cfm files that contain html markup – [Adam Chapman]
  • Adds the ability to scroll large items horizontally in the test runner UI #1130 – [Adam Chapman]
  • Fix cfformat ignore markers #1129 – [Adam Chapman]
  • Enable finder model methods to returnAs “sql”, mainly for debugging #1141 – [Adam Chapman]
  • Show the Test Runner buttons in the CFWheels GUI on the Package List screen allowing the developer to run the entire test suite instead of one package at a time. – [Peter Amiri]
  • The Base Template now contains all necessary placeholders for the CLI to interact with the application and be able to inject code properly. – [Peter Amiri]
  • By default the Core tests will run in the application datasource, but the developer can setup a different database for running the Core tests to ensure there is no side effects from running the tests. If you do end up setting a different database for the coreTestDatasourceName, make sure to reload your application after running the Core tests. – [Peter Amiri]
  • Fix two broken links in README. [#1150] – [John Bampton – * New Contributor *]
  • Fix spelling [#1151][#1158] – [John Bampton – * New Contributor *]
  • Add .env parser to parse .env files and add the properties found in the file to this.env scope. #1157 – [Peter Amiri]
  • Update the local test suite to supported ARM architecture docker images to make the suite compatible with the Apple Silicon Macs. #1143 – [Peter Amiri]

Guides

  • Fix broken links throughout the guides. – [Peter Amiri]
  • Fixed mailto link in CONTRIBUTING.md #1123 – [Coleman Sperando * New Contributor *]
  • Fix test guides examples #1125 [Adam Chapman]
  • Fix typos in the guides #1161 [Adam Chapman]

Wheels CLI matures to Version 1.0

It’s hard to believe it took so long to get here but modern CFML development has come a long way thanks to tools like CommandBox and ForgeBox. The Wheels CLI is built as a CommandBox module and wouldn’t have even been possible without the support of the fine folks at Ortus Solutions.

The first commit to the repo for this project was committed back in July of 2016. It’s taken a while, that’s an understatement, to get here but Wheels itself jumped to 2.0, CommandBox matured, and we were able to put the plumbing in place to support the communication between the CLI and the running server. With nearly 300 commits in the repo, 25 commands in the CLI, and over 20 pages of documentation, it’s now time to take the alpha/beta label off send this baby out into the world.

Some of the more notable commands are wheels new to use our wizard to start a brand new project. With this command and the corresponding wheels generate app command, you can start a new Wheels project in a directory, specify the template to use, pick the CF engine to use, configure the datasource, and setup your reload password. In fact there’s a whole host of generate commands for every type of object you may want to create. There are a bunch of dbmigrate commands to interact with database migrations.

To install the CLI issue the following command:

box install cfwheels-cli

Don’t forget to check out the full CLI Commands section in the guides too.

CFWheels Added to the htmx Server-Side Examples Page

Back in March we published an example app where we took the TodoMVC spec and built a reference implementation of the app with CFWheels and htmx. Here is a quick graphic of the UI of the app.

Todo app implemented with CFWheels and htmx

This app has now been added to the list of Server-Side integration examples on the htmx website.

htmx at it’s core is html over the wire. Instead of returning JSON from backend APIs and consuming them with Javascript to build page interactivity, htmx takes a different approach. It expects actual html snippets to be returned that are swapped into the DOM. How it does it, is by extending html with a handful of additional attributes, that probably should have been there in the first place, which enable any HTML element to issue an AJAX call to the backend, specify what triggers the call, and specify how the returned HTML should be added to the DOM.

We’ll be doing more with HTMX in the future so it’s great to get CFWheels on the radars of the htmx project.