Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Install CFWheels and get a local development server running
By far the quickest way to get started with CFWheels is via CommandBox. CommandBox brings a whole host of command line capabilities to the CFML developer. It allows you to write scripts that can be executed at the command line written entirely in CFML. It allows you to start a CFML server from any directory on your machine and wire up the code in that directory as the web root of the server. What's more is, those servers can be either Lucee servers or Adobe ColdFusion servers. You can even specify what version of each server to launch. Lastly, CommandBox is a package manager for CFML. That means you can take some CFML code and package it up into a module, host it on ForgeBox.io, and make it available to other CFML developers. In fact we make extensive use of these capabilities to distribute CFWheels plugins and templates. More on that later.
One module that we have created is a module that extends CommandBox itself with commands and features specific to the CFWheels framework. The CFWheels CLI module for CommandBox is modeled after the Ruby on Rails CLI module and gives similar capabilities to the CFWheels developer.
The first step is to get CommandBox downloaded and running. CommandBox is available for Windows, Mac & Linux, and can be installed manually or using one of the respective package managers for each OS. You can use Chocolatey on Windows, Homebrew on MacOS, or Yum/Apt on Linux depending on your flavor of Linux. Please follow the instructions on how to install CommandBox on your particular operating system. At the end of the installation process you want to make sure the box
command is part of your system path so you can call the command from any directory on your system.
Once installed, you can either double-click on the box
executable which opens the CommandBox shell window, or run box
from a CMD window in Windows, Terminal window in MacOS, or shell prompt on a Linux server. Sometimes you only want to call a single CommandBox command and don't need to launch a whole CommandBox shell window to do that, for these instances you can call the CommandBox command directly from your default system terminal window by prefixing the command with the box
prefix.
So to run the CommandBox version
command you could run box version from the shell or you could launch the CommandBox shell and run version inside it.
box version
version
This is a good concept to grasp, cause depending on your workflow, you may find it easier to do one versus the other. Most of the commands you will see in these CLI guides will assume that you are entering the command in the actual CommandBox shell so the box
prefix is left off.
Okay, now that we have CommandBox installed, let's add the CFWheels CLI module.
install wheels-cli
Installing this module will add a number of commands to your default CommandBox installation. All of these commands are prefixed by the wheels
name space. There are commands to create a brand new CFWheels application or scaffold out sections of your application. We'll see some of these commands in action momentarily.
To install a new application using version 3.0, we can use the new application wizard and select Bleeding Edge when prompted to select the template to use.
wheels new
Now that we have CommandBox installed and extended it with the Wheels CLI module, let's start our first Wheels app from the command line. We'll look at the simplest method for creating a Wheels app and starting our development server.
wheels generate app myApp server start
A few minutes after submitting the above commands a new browser window should open up and display the default CFWheels congratulations screen.
So what just happened? Since we only passed the application name myApp
to the wheels generate app
command, it used default values for most of its parameters and downloaded our Base template (cfwheels-base-template) from ForgeBox.io, then downloaded the framework core files (wheels.dev) from ForgeBox.io and placed it in the vendor/wheels
directory, then configured the application name and reload password, and started a Lucee server on a random port.
A Word About Command Aliases
CommandBox commands have the capability to be called by multiple names or aliases. The command above wheels generate app
can also be initiated by typing wheels g app
. In fact g
is an alias for generate
so wherever you see a command in the CLI documentation that has generate
in it you can substitute g
instead.
In addition to shortening generate
to g
, aliases can completely change the name space as well. A command that you haven't seen yet is the wheels generate app-wizard
command. This command guides the user through a series of menu options, building up all the parameters needed to customize the start of a new CFWheels project. You're likely to use the wizard when starting a new CFWheels application so it's good to become familiar with it.
This command has the normal alias referenced above at wheels g app-wizard
but it also has an additional alias at wheels new
which is the command more prevalent in the Rails community. So the three commands wheels generate app-wizard
, wheels g app-wizard
, and wheels new
all call the same functionality which guides the user though a set of menus, collecting details on how to configure the desired app. Once all the parameters have been gathered, this command actually calls the wheels generate app
command to create the actual CFWheels application.
This Getting Started guide has taken you from the very beginning and gotten you to the point where you can go into any empty directory on your local development machine and start a CFWheels project by issuing a couple of CLI commands. In later guides we'll explore these options further and see what else the CLI can do for us.
With CommandBox, we don't need to have Lucee or Adobe ColdFusion installed locally. With a simple command, we can make CommandBox go and get the CFML engine we've requested, and quickly create a server running on Undertow. Make sure you're in the root of your website, and then run:
server start
The server will then start on a random port on 127.0.0.1
based the configuration from the server.json
file that is in the root of your application that comes with wheels. We can add various options to server.json
to customize our server. Your default server.json
will look something like this:
In this server.json
file, the server name is set to wheels
, meaning I can now start the server from any directory by simply calling start myApp
. We don't have any port specified, but you can specify any port you want. Lastly, we have URL rewriting enabled and pointed the URL rewrite configuration file to public/urlrewrite.xml
, which is included starting from CFWheels 2.x.
You can also specify hosts other than localhost: there's a useful CommandBox module to do that (Host updater) which will automatically create entries in your hosts file to allow for domains such as myapp.local
running on port 80. You can install it via install commandbox-hostupdater
when running the box shell with administrator privileges.
Obviously, anything you start, you might want to stop. Servers can be stopped either via right/ctrl clicking on the icon in the taskbar, or by the stop
command. To stop a server running in the current directory issue the following:
server stop
You can also stop a server from anywhere by using its name:
server stop myApp
If you want to see what server configurations exist on your system and their current status, simply do server list
server list
To remove a server configuration from the list, you can use server forget myapp
. Note the status of the servers on the list are somewhat unreliable, as it only remembers the last known state of the server: so if you start a server and then turn off your local machine, it may still remember it as running
when you turn your local machine back on, which is why we recommend the use of force: true
in the server.json
file.
By default, CommandBox will run Lucee (version 6.x at time of writing). You may wish to specify an exact version of Lucee, or use Adobe ColdFusion. We can do this via either setting the appropriate cfengine
setting in server.json
, or at runtime with the cfengine=
argument.
Start the default engine
CommandBox> start
__
Start the latest stable Lucee 5.x engine
CommandBox> start cfengine=lucee@5
__
Start a specific engine and version
CommandBox> start cfengine=adobe@10.0.12
__
Start the most recent Adobe server that starts with version "11"
CommandBox> start cfengine=adobe@11
__
Start the most recent adobe engine that matches the range
CommandBox> start cfengine="adobe@>9.0 <=11"
Or via server.json
CFIDE / Lucee administrators
The default username and password for all administrators is admin
& commandbox
You can of course run multiple servers, so if you need to test your app on Lucee 5.x, Lucee 6.x and Adobe 2018, you can just start three servers with different cfengine=
arguments!
Watch out
CommandBox 5.1 required to install dependencies easily
By default, the Lucee server that CommandBox starts includes all the essential Lucee extensions you need, but if need to minimize the size of the Lucee instance you launch, then you can use Lucee-Light by specifying cfengine=lucee-light
in your server.json
file. CFWheels can run just fine on lucee-light (which is after all, Lucee, minus all the extensions) but at a minimum, requires the following extensions to be installed as dependencies in your box.json
. Please note you may have to add any drivers you need for your database to this list as well.
Once added to your box.json file, while the server is running, just do box install
, which will install the dependencies, and load them into the running server within 60 seconds.
Alternatively you can download the extensions and add them manually to your server root's deploy folder (i.e \WEB-INF\lucee-server\deploy
)
Learn the goals of CFWheels as well as web development frameworks in general. Then learn more about some key concepts in CFWheels.
This chapter will introduce you to frameworks in general and later specifically to CFWheels. We'll help you decide if you even need a framework at all and what common problems a framework tries to solve. If we're able to convince you that using a framework is the right thing for you, then we'll present our goals with creating CFWheels and show you some key CFWheels concepts.
So let's get started.
Short answer, no. If you don't mind doing the same thing over and over again and are getting paid by the hour to do so, then by all means keep doing that.
Slightly longer answer, no. If you're working on a highly customized project that does not fall within what 9 out of 10 web sites/applications normally do then you likely need a high percentage of custom code, and a framework will not help much.
However, if you're like most of us and have noticed that for every new project you start on--or even every new feature you add to an existing project--you waste a lot of time re-creating the wheel, then you should read on because CFWheels may just be the solution for you!
CFWheels will make starting a new project or building a new feature quick and painless. You can get straight to solving business problems on day one! To understand how this is achieved, we figured that a little background info on frameworks in general may help you out.
All good frameworks rise from the need to solve real problems in real world situations. CFWheels is based heavily on the Rails framework for Ruby and also gets inspiration from Django and, though to a lesser extent, other frameworks in the ColdFusion space (like Fusebox, for example). Over the years the contributors to these frameworks have identified problems and tedious tasks in their own development processes, built a solution for it, and abstracted (made it more generic so it suits any project) the solution into the framework in question. Piggy-backing on what all these great programmers have already created and adding a few nice solutions of our own, CFWheels stands on solid ground.
OK, so that was the high level overview of what frameworks are meant to do. But let's get a little more specific.
Most web development frameworks set out to address some or all of these common concerns:
Map incoming requests to the code that handles them.
Separate your business logic from your presentation code.
Let you work at a higher level of abstraction, thus making you work faster.
Give you a good code organization structure to follow.
Encourage clean and pragmatic design.
Simplify saving data to a storage layer.
Like all other good frameworks, CFWheels does all this. But there are some subtle differences, and certain things are more important in CFWheels than in other frameworks and vice versa. Let's have a look at the specific goals with CFWheels so you can see how it relates to the overall goals of frameworks in general.
As we've said before, CFWheels is heavily based on Ruby on Rails, but it's not a direct port, and there are some things that have been changed to better fit the CFML language. Here's a brief overview of the goals we're striving for with CFWheels (most of these will be covered in greater detail in later chapters):
We strive for simplicity on a lot of different levels in CFWheels. We'll gladly trade code beauty in the framework's internal code for simplicity for the developers who will use it. This goal to keep things simple is evident in a lot of different areas in CFWheels. Here are some of the most notable ones:
The concept of object oriented programming is very simple and data-centric in CFWheels, rather than 100% "pure" at all times.
By default, you'll always get a query result set back when dealing with multiple records in CFWheels, simply because that is the way we're all used to outputting data.
CFWheels encourages best practices, but it will never give you an error if you go against any of them.
With CFWheels, you won't program yourself into a corner. If worse comes to worse, you can always drop right out of the framework and go back to old school code for a while if necessary.
Good old CFML code is used for everything, so there is no need to mess with XML for example.
What this means is that you don't have to be a fantastic programmer to use the framework (although it doesn't hurt). It's enough if you're an average programmer. After using CFWheels for a while, you'll probably find that you've become a better programmer though!
If you've ever downloaded a piece of open source software, then you know that most projects lack documentation. CFWheels hopes to change that. We're hoping that by putting together complete, up-to-date documentation that this framework will appeal, and be usable, by everyone. Even someone who has little ColdFusion programming background, let alone experience with frameworks.
Besides what is already mentioned above, there are some key concepts in CFWheels that makes sense to familiarize yourself with early on. If you don't feel that these concepts are to your liking, feel free to look for a different framework or stick to using no framework at all. Too often programmers choose a framework and spend weeks trying to bend it to do what they want to do rather than follow the framework conventions.
Speaking of conventions, this brings us to the first key concept:
Instead of having to set up tons of configuration variables, CFWheels will just assume you want to do things a certain way by using default settings. In fact, you can start programming a Wheels application without setting any configuration variables at all!
If you find yourself constantly fighting the conventions, then that is a hint that you're not yet ready for CFWheels or CFWheels is not ready for you.
Beautiful (for lack of a better word) code is code that you can scan through and immediately see what it's meant to do. It's code that is never repeated anywhere else. And, most of all, it's code that you'll enjoy writing and will enjoy coming back to 6 months from now.
Sometimes the CFWheels structure itself encourages beautiful code (separating business logic from request handling, for example). Sometimes it's just something that comes naturally after reading documentation, viewing other CFWheels applications, and talking to other CFWheels developers.
If you've investigated frameworks in the past, then you've probably heard this terminology before. Model-View-Controller, or MVC, is a way to structure your code so that it is broken down into three easy-to-manage pieces:
Model: Just another name for the representation of data, usually a database table.
View: What the user or their browser sees and interacts with (a web page in most cases).
Controller: The behind-the-scenes guy that's coordinating everything.
"Uh, yeah. So what's this got to do with anything?" you may ask. MVC is how CFWheels structures your code for you. As you start working with CFWheels applications, you'll see that most of the code you write (database queries, forms, and data manipulation) are very nicely separated into one of these three categories.
The benefits of MVC are limitless, but one of the major ones is that you almost always know right where to go when something needs to change.
If you've added a column to the vehicles table in your database and need to give the user the ability to edit that field, all you need to change is your View. That's where the form is presented to the user for editing.
If you find yourself constantly getting a list of all the red cars in your inventory, you can add a new method to your model called getRedCars()
that does all the work for you. Then when you want that list, just add a call to that method in your controller and you've got 'em!
The Object Relational Mapping, or ORM, in CFWheels is perhaps the one thing that could potentially speed up your development the most. An ORM handles mapping objects in memory to how they are stored in the database. It can replace a lot of your query writing with simple methods such as user.save()
, blogPost.comments(order="date")
, and so on. We'll talk a lot more about the ORM in CFWheels in the chapters about models.
So there you have it, a completely fair and unbiased introduction to CFWheels. ;)
If you've been developing ColdFusion applications for a while, then we know this all seems hard to believe. But trust us; it works. And if you're new to ColdFusion or even web development in general, then you probably aren't aware of most of the pains that Wheels was meant to alleviate!
That's okay. You're welcome in the CFWheels camp just the same.
In this tutorial, we'll be writing a simple application to make sure we have CFWheels installed properly and that everything is working as it should.
Let's make sure we're all on the same page. I'm going to assume that you've followed the Getting Started guide and have CommandBox all setup. If you haven't done that, stop and read that guide get everything setup. It's okay, this web page will wait for you.
Okay, so you have CFWheels installed and can see the CFWheels "Congratulations!" page as shown below. That wasn't that hard now, was it?
Okay, let's get to some example code. We know that you've been dying to get your hands on some code!
To continue with Programming Tutorial Tradition, we'll create the ubiquitous Hello World! application. But to keep things interesting, let's add a little CFWheels magic along the way.
Let's create a controller from scratch to illustrate how easy it is to set up a controller and plug it into the CFWheels framework.
First, create a file called Say.cfc
in the app/controllers
directory and add the
code below to the file.
Congratulations, you just created your first CFWheels controller! What does this
controller do, you might ask? Well, to be honest, not much. It has no methods
defined, so it doesn't add any new functionality to our application. But because
it extends the base Controller
component, it inherits quite a bit of powerful
functionality and is now tied into our CFWheels application.
So what happens if we try to call our new controller right now? Lets take a
look. Open your browser and point your browser to the new controller. Because my
local server is installed on port 60000, my URL is http://127.0.0.1:60000/say
.
You may need to enter a different URL, depending on how your web server is
configured. In my case, I'm using CommandBox.
The error says "Could not find the view page for the 'index' action in the 'say'
controller." Where did "index" come from? The URL we typed in only specified a
controller name but no action. When an action is not specified in the URL,
CFWheels assumes that we want the default action. Out of the box, the default
action in CFWheels is set to index
. So in our example, CFWheels tried to find
the index
action within the say
controller, and it threw an error because it
couldn't find its view page.
But let's jump ahead. Now that we have the controller created, let's add an
action to it called hello
. Change your say
controller so it looks like the
code block below:
As you can see, we created an empty method named hello
.
Now let's call our new action in the browser and see what we get. To call the
hello
action, we simply add /hello
to the end of the previous URL that we
used to call our say
controller:
http://127.0.0.1:60000/say/hello
Once again, we get a ColdFusion error. Although we have created the controller
and added the hello
action to it, we haven't created the view.
By default, when an action is called, CFWheels will look for a view file with
the same name as the action. It then hands off the processing to the view to
display the user interface. In our case, CFWheels tried to find a view file for
our say/hello
action and couldn't find one.
Let's remedy the situation and create a view file. View files are simple CFML pages that handle the output of our application. In most cases, views will return HTML code to the browser. By default, the view files will have the same name as our controller actions and will be grouped into a directory under the view directory. This new directory will have the same name as our controller.
Find the views
directory inside the app
directory, located at the root of your
CFWheels installation. There will be a few directories in there already. For
now, we need to create a new directory in the views
directory called say
.
This is the same name as the controller that we created above.
Now inside the say
directory, create a file called hello.cfm
. In the
hello.cfm
file, add the following line of code:
Save your hello.cfm
file, and let's call our say/hello
action once again.
You have your first working CFWheels page if your browser looks like Figure 3
below.
You have just created your first functional CFWheels page, albeit it is a very simple one. Pat yourself on the back, go grab a snack, and when you're ready, let's go on and extend the functionality of our Hello World! application a little more.
We will add some simple dynamic content to our hello
action and add a second
action to the application. We'll then use some CFWheels code to tie the 2
actions together. Let's get get to it!
The first thing we are going to do is to add some dynamic content to our
say/hello
action. Modify your say
controller so it looks like the code block
below:
All we are doing here is creating a variable called time
and setting its value
to the current server time using the basic ColdFusion Now()
function. When we
do this, the variable becomes immediately available to our view code.
Why not just set up this value directly in the view? If you think about it, maybe the logic behind the value of time may eventually change. What if eventually we want to display its value based on the user's time zone? What if later we decide to pull it from a web service instead? Remember, the controller is supposed to coordinate all of the data and business logic, not the view.
Next, we will modify our say/hello.cfm
view file so that it looks like the
code block below. When we do this, the value will be displayed in the browser.
call your say/hello
action again in your browser. Your browser should look
like Figure 4 below.
This simple example showed that any dynamic content created in a controller
action is available to the corresponding view file. In our application, we
created a time
variable in the say/hello
controller action and display that
variable in our say/hello.cfm
view file.
Now we will expand the functionality of our application once again by adding a
second action to our say
controller. If you feel adventurous, go ahead and add
a goodbye
action to the say
controller on your own, then create a
goodbye.cfm
view file that displays a "Goodbye" message to the user. If you're
not feeling that adventurous, we'll quickly go step by step.
First, modify the the say
controller file so that it looks like the code block
below.
Now go to the app/views/say
directory and create a goodbye.cfm
page.
Add the following code to the goodbye.cfm
page and save it.
If we did everything right, we should be able to call the new say/goodbye
action using the following URL:
http://127.0.0.1:60000/say/goodbye
Your browser should look like Figure 5 below:
Now let's link our two actions together. We will do this by adding a link to the bottom of each page so that it calls the other page.
Open the say/hello.cfm
view file. We are going to add a line of code to the
end of this file so our say/hello.cfm
view file looks like the code block
below:
The linkTo() function is a built-in CFWheels function. In this case, we are passing 2 named parameters to it. The first parameter, text
, is the text
that will be displayed in the hyperlink. The second parameter, action
, defines the action to point the link to. By using this built-in function, your application's main URL may change, and even controllers and actions may get shifted around, but you won't suffer from the dreaded dead link. CFWheels will
always create a valid link for you as long as you configure it correctly when you make infrastructure changes to your application.
Once you have added the additional line of code to the end of the
say/hello.cfm
view file, save your file and call the say/hello
action from
your browser. Your browser should look like Figure 6 below.
You can see that CFWheels created a link for us and added an appropriate URL for
the say/goodbye
action to the link.
Let's complete our little app and add a corresponding link to the bottom of our
say/goodbye.cfm
view page.
Open your say/goodbye.cfm
view page and modify it so it looks like the code
block below.
CFML: app/views/say/goodbye.cfm
If you now call the say/goodbye
action in your browser, your browser should
look like Figure 7 below.
You now know enough to be dangerous with CFWheels. Look out! But there are many more powerful features to cover. You may have noticed that we haven't even talked about the M in MVC.
No worries. We will get there. And we think you will enjoy it.
What you need to know and have installed before you start programming in CFWheels.
We can identify 3 different types of requirements that you should be aware of:
Project Requirements. Is CFWheels a good fit for your project?
Developer Requirements. Do you have the knowledge and mindset to program effectively in CFWheels?
System Requirements. Is your server ready for CFWheels?
Before you start learning CFWheels and making sure all the necessary software is installed on your computer, you really need to take a moment and think about the project you intend to use CFWheels on. Is it a ten page website that won't be updated very often? Is it a space flight simulator program for NASA? Is it something in between?
Most websites are, at their cores, simple data manipulation applications. You fetch a row, make some updates to it, stick it back in the database and so on. This is the "target market" for CFWheels--simple CRUD (create, read, update, delete) website applications.
A simple ten page website won't do much data manipulation, so you don't need CFWheels for that (or even ColdFusion in some cases). A flight simulator program will do so much more than simple CRUD work, so in that case, CFWheels is a poor match for you (and so perhaps, is ColdFusion).
If your website falls somewhere in between these two extreme examples, then read on. If not, go look for another programming language and framework. ;)
Another thing worth noting right off the bat (and one that ties in with the simple CRUD reasoning above) is that CFWheels takes a very data-centric approach to the development process. What we mean by that is that it should be possible to visualize and implement the database design early on in the project's life cycle. So, if you're about to embark on a project with an extensive period of object oriented analysis and design which, as a last step almost, looks at how to persist objects, then you should probably also look for another framework.
Still reading?
Good!
Moving on...
Yes, there are actually some things you should familiarize yourself with before starting to use CFWheels. Don't worry though. You don't need to be an expert on any on of them. A basic understanding is good enough.
CFML. You should know CFML, the ColdFusion programming language. (Surprise!)
Object Oriented Programming. You should grasp the concept of object oriented programming and how it applies to CFML.
Model-View-Controller. You should know the theory behind the Model-View-Controller development pattern.
This is a programming methodology that uses constructs called objects to design applications. Objects model real world entities in your application. OOP is based on several techniques including inheritance, modularity, polymorphism, and encapsulation. Most of these techniques are supported in CFML, making it a fairly functional object oriented language. At the most basic level, a .cfc
file in CFML is a class, and you create an instance of a class by using the CreateObject
function or the <cfobject>
tag.
Trying to squeeze an explanation of object oriented programming and how it's used in CFML into a few sentences is impossible, and a detailed overview of it is outside the scope of this chapter. There is lots of high quality information online, so go ahead and Google it.
Model-View-Controller, or MVC for short, is a way to structure your code so that it is broken down into 3 easy-to-manage pieces:
Model. Just another name for the representation of data, usually a database table.
View. What the user sees and interacts with (a web page in our case).
Controller. The behind-the-scenes guy that's coordinating everything.
MVC is how CFWheels structures your code for you. As you start working with CFWheels applications, you'll see that most of the code you write is very nicely separated into one of these 3 categories.
CFWheels requires that you use one of these CFML engines:
Your ColdFusion or Lucee engine can be installed on Windows, Mac, UNIX, or Linux—they all work just fine.
Finally, to build any kind of meaningful website application, you will likely interact with a database. These are the currently supported databases:
SQL Server 7+
MySQL 5+ *
PostgreSQL 8.4+
H2 1.4+
MySQL
CFWheels maybe incompatible with newer MySQL JDBC drivers. It is recommended you downgrade the driver to version 5.1.x for full ORM functionality.
MySQL 4 is not supported.
OK, hopefully this chapter didn't scare you too much. You can move on knowing that you have the basic knowledge needed, the software to run CFWheels, and a suitable project to start with.
A quick tutorial that demonstrates how quickly you can get database connectivity up and running with CFWheels.
CFWheels's built in model provides your application with some simple and powerful functionality for interacting with databases. To get started, you will make some simple configurations, call some functions within your controllers, and that's it. Best yet, you will rarely ever need to write SQL code to get those redundant CRUD tasks out of the way.
We'll learn by building part of a sample user management application. This tutorial will teach you the basics of setting up a resource that interacts with the CFWheels ORM.
Download source code
By default, CFWheels will connect to a data source wheels.dev
. To change this default behavior, open the file at app/config/settings.cfm
. In a fresh install of CFWheels, you'll see the follwing code:
These lines provide CFWheels with the necessary information about the data source, URL rewriting, and reload password for your application, and include the appropriate values. This may include values for dataSourceName
, dataSourceUserName
, and dataSourcePassword
. More on URL rewriting and reload password later.
CFWheels supports MySQL, SQL Server, PostgreSQL, and H2. It doesn't matter which DBMS you use for this tutorial; we will all be writing the same CFML code to interact with the database. CFWheels does everything behind the scenes that needs to be done to work with each DBMS.
That said, here's a quick look at a table that you'll need in your database, named users
:
Note a couple things about this users
table:
The table name is plural.
The table has an auto-incrementing primary key named id
.
Fortunately, there are ways of going outside of these conventions when you really need it. But let's learn the conventional way first. Sometimes you need to learn the rules before you can know how to break them.
Next, open the file at app/config/routes.cfm
. You will see contents similar to this:
We are going to create a section of our application for listing, creating, updating, and deleting user records. In CFWheels routing, this requires a plural resource, which we'll name users
.
Because a users
resource is more specific than the "generic" routes provided by CFWheels, we'll list it first in the chain of mapper method calls:
This will create URL endpoints for creating, reading, updating, and deleting user records:
Name is referenced in your code to tell CFWheels where to point forms and links.
Method is the HTTP verb that CFWheels listens for to match up the request.
URL Path is the URL that CFWheels listens for to match up the request.
Don't forget to reload
You will need to reload your application after adding new routes!
First, let's create a simple form for adding a new user to the users
table. To do this, we will use CFWheels's form helper functions. CFWheels includes a whole range of functions that simplifies all of the tasks that you need to display forms and communicate errors to the user.
Now create a new file in app/views/users
called new.cfm
. This will contain the view code for our simple form.
Next, add these lines of code to the new file:
What we've done here is use form helpers to generate all of the form fields necessary for creating a new user in our database. It may feel a little strange using functions to generate form elements, but it will soon become clear why we're doing this. Trust us on this one… you'll love it!
All of the form helper calls in our view specify an objectName
argument with a reference to a variable named user
. That means that we need to supply our view code with an object called user
. Because the controller is responsible for providing the views with data, we'll set it there.
Create a new ColdFusion component at app/controllers/Users.cfc
.
CFWheels will automatically know that we're talking about the users
database table when we instantiate a user
model. The convention: database tables are plural and their corresponding CFWheels models are singular.
Why is our model name singular instead of plural? When we're talking about a single record in the users
database, we represent that with an individual model object. So the users
table contains many user
objects. It just works better in conversation.
Now when we run the URL at http://localhost/users/new
, we'll see the form with the fields that we defined.
The HTML generated by your application will look something like this:
So far we have a fairly well-formed, accessible form, without writing a bunch of repetitive markup.
Next, we'll code the create
action in the controller to handle the form submission and save the new user to the database.
Because we used the objectName
argument in the fields of our form, we can access the user data as a struct in the params
struct.
There are more things that we can do in the create
action to handle validation, but let's keep it simple in this tutorial.
First, let's get the data that the listing needs. Create an action named index
in the users
controller like so:
In the view at app/views/users/index.cfm
, it's as simple as looping through the query and outputting the data
When to use EncodeForHtml
You'll see references to EncodeForHtml
in some of our examples that output data. This helps escape HTML code in data that attackers could use to embed inject harmful JavaScript. (This is commonly referred to as an "XSS attack," short for "Cross-site Scripting attack.")
A rule of thumb: you do not need to use EncodeForHtml
when passing values into CFWheels helpers like linkTo
, buttonTo
, startFormTag
, textField
, etc. However, you need to escape data that is displayed directly onto the page without a CFWheels helper.
We'll now show another cool aspect of form helpers by creating a screen for editing users.
You probably noticed in the code listed above that we'll have an action for editing a single users
record. We used the linkTo() form helper function to add an "Edit" button to the form. This action expects a key
as well.
Because in the linkTo() form helper function we specified the parameter key
, Wheels adds this parameter into the URL when generating the route.
Wheels will automatically add the provided 'key' from the URL to the params struct in the controllers edit() function.
Given the provided key
, we'll have the action load the appropriate user
object to pass on to the view:
The view at app/views/users/edit.cfm
looks almost exactly the same as the view for creating a user:
But an interesting thing happens. Because the form fields are bound to the user
object via the form helpers' objectName
arguments, the form will automatically provide default values based on the object's properties.
With the user
model populated, we'll end up seeing code similar to this:
Pretty cool, huh?
There's a lot of repetition in the new
and edit
forms. You'd imagine that we could factor out most of this code into a single view file. To keep this tutorial from becoming a book, we'll just continue on knowing that this could be better.
Now we'll create the update
action. This will be similar to the create
action, except it will be updating the user object:
Notice in our listing above that we have a delete
action. Here's what it would look like:
We've shown you quite a few of the basics in getting a simple user database up and running. We hope that this has whet your appetite to see some of the power packed into the CFWheels framework. There's plenty more.
Be sure to read on to some of the related chapters listed below to learn more about working with CFWheels's ORM.
Instructions for installing CFWheels on your system.
Installing CFWheels is so simple that there is barely a need for a chapter devoted to it. But we figured we'd better make one anyway in case anyone is specifically looking for a chapter about installation.
So, here are the simple steps you need to follow to get rolling on CFWheels...
You have 2 choices when downloading CFWheels. You can either use the latest official release of CFWheels, or you can take a walk on the wild side and go with the latest committed source code in our Git repository.
In most cases, we recommend going with the official release because it's well documented and has been through a lot of bug testing. Only if you're in desperate need of a feature that has not been released yet would we advise you to go with the version stored in the Git master
branch.
Let's assume you have downloaded the latest official release. (Really, you should go with this option.) You now have a .zip
file saved somewhere on your computer. On to the next step...
Getting an empty website running with CFWheels installed is an easy process if you already know your way around IIS or Apache. Basically, you need to create a new website in your web server of choice and unzip the contents of the file into the root of it.
Create a new folder under your web root (usually C:\Inetpub\wwwroot
) named wheels_site
and unzip the CFWheels .zip
file into the root of it.
Create a new website using IIS called CFWheels Site
with localhost
as the host header name and C:\Inetpub\wwwroot\mysite
as the path to your home directory.
Create a new database in MySQL, PostgreSQL, Microsoft SQL Server, or H2 and add a new data source for it in the ColdFusion/Lucee Administrator, just as you'd normally do. Now open up app/config/settings.cfm
and call set(dataSourceName="")
with the name you chose for the data source.
When you've followed the steps above, you can test your installation by typing http://localhost/
(or whatever you set as the host header name) in your web browser. You should get a "Congratulations!" page.
That's it. You're done. This is where the fun begins!
Tutorials, demonstrations, and presentations about the ColdFusion on Wheels framework.
Simply the best web development language in the world! The best way to learn it, in our humble opinion, is to get the free developer edition of Adobe ColdFusion, buy Ben Forta's ColdFusion Web Application Construction Kit series, and start coding using your programming editor of choice. Remember it's not just the commercial Adobe offering that's available; offers an excellent open source alternative. Using is a great and simple way to get a local development environment of your choice up and running quickly.
2018 / 2021 / 2023
5.2.1.9+ / 6
You also need a web server. CFWheels runs on all popular web servers, including Apache, Microsoft IIS, Jetty, and the JRun or Tomcat web server that ships with Adobe ColdFusion. Some web servers support URL rewriting out of the box, some support the cgi.PATH_INFO
variable which is used to achieve partial rewriting, and some don't have support for either. For local development, we strongly encourage the use of .
Don't worry though. CFWheels will adopt to your setup and run just fine, but the URLs that it creates might differ a bit. You can read more about this in the chapter.
If you're using MySQL 5.7.5+ you should be aware that the ONLY_FULL_GROUP_BY
setting is enabled by default and it's currently not compatible with the CFWheels ORM. However, you can work around this by either disabling the ONLY_FULL_GROUP_BY
setting or using ANY_VALUE()
in a calculated property. You can read more about it .
We also recommend using the InnoDB engine if you want to work.
You can download all the source code for this sample application from
These are database used by CFWheels. This framework strongly encourages that everyone follow convention over configuration. That way everyone is doing things mostly the same way, leading to less maintenance and training headaches down the road.
To generate the form tag's action
attribute, the function takes parameters similar to the function that we introduced in the Beginner Tutorial: Hello World tutorial. We can pass in controller, action, key
, and other route- and parameter-defined URLs just like we do with .
To end the form, we use the function. Easy enough.
The and helpers are similar. As you probably guessed, they create <input>
elements with type="text"
and type="password"
, respectively. And the function creates an <input type="submit" />
element.
One thing you'll notice is the and functions accept arguments called objectName
and property
. As it turns out, this particular view code will throw an error because these functions are expecting an object named user
. Let's fix that.
As it turns out, our controller needs to provide the view with a blank user
object (whose instance variable will also be called user
in this case). In our new action, we will use the function to generate a new instance of the user model.
To get a blank set of properties in the model, we'll also call the generated model's method.
Notice how we have prefixed the function with application.wo
. This is because, in CFWheels, all the global functions and functions for your controller reside in the application.wo
structure. So, whenever you need to call a global function or a function for your controller, you have to prefix them with application.wo
. You will see its use throughout the documentation wherever required.
A basic way of doing this is using the model object's method:
Notice that our create
action above redirects the user to the users
index route using the function. We'll use this action to list all users in the system with "Edit" links. We'll also provide a link to the "New User" form that we just coded.
This call to the model's method will return a query object of all users in the system. By using the method's order
argument, we're also telling the database to order the records by username
.
To update the user
, simply call its method with the user
struct passed from the form via params
. It's that simple.
After the update, we'll add a success message and send the end user back to the edit form in case they want to make more changes.
We simply load the user using the model's method and then call the object's method. That's all there is to it.
The latest official releases can always be found in the section of GitHub, and the Git repository is available at our .
In case you're not sure, here are the instructions for setting up an empty CFWheels site that can be accessed when typing localhost
in your browser. The instructions refer to a system running Windows Server 2003 and IIS, but you should be able to follow along and apply the instructions with minor modifications to your system. (See for a list of tested systems).
If you want to run a CFWheels-powered application from a subfolder in an existing website, this is entirely possible, but you may need to get a little creative with your URL rewrite rules if you want to get pretty URLs--it will only work out of the box on recent versions of Apache. (Read more about this in the chapter.)
If you don't want to be bothered by opening up a CFWheels configuration file at all, there is a nice convention you can follow for the naming. Just name your data source with the same name as the folder you are running your website from (mysite
in the example above), and CFWheels will use that when you haven't set the dataSourceName
setting using the function.
Create a basic CRUD interface in CFWheels 2.x
Create a basic JSON API in CFWheels 2.x
Routing in CFWheels 2.x - Part 1
Routing in CFWheels 2.x - Part 2
Introduction to Unit Testing in CFWheels 2.x
Unit Testing Controllers in CFWheels 2.x
Learn about basic create operations when building standard CRUD functionality in CFWheels
Learn about basic read operations when building standard CRUD functionality in CFWheels
Chris Peters demonstrates updating data in a simple CRUD CFWheels application
Learn how simple it is to delete records in a basic CRUD application using CFWheels
Chris Peters starts the webcast series by demonstrating how to set up ColdFusion on Wheels
Chris Peters demonstrates how to bind a Wheels model object to a form through the use of form helpers
Chris Peters finishes the "success" portion of the registration functionality by adding a success message to the Flash and redirecting the user to their home screen
Chris Peters teaches you about more validation options and how you can add them to the registration form quickly and easily
Chris Peters stylizes form markup globally using a Wheels feature called global helpers
Learn how to set up simple user authentication on a website by using a Wheels feature called filters
Learn the mechanics of reading a single record from the database and displaying its data in the view
Creating custom URL patterns is a breeze in ColdFusion on Wheels
Learn how to fetch multiple records from your model with findAll() and then display them to the user using ColdFusion on Wheels
Learn how to factor out logic in your view templates into custom helper functions in ColdFusion on Wheels
Chris Peters demonstrates joining data together with model associations using ColdFusion on Wheels
All it takes to offer pagination is two extra arguments to findAll() and a call to a view helper called paginationLinks()
Learn how to use the provides() and renderWith() functions to automatically serialize data into XML, JSON, and more
Peter Amiri walks you through setting up a "Hello World" application using the ColdFusion on Wheels framework
Chris Peters gives a high level overview of the ORM included with ColdFusion on Wheels
Chris Peters from Liquifusion demonstrates the ColdRoute plugin for CFWheels
Doug Boude demonstrates using his new Wirebox plugin for CFWheels
Chris Peters from Liquifusion demonstrates creating tables and records in the DBMigrate plugin for ColdFusion on Wheels
Online ColdFusion Meetup (coldfusionmeetup.com) session for March 10 2011, "What's New in CFWheels 1.1", with Chris Peters:
A quick demo of the CFWheels Textmate bundle by Russ Johnson
id
int
auto increment
username
varchar(100)
varchar(255)
passwd
varchar(15)
users
GET
/users
Lists users
newUsers
GET
/users/new
Display a form for creating a user record
users
POST
/users
Form posts a new user record to be created
editUser
GET
/users/[id]/edit
Displays a form for editing a user record
user
PATCH
/users/[id]
Form posts an existing user record to be updated
user
DELETE
/users/[id]
Deletes a user record
Using CFWheels to develop web applications with AJAX features is a breeze. You have several options and tools at your disposal, which we'll cover in this chapter.
CFWheels was designed to be as lightweight as possible, so this keeps your options fairly open for developing AJAX features into your application.
While there are several flavors of JavaScript libraries out there with AJAX support, we will be using the jQuery framework in this tutorial. Let's assume that you are fairly familiar with the basics of jQuery and know how to set it up.
For this tutorial, let's create the simplest example of all: a link that will render a message back to the user without refreshing the page.
In this example, we'll wire up some simple JavaScript code that calls a CFWheels action asynchronously. All of this will be done with basic jQuery code and built-in CFWheels functionality.
First, let's make sure we've got an appropriate route setup. It might be you're still using the default wildcard()
route which will create some default GET
routes for the controller/action
pattern, but we'll add a new route here just for practice. We are going to create a route named sayHello
and direct it to the hello
action of the say
controller. There are two ways you could write this code a long hand method specifying the controller and action separately as well as a short hand method that combines the two into a single parameter.
The longhand way would look like:
The shorthand method would look like:
You can decide which method you prefer. Both sets of code above are equivalent.
Then, let's create a link to a controller's action in a view file, like so:
That piece of code by itself will work just like you expect it to. When you click the link, you will load the hello
action inside the say
controller.
But let's make it into an asynchronous request. Add this JavaScript (either on the page inside script
tags or in a separate .js
file included via javaScriptIncludeTag() ):
With that code, we are listening to the click
event of the hyperlink, which will make an asynchronous request to the hello
action in the say
controller. Additionally, the JavaScript call is passing a URL parameter called format
set to json
.
Note that the success
block inserts keys from the response into the empty h1
and p
blocks in the calling view. (You may have been wondering about those when you saw the first example. Mystery solved.)
The last thing that we need to do is implement the say/hello
action. Note that the request expects a dataType
of JSON
. By default, CFWheels controllers only generate HTML responses, but there is an easy way to generate JSON instead using CFWheels's provides() and renderWith() functions:
In this controller's config()
method, we use the provides() function to indicate that we want all actions in the controller to be able to respond with the data in HTML or JSON formats. Note that the client calling the action can request the type by passing a URL parameter named format or by sending the format
in the request header.
The call to renderWith() in the hello
action takes care of the translation to the requested format. Our JavaScript is requesting JSON, so Wheels will format the greeting
struct as JSON automatically and send it back to the client. If the client requested HTML or the default of none, Wheels will process and serve the view template at app/views/say/hello.cfm
. For more information about provides() and renderWith(), reference the chapter on Responding with Multiple Formats.
Lastly, notice the lines where we're setting greeting["message"]
and greeting["time"]
. Due to the case-insensitive nature of ColdFusion, we recommend setting variables to be consumed by JavaScript using bracket notation like that. If you do not use that notation (i.e., greetings.message
and greetings.time
instead), your JavaScript will need to reference those keys from the JSON as MESSAGE
and TIME
(all caps). Unless you like turning caps lock on and off, you can see how that would get annoying after some time.
Assuming you already included jQuery in your application and you followed the code examples above, you now have a simple AJAX-powered web application built on Wheels. After clicking that Alert me!
link, your say controller will respond back to you the serialized message via AJAX. jQuery will parse the JSON object and populate the h1
and p
with the appropriate data.
That is it! Hopefully now you have a clearer picture on how to create AJAX-based features for your web applications.
The command line tools extends the functionality of CommandBox with some commands specifically designed for CFWheels development.
CommandBox brings a whole host of command line capabilities to the CFML developer. It allows you to write scripts that can be executed at the command line written entirely in CFML. It allows you to start a CFML server from any directory on your machine and wire up the code in that directory as the web root of the server. What's more is, those servers can be either Lucee servers or Adobe ColdFusion servers. You can even specify what version of each server to launch. Lastly, CommandBox is a package manager for CFML. That means you can take some CFML code and package it up into a module, host it on ForgeBox.io, and make it available to other CFML developers. In fact we make extensive use of these capabilities to distribute CFWheels plugins and templates. More on that later.
One module that we have created is a module that extends CommandBox itself with commands and features specific to the CFWheels framework. The CFWheels CLI module for CommandBox is modeled after the Ruby on Rails CLI module and gives similar capabilities to the CFWheels developer.
The first step is to get CommandBox downloaded and running. CommandBox is available for Windows, Mac & Linux, and can be installed manually or using one of the respective package managers for each OS. You can use Chocolatey on Windows, Homebrew on MacOS, or Yum/Apt on Linux depending on your flavor of Linux. Please follow the instructions on how to install CommandBox on your particular operating system. At the end of the installation process you want to make sure the box
command is part of your system path so you can call the command from any directory on your system.
Once installed, you can either double-click on the box
executable which opens the CommandBox shell window, or run box
from a CMD window in Windows, Terminal window in MacOS, or shell prompt on a Linux server. Sometimes you only want to call a single CommandBox command and don't need to launch a whole CommandBox shell window to do that, for these instances you can call the CommandBox command directly from your default system terminal window by prefixing the command with the box
prefix.
So to run the CommandBox version
command you could run box version from the shell or you could launch the CommandBox shell and run version inside it.
box version
version
This is a good concept to grasp, cause depending on your workflow, you may find it easier to do one versus the other. Most of the commands you will see in these CLI guides will assume that you are entering the command in the actual CommandBox shell so the box
prefix is left off.
Okay, now that we have CommandBox installed, let's add the CFWheels CLI module.
install wheels-cli
Installing this module will add a number of commands to your default CommandBox installation. All of these commands are prefixed by the wheels
name space. There are commands to create a brand new CFWheels application or scaffold out sections of your application. We'll see some of these commands in action momentarily.
These tools allow you to adopt a more modern workflow and allow you to create and manipulate many CFWheels objects from the command line. By making these tools available in the command line, not only will you be able to speed up your development but you can also utilize these commands in Continuous Integration (CI) and Continuous Deployment (CD) work flows.
These are the top level commands in the wheels
namespace.
wheels info
This command is the most basic of the commands and other than printing some pretty ASCII art it also displays the Current Working Directory, the CommandBox Module Root which can be handy when trying to diagnose version discrepancies, and lastly the CFWheels version currently installed. The version is determined from a variety of sources. First and foremost, if there is a box.json
file in the vendor/wheels/
directory the version is extracted from that box.json
. Alternatively, if there is no box.json
file in the wheels/
directory, we look in vendor/wheels/events/onapplicationstart.cfm
and extract a version number from that file. That is the version number that is displayed on the default congratulations screen by the way. If both of these fail to get us a version number we can use, we ask you to let us know what version of wheels you are using and give you the option of generating a box.json
file. This is handy for bringing old legacy installations under CLI control.
wheels init
This will attempt to bootstrap an EXISTING wheels app to work with the CLI.
We'll assume the database/datasource exists and the other config options like reloadpassword is all set up. If there's no box.json, create it, and ask for the version number if we can't determine it. If there's no server.json, create it, and ask for cfengine preferences. We'll ignore other templating objects for now, as this will probably be in place too.
wheels reload
This command will reload your CFWheels application. In order for this command to work, your local server needs to be started and running. This command basically issues a request to the running CFWheels application to reload as if you were doing it from your browsers address bar. You will be prompted for your reload password that will be passed to the reload endpoint.
mode
false
development
possible values development, testing, maintenance, production
wheels test
This command will call the Test Runner in a running server and return the results. The command can be run from within the directory of the running server or you can specify the server name to run against. Additionally you can specify the test suite to run, possible choices include the running application's test suite (app), the core framework test suite (core), or a particular plugin's test suite by passing in the plugin name.
type
false
app
Either Core, App, or the name of the plugin
servername
false
Servername to run the tests against
reload
false
false
Force Reload
debug
false
false
Output passing tests as well as failing ones
format
false
json
Force a specific return format for debug
adapter
false
Attempt to override what dbadapter wheels uses
wheels scaffold
This command will completely scaffold a new object. Typically you would run this command to stub out all the CRUD related files and then follow it up with a series of wheels g property
commands to add the individual fields to the object. This command will:
Create a model file
A Default CRUD Controller complete with create/edit/update/delete code
View files for all those actions
Associated test stubs
DB migration file
This command can be run without the server running except the database migration portion because that requires a running database. So if your server is already up and running you can run this command completely including the database migration portion. Afterwards make sure to run wheels reload
to reload your application since we just made model changes. If the server isn't running, you can run this command and stub out all the files, then start your server with server start
and finally migrate the database with wheels db latest
.
Name
true
Name of the object to scaffold out
wheels destroy
This command will destroy a given object. This is highly destructive, given the name, so proceed with caution. If you created an object using the wheels scaffold [objectName]
command, this command is the inverse of that command and will remove all elements created by that command.
This command will destroy the following elements:
the models definition file
the controllers definition file
the view sub folder and all it's contents
the model test file
the controller test file
the views test file
resource route configuration
Name
true
Name of the object to destroy
These are the commands in the wheels dbmigrate
namespace. They allow you to manipulate the
database structure and script the changes. This makes is easy to share your changes with
coworkers, check them into source control, or apply them automatically when you deploy your
code to production.
wheels dbmigrate
This is another namespace with sub commands within it. It also has an alias of wheels db
which allows you to shorten the command you need to type.
wheels dbmigrate info
This command doesn't take any inputs but simply tries to communicate with the running server and gather information about your migrations and displays them in a table.
From the information presented in the two tables you can see how many migration files are in your application and of those how many have already been applied and available to be applied. You are also presented with the datasource name and database type information.
wheels dbmigrate latest
This command will migrate the database to the latest version. This command will apply each migration file from the current state all the way to the latest one at a time. If a SQL error is encountered in one of the files, the command will stop at that point and report the error.
wheels dbmigrate reset
This command will migrate the database to version 0 effectively resetting the database to nothing.
wheels dbmigrate up
This command will process the next migration file from the current state. If the database is already at the latest version this command will have no effect.
wheels dbmigrate down
This command will reverse the current migration file and take the database one step backwards. If the database is already at version 0 then this command will have no effect.
wheels dbmigrate exec
This command will run a particular migration file and take the database to that version. The four directional
migration commands above latest
, reset
, up
, and down
each in turn call this command to process their
intended action.
version
true
The version to migrate the database to
wheels dbmigrate create table
This command will generate a new migration file for creating a table in the database. Keep in mind you will still have to run the migration file but this will add it to the migration history.
name
true
The name of the database table to create
force
false
false
Force the creation of the table
id
false
true
Auto create ID column as autoincrement ID
primaryKey
false
ID
Overrides the default primary key column name
wheels dbmigrate create column
This command will generate a new migration file for adding a new column to an existing table.
name
true
The name of the database table to modify
columnType
true
The column type to add
columnName
false
The column name to add
default
false
The default value to set for the column
null
false
true
Should the column allow nulls
limit
false
The character limit of the column
precision
false
The precision of the numeric column
scale
false
The scale of the numeric column
wheels dbmigrate create blank
wheels dbmigrate remove table
This command generates a migration file to remove a table. The migration file is will still need to be run individual but this command gets the migration generated and into the history.
name
true
The name of the database table to remove
Instructions for upgrading CFWheels applications
CFWheels follows Semantic Versioning (http://semver.org/) so large version changes (e.g, 1.x.x -> 2.x.x
) will most likely contain breaking changes which will require evaluation of your codebase. Minor version changes (e.g, 1.3.x->1.4.x
) will often contain new functionality, but in a backwards-compatible manner, and maintenance releases (e.g 1.4.4 -> 1.4.5
) will just be trying to fix bugs.
Generally speaking, upgrading CFWheels is as easy as replacing the wheels
folder, especially for those small maintenance releases: however, there are usually exceptions in minor point releases (i.e, 1.1
to 1.3
required replacing other files outside the wheels
folder). The notes below detail those changes.
Adobe Coldfusion 2016 and below are no longer compatible with CFWheels going forward. Consequently, these versions have been removed from the Wheels Internal Test Suites.
Prefix global and controller functions with application.wo
. For example, change the model("")
function in your controllers to application.wo.model("")
.
Starting with CFWheels 3.x, Wirebox will be used as the default dependency injector.
After installing CFWheels 3.x, you'll have to run box install
to intall testbox and wirebox in your application as they are not shipped with CFWheels but are rather listed in box.json
file as dependencies to be installed.
Added Mappings for the app
, vendor
, wheels
, wirebox
, testbox
and tests
directories.
root.cfm
and rewrite.cfm
have been removed. All the requests are now being redirected only through public/index.cfm
.
A .env
file has been added in the root of the application which adds the H2 database extension for lucee and sets the cfadmin password to commandbox
for both Lucee and Adobe ColdFusion.
Replace the wheels
folder with the new one from the 3.0.0 download.
Move the wheels
folder inside the vendor
folder.
Moved the config
, controllers
, events
, global
, lib
, migrator
, models
, plugins
, snippets
and views
directories inside the app
directory.
Moved the files
, images
, javascripts
, miscellaneous
, stylesheets
directories and Application.cfc
, index.cfm
and urlrewrite.xml
files into the public
folder.
Replace the wheels
folder with the new one from the 2.3.0 download.
Replace the wheels
folder with the new one from the 2.2.0 download.
Replace the wheels
folder with the new one from the 2.1.0 download.
Rename any instances of findLast()
to findLastOne()
Create /events/onabort.cfm
to support the onAbort
method
As always, the first step is to replace the wheels
folder with the new one from the 2.0 download.
Other major changes required to upgrade your application are listed in the following sections.
CFWheels 2.0 requires one of these CFML engines:
Lucee 4.5.5.006 + / 5.2.1.9+
Adobe ColdFusion 10.0.23 / 11.0.12+ / 2016.0.4+
We've updated our minimum requirements to match officially supported versions from the vendors. (For example, Adobe discontinued support for ColdFusion 10 in May 2017, which causes it to be exposed to security exploits in the future. We've included it in 2.0 but it may be discontinued in a future version)
The events/functions.cfm
file has been moved to global/functions.cfm
.
The models/Model.cfc
file should extend wheels.Model
instead of Wheels
(models/Wheels.cfc
can be deleted).
The controllers/Controller.cfc
file should extend wheels.Controller
instead of Wheels
(controllers/Wheels.cfc
can be deleted).
The init
function of controllers and models must be renamed to config
.
The global setting modelRequireInit
has been renamed to modelRequireConfig
.
The global setting cacheControllerInitialization
has been renamed to cacheControllerConfig
.
The global setting cacheModelInitialization
has been renamed to cacheModelConfig
.
The global setting clearServerCache
has been renamed to clearTemplateCache
.
The updateProperties()
method has been removed, use update()
instead.
JavaScript arguments like confirm
and disable
have been removed from the link and form helper functions (use the JS Confirm and JS Disable plugins to reinstate the old behavior).
The renderPage
function has been renamed to renderView
includePartial()
now requires the partial
and query
arguments to be set (if using a query)
The addRoute() function has been removed in CFWheels 2.0 in favor of a new routing API. See the Routing chapter for information about the new RESTful routing system.
A limited version of the "wildcard" route ([controller]/[action]/[key]
) is available as [controller]/[action]
) if you use the new wildcard() mapper method:
By default, this is limited to GET
requests for security reasons.
It is strongly recommended that you enable CFWheels 2.0's built-in CSRF protection.
For many applications, you need to follow these steps:
In controllers/Controller.cfc
, add a call to protectsFromForgery() to the config
method.
Add a call to the csrfMetaTags() helper in your layouts' <head>
sections.
Configure any AJAX calls that POST
data to your application to pass the authenticityToken
from the <meta>
tags generated by csrfMetaTags() as an X-CSRF-TOKEN
HTTP header.
Update your route definitions to enforce HTTP verbs on actions that manipulate data (get
, post
, patch
, delete
, etc.)
Make sure that forms within the application are POST
ing data to the actions that require post
, patch
, and delete
verbs.
See documentation for the CSRF Protection Plugin for more information.
Note: If you had previously installed the CSRF Protection plugin, you may remove it and rely on the functionality included in the CFWheels 2 core.
If you have previously been using the dbmigrate plugin, you can now use the inbuilt version within the CFWheels 2 core.
Database Migration files in /db/migrate/
should now be moved to /migrator/migrations
and extend wheels.migrator.Migration
, not plugins.dbmigrate.Migration
which can be changed with a simple find and replace. Note: Oracle is not currently supported for Migrator.
Replace the wheels
folder with the new one from the 1.4 download.
Replace URL rewriting rule files – i.e, .htaccess
, web.config
, IsapiRewrite.ini
In addition, if you're upgrading from an earlier version of CFWheels, we recommend reviewing the instructions from earlier reference guides below.
If you are upgrading from CFWheels 1.1.0 or newer, follow these steps:
Replace the wheels
folder with the new one from the 1.3 download.
Replace the root root.cfm
file with the new one from the 1.3 download.
Remove the <cfheader>
calls from the following files:
events/onerror.cfm
events/onmaintenance.cfm
events/onmissingtemplate.cfm
In addition, if you're upgrading from an earlier version of CFWheels, we recommend reviewing the instructions from earlier reference guides below.
Note: To accompany the newest 1.1.x releases, we've highlighted the changes that are affected by each release in this cycle.
If you are upgrading from Wheels 1.0 or newer, the easiest way to upgrade is to replace the wheels folder with the new one from the 1.1 download. If you are upgrading from an earlier version, we recommend reviewing the steps outlined in Upgrading to Wheels 1.0.
Note: To accompany the newest 1.1.x releases, we've highlighted the changes that are affected by each release in this cycle.
Be sure to review your plugins and their compatibility with your newly-updated version of Wheels. Some plugins may stop working, throw errors, or cause unexpected behavior in your application.
1.1: The minimum Adobe ColdFusion version required is now 8.0.1.
1.1: The minimum Railo version required is now 3.1.2.020.
1.1: The H2 database engine is now supported.
1.1: The .htaccess file has been changed. Be sure to copy over the new one from the new version 1.1 download and copy any addition changes that you may have also made to the original version.
1.1: By default, Wheels 1.1 will wrap database queries in transactions. This requires that your database engine supports transactions. For MySQL in particular, you can convert your MyISAM tables to InnoDB to be compatible with this new functionality. Otherwise, to turn off automatic transactions, place a call to set(transactionMode="none").
1.1: Binary data types are now supported.
Model Code
1.1: Validations will be applied to some model properties automatically. This may cause unintended behavior with your validations. To turn this setting off, call set(automaticValidations=false) in config/settings.cfm.
1.1: The class argument in hasOne(), hasMany(), and belongsTo() has been deprecated. Use the modelName argument instead.
1.1: afterFind() callbacks no longer require special logic to handle the setting of properties in objects and queries. (The "query way" works for both cases now.) Because arguments will always be passed in to the method, you can't rely on StructIsEmpty() to determine if you're dealing with an object or not. In the rare cases that you need to know, you can now call isInstance() or isClass() instead.
1.1: On create, a model will now set the updatedAt auto-timestamp to the same value as the createdAt timestamp. To override this behavior, call set(setUpdatedAtOnCreate=false) in config/settings.cfm.
View Code
1.1: Object form helpers (e.g. textField() and radioButton()) now automatically display a label based on the property name. If you left the label argument blank while using an earlier version of Wheels, some labels may start appearing automatically, leaving you with unintended results. To stop a label from appearing, use label=false instead.
1.1: The contentForLayout() helper to be used in your layout files has been deprecated. Use the includeContent() helper instead.
1.1: In production mode, query strings will automatically be added to the end of all asset URLs (which includes JavaScript includes, stylesheet links, and images). To turn off this setting, call set(assetQueryString=false) in config/settings.cfm.
1.1: stylesheetLinkTag() and javaScriptIncludeTag() now accept external URLs for the source/sources argument. If you manually typed out these tags in previous releases, you can now use these helpers instead.
1.1: flashMessages(), errorMessageOn(), and errorMessagesFor() now create camelCased class attributes instead (for example error-messages is now errorMessages). The same goes for the class attribute on the tag that wraps form elements with errors: it is now fieldWithErrors.
Controller Code
1.1.1: The if argument in all validation functions is now deprecated. Use the condition argument instead.
Our listing of steps to take while upgrading your Wheels application from earlier versions to 1.0.x.
Upgrading from an earlier version of 1.x? Then the upgrade path is simple. All you need to do is replace the wheels folder with the new wheels folder from the download.
The easiest way to upgrade is to setup an empty website, deploy a fresh copy of Wheels 1.0, and then transfer your application code to it. When transferring, please make note of the following changes and make the appropriate changes to your code.
Note: To accompany the newest 1.0 release, we've highlighted the changes that are affected by that release.
1.0: URL rewriting with IIS 7 is now supported.
1.0: URL rewriting in a sub folder on Apache is now supported.
ColdFusion 9 is now supported.
Oracle 10g or later is now supported.
PostgreSQL is now supported.
Railo 3.1 is now supported.
1.0: There is now an app.cfm file in the config folder. Use it to set variables that you'd normally set in Application.cfc (i.e., this.name, this.sessionManagement, this.customTagPaths, etc.)
1.0: There is now a web.config file in the root.
1.0: There is now a Wheels.cfc file in the models folder.
1.0: The Wheels.cfc file in the controllers folder has been updated.
1.0: The IsapiRewrite4.ini and .htaccess files in the root have both been updated.
The controller folder has been changed to controllers.
The model folder has been changed to models.
The view folder has been changed to views.
Rename all of your CFCs in models and controllers to UpperCamelCase. So controller.cfc will become Controller.cfc, adminUser.cfc will become AdminUser.cfc, and so on.
All images must now be stored in the images folder, files in the files folder, JavaScript files in the javascripts folder, and CSS files in the stylesheets folder off of the root.
deletedOn, updatedOn, and createdOn are no longer available as auto-generated fields. Please change the names to deletedAt, updatedAt, and createdAt instead to get similar functionality, and make sure that they are of type datetime, timestamp, or equivalent.
Config Code
1.0: The action of the default route (home) has changed to wheels. The way configuration settings are done has changed quite a bit. To change a Wheels application setting, use the new set() function with the name of the Wheels property to change. (For example, <cfset set(dataSourceName="mydatasource")>.) To see a list of available Wheels settings, refer to the Configuration and Defaults chapter. Model Code
1.0: The extends attribute in models/Model.cfc should now be Wheels.
findById() is now called findByKey(). Additionally, its id argument is now named key instead. For composite keys, this argument will accept a comma-delimited list.
When using a model's findByKey() or findOne() functions, the found property is no longer available. Instead, the functions return false if the record was not found.
A model's errorsOn() function now always returns an array, even if there are no errors on the field. When there are errors for the field, the array elements will contain a struct with name, fieldName, and message elements.
The way callbacks are created has changed. There is now a method for each callback event ( beforeValidation(), beforeValidationOnCreate(), etc.) that should be called from your model's init() method. These methods take a single argument: the method within your model that should be invoked during the callback event. See the chapter on Object Callbacks for an example.
View Code
1.0: The contents of the views/wheels folder have been changed.
The wrapLabel argument in form helpers is now replaced with labelPlacement. Valid values for labelPlacement are before, after, and around.
The first argument for includePartial() has changed from name to partial. If you're referring to it through a named argument, you'll need to replace all instances with partial.
The variable that keeps a counter of the current record when using includePartial() with a query has been renamed from currentRow to current.
There is now an included wheels view folder in views. Be sure to copy that into your existing Wheels application if you're upgrading.
The location of the default layout has changed. It is now stored at /views/layout.cfm. Now controller-specific layouts are stored in their respective view folder as layout.cfm. For example, a custom layout for www.domain.com/about would be stored at /views/about/layout.cfm.
In linkTo(), the id argument is now called key. It now accepts a comma-delimited list in the case of composite keys.
The linkTo() function also accepts an object for the key argument, in which case it will automatically extract the keys from it for use in the hyperlink.
The linkTo() function can be used only for controller-, action-, and route-driven links now. * The url argument has been removed, so now all static links should be coded using a standard "a" tag.
Controller Code
1.0: The extends attribute in controllers/Controller.cfc should now be Wheels. Multiple-word controllers and actions are now word-delimited by hyphens in the URL. For example, if your controller is called SiteAdmin and the action is called editLayout, the URL to access that action would be http://www.domain.com/site-admin/edit-layout.
The default route for Wheels has changed from [controller]/[action]/[id] to [controller]/[action]/[key]. This is to support composite keys. The params.id value will now only be available as params.key.
You can now pass along composite keys in the URL. Delimit multiple keys with a comma. (If you want to use this feature, then you can't have a comma in the key value itself).
With a convention-over-configuration framework like CFWheels, it's important to know these conventions. This is your guide.
There is a specific set of standards that CFWheels follows when you run it in its default state. This is to save you time. With conventions in place, you can get started coding without worrying about configuring every little detail.
But it is important for you to know these conventions, especially if you're running an operating system and/or DBMS configuration that's picky about things like case sensitivity.
CFWheels uses a very flexible routing system to match your application's URLs to controllers, views, and parameters.
Within this routing system is a default route that handles many scenarios that you'll run across as a developer. The default route is mapped using the pattern [controller]/[action]/[key]
.
Consider this example URL:http://localhost/users/edit/12
http://localhost/users/edit/12
This maps to the Users
controller, edit
action, and a key of 12
. For all intents and purposes, this will load a view for editing a user with a primary key value in the database of 12
.
This URL pattern works up the chain and will also handle the following example URLs:
users
edit
12
users
new
users
index
Note that the above conventions are for GET
requests and only apply when you have a wildcard()
call in app/config/routes.cfm
(which is the default). See Routing for instructions on overriding this behavior and how to deal with PUT
, POST
etc.
Controllers, actions, and views are closely linked together by default. And how you name them will influence the URLs that CFWheels will generate.
First, a controller is a CFC file placed in the controllers
folder. It should be named in PascalCase
. For example, a site map controller would be stored at app/controllers/SiteMap.cfc
.
Multi-word controllers will be delimited by hyphens in their calling URLs. For example, a URL of /site-map
will reference the SiteMap
controller.
See Routing for instructions on overriding this behavior.
Methods within the controllers, known as actions, should be named in camelCase
.
Like with controllers, any time a capital letter is used in camelCase
, a hyphen will be used as a word delimiter in the corresponding URL. For example, a URL of /site-map/search-engines
will reference the searchEngines
action in the SiteMap
controller.
See Routing for instructions on overriding this behavior.
By default, view files are named after the action names and are stored in folders that correspond to controller names. Both the folder names and view file names should be all lowercase, and there is no word delimiter.
In our /site-map/search-engines
URL example, the corresponding view file would be stored at app/views/sitemap/searchengines.cfm
.
For information on overriding this behavior, refer to documentation for the renderView() function and read the Pages chapter.
A special type of view file called a layout defines markup that should surround the views loaded by the application. The default layout is stored at app/views/layout.cfm
and is automatically used by all views in the application.
Controller-level layouts can also be set automatically by creating a file called layout.cfm
and storing it in the given controller's view folder. For example, to create a layout for the users
controller, the file would be stored at app/views/users/layout.cfm
.
When a controller-level layout is present, it overrides the default layout stored in the root app/views
folder.
For information on overriding the layout file to be loaded by an action, see the chapter on Layouts and documentation for the renderView function.
By default, the names of CFWheels models, model properties, database tables, and database fields all relate to each other. CFWheels even sets a sensible default for the CFML data source used for database interactions.
By default, the datasource is set to wheels.dev
in the app/config/settings.cfm
file. You can change the value in the set(dataSourceName="wheels.dev")
function to whatever you want the name of the datasource to be.
Refer to the Configuration and Defaults chapter for instructions on overriding data source information.
CFWheels adopts a Rails-style naming conventions for database tables and model files. Think of a database table as a collection of model objects; therefore, it is named with a plural name. Think of a model object as a representation of a single record from the database table; therefore, it is named with a singular word.
For example, a user
model represents a record from the users
database table. CFWheels also recognizes plural patterns like binary/binaries
, mouse/mice
, child/children
, etc.
Like controller files, models are also CFCs and are named in PascalCase
. They are stored in the app/models
folder. So the user model would be stored at app/models/User.cfc
.
For instructions on overriding database naming conventions, refer to documentation for the table() function and the chapter on Object Relational Mapping.
In your database, both table names and column names should be lowercase. The customersegments
table could have fields called title
, regionid
, and incomelevel
, for example.
Because of CFML's case-insensitive nature, we recommend that you refer to model names and corresponding properties in camelCase
. This makes for easier readability in your application code.
In the customersegments
example above, you could refer to the properties in your CFML as title
, regionId
, and incomeLevel
to stick to CFML's Java-style roots. (Built-in CFML functions are often written in camelCase
and PascalCase
, after all.)
For information on overriding column and property names, refer to documentation for the property() function and the Object Relational Mapping chapter.
There are many default values and settings that you can tweak in CFWheels when you need to. Some of them are conventions and others are just configurations available for you to change. You can even change argument defaults for built-in CFWheels functions to keep your code DRYer.
For more details on what you can configure, read the Configuration and Defaults chapter.
These are the commands in the wheels generate
namespace. These commands are called by some of
the top level commands but you can use them directly to speed up your development process.
wheels generate
The wheels generate
command is what CommandBox calls a namespace and contains many sub commands beneath it. It's main purpose is to isolate those sub commands so there is no name collisions. It also has an alias of wheels g
which allows you to shorten the commands you have to type. However, we have opted to show all the commands with their full names in the list below.
wheels generate app-wizard
Creates a new CFWheels application using our wizard to gather all the necessary information. This is the recommended route to start a new application.
This command will ask for:
An Application Name (a new directory will be created with this name)
Template to use
A reload Password
A datasource name
What local cfengine you want to run
If using Lucee, do you want to setup a local h2 dev database
Do you want to initialize the app as a ForgeBox module
All these three commands are equivalent and will call the same wizard. The wizard in turn gathers all the required data and passes it all off to the wheels generate app
command to do all the heavy lifting.
Let's take a look at the wizard pages after issuing the wheels new
command:
You can accept the name offered or change it to whatever name you like. We try to clean up the name and take out special characters and spaces if we need to.
You can select a template to use for your app.
You can set what you want to use as your reload password or accept the default. Please make sure to change this before you go into production. Ideally this should be kept out of your source repository by using something like the (CFWheels DotEnvSettings Plugin)[https://www.forgebox.io/view/cfwheels-dotenvsettings].
The datasource is something you'll have to take care of unless you opt to use the H2 Embedded database in a Lucee server. Here you can define the datasource name if you would like to use something different than the application name.
In this step you can choose what CF Engine and version to launch. Lucee has an embedded SQL compliant database server called H2. So if you use one of the Lucee options you can specify to use the H2 database as well. Notice the last item allows you to specify the module slug or URI to a CF Engine not on the list.
On this step you are asked if you'd like to use the H2 Database, in which case we can set everything up for you, or if you would prefer to use another database engine and will take care of setting up the database yourself.
On this last step, you are asked if you want us to include a box.json file so you can eventually submit this to ForgeBox.io for sharing with the world.
This is the confirmation screen that shows all the choices you've made and gives you one last chance to bail out. If you choose to continue, the choices you've made will be sent over to the wheels g app
command to do the actual app creation.
If you opted to continue, you'll see a bunch of things scroll across your screen as the various items are downloaded and configured. Eventually you will see this status screen letting you know that everything was installed properly.
wheels generate app
Create a blank CFWheels app from one of our app templates or a template using a valid Endpoint ID which can come from ForgeBox, HTTP/S, git, github, etc.
By default an app named MyCFWheelsApp will be created in a sub directory called MyCFWheelsApp.
The most basic call...
This can be shortened to...
Here are the basic templates that are available for you that come from ForgeBox
CFWheels Base Template - Stable (default)
CFWheels Base Template - Bleeding Edge
CFWheels Template - HelloWorld
CFWheels Template - HelloDynamic
CFWheels Template - HelloPages
CFWheels Example App
CFWheels - TodoMVC - HTMX - Demo App
The template parameter can also be any valid Endpoint ID, which includes a Git repo or HTTP URL pointing to a package. So you can use this to publish your own templates to use to start new projects.
name
false
MyCFWheelsApp
The name of the app you want to create
template
false
base template
The name of the app template to use
directory
false
mycfwheelsapp/
The directory to create the app in
reloadPassword
false
ChangeMe
The reload password to set for the app
datasourceName
false
MyCFWheelsApp
The datasource name to set for the app
cfmlEngine
false
Lucee
The CFML engine to use for the app
setupH2
false
false
Setup the H2 database for development
init
false
false
"init" the directory as a package if it isn't already
force
false
false
Force installation into an none empty directory
wheels generate route
Adds a default resources Route to the routes table. All the normal CRUD routes are automatically added.
objectname
true
The name of the resource to add to the routes table
wheels generate controller
I generate a controller in the app/controllers/
directory. You can either pass in a list of actions to stub out or the standard CRUD methods will be generated.
Create a user controller with full CRUD methods
Create a user object with just "index" and "customaction" methods
name
true
Name of the controller to create without the .cfc
actionList
false
optional list of actions, comma delimited
directory
false
if for some reason you don't have your controllers in app/controllers/
wheels generate model
This command generates a model in the app/models/
folder and creates the associated DB Table using migrations.
Create "users" table and "User.cfc" in models:
Create just "User.cfc" in models:
name
true
Name of the model to create without the .cfc: assumes singular
db
false
Boolean attribute specifying if the database table should be generated as well
wheels generate property
This command generates a dbmigration file to add a property to an object and scaffold into _form.cfm and show.cfm if they exist (i.e, wheels generate property table columnName columnType).
Create the a string/textField property called firstname on the User model:
Create a boolean/Checkbox property called isActive on the User model with a default of 0:
Create a boolean/Checkbox property called hasActivated on the User model with a default of 1 (i.e, true):
Create a datetime/datetimepicker property called lastloggedin on the User model:
All columnType options: biginteger,binary,boolean,date,datetime,decimal,float,integer,string,limit,text,time,timestamp,uuid
name
true
Table Name
columnName
false
Name of Column
columnType
false
Type of Column on of biginteger, binary, boolean, date, datetime, decimal, float,integer, string, limit, text, time, timestamp, uuid
default
false
Default Value for column
null
false
Whether to allow null values
limit
false
character or integer size limit for column
precision
false
precision value for decimal columns, i.e. number of digits the column can hold
scale
false
scale value for decimal columns, i.e. number of digits that can be placed to the right of the decimal point (must be less than or equal to precision)
wheels generate view
This command generates a view file in the app/views/
directory when specifying the object name and the action. If a directory for the object does not exist a subdirectory will be created in the app/views/
directory and the action NAME.cfm file place into it.
Create a default file called show.cfm without a template
Create a default file called show.cfm using the default CRUD template
objectname
true
View path folder, i.e user
name
true
Name of the file to create, i.e, edit
template
false
template (used in Scaffolding) - options crud/_form,crud/edit,crud/index,crud/new,crud/show
The "crud/show" parameter of this command is referring to an existing template to be used to generate the "user/show" view. The prefix "crud" points to a templates directory in the app that holds a "crud" directory in which templates like "show" are placed. In this way the "crud/show" parameter fetches the show.txt template in the "templates/crud" directory and uses that for generating the "user/show" view.
wheels generate test
This command generates a test stub in /tests/Testbox/specs/TYPE/NAME.cfc
.
type
true
Type of test to generate. Options are model, controller, and view
objectname
true
View path folder or name of object, i.e user
name
true
Name of the action/view
One of a developer’s biggest time sinks is coming up with and writing accurate and engaging documentation. Even if it’s an internal project with.. well, just you… it’s still incredibly valuable to have: coming back to projects a few months or even years later can often lead to a bit of head scratching and screams of “why?”, especially with your own code.
Whilst we’re not promising that CFWheels will write all your documentation for you, we have put some tools in place to hopefully make the process a little less painful. With a small amount of adjustment in how you document your core functions, documentation doesn’t necessarily have to be such a time consuming process.
In the CFWheels core, we've adopted javadoc-style syntax (with a few twists of our own) to automatically create our main documentation, and there's nothing stopping you adding to this core set of documentation for your own app. It just needs a bit of markup.
The first thing to notice is the new ‘[Docs]’ link in the debug section in the footer: Following that link leads you to the main internal documentation.
The three-column layout is designed to allow for quick filtering by section or function name. On the right are the main CFWheels core categories, such as Controller and Model functions. These categories are further divided into subcategories, such as Flash and Pagination functions. Clicking on a link in the right column will filter the list in the left and middle columns to show all matching functions, including child functions of that category.
Filtering by function name is made simple by a “filter-as-you-type” search field in the left column, making it very quick to find the right function.
The middle column contains the main function definition, including tags, parameters and code samples.
Each function in the core is now appropriately marked up with javaDoc style comments. This, combined with getMetaData()
allows us to parse the markup into something useful.
Example Core Function
The [section]
and [category]
tags categorise the function as appropriate, and the @html
part describes the function’s parameter. The additional parameter data, such as whether it’s required, type and any defaults are automatically parsed too. This results in a display like:
Any function which is available to Controller.cfc
or Model.cfc
is automatically included; if there’s no javaDoc comment, then they’ll appear in uncategorized
. But of course, there’s nothing stopping you creating your own [section]
and [category]
tags, which will then automatically appear on the left hand column for filtering: you’re not restricted to what we’ve used in the core.
As an example, if you wanted to document all your filters, you might want to have a [section: Application]
tag, with [category: filters]
. This way, your application documentation grows as you create it.
Something as simple as a sublime text snippet for a new function which includes the basic javaDoc skeleton can get you in the habit pretty quickly!
We also introspect plugins for the same markup. We encourage plugin authors to adjust their plugin code to include [section: Plugins]
at the very least.
You can export the docs via JSON just by changing the URL string:
i.e ?controller=wheels&action=wheels&view=docs&type=core&format=json
You could also include the functions used to create the docs and create your own version (perhaps useful for a CMS or other application where you have internal documentation for authenticated users). Whilst this isn’t officially supported (the main functions may be subject to change!) it is technically possible. The best example is the thing itself – see the main output if you’re interested. Please note that the user interface isn’t available in production mode (for obvious reasons we hope!), so if you wanted to expose this data to an end user, you would probably need to “roll your own” with this approach.
Note that the CFC introspection doesn’t automatically happen on every request, so you will need to ?reload=true
to see changes to your code. Additionally, Adobe ColdFusion is more aggressive in caching CFC metadata, so depending on your settings, you may not see changes until a server restart.
Whilst the core has additional code samples which can be loaded from text files, there’s no support for your application functions to take advantage of this yet.
Whilst this API/function explorer is a great first step, you’ll notice your controller and model specific functions aren’t included (only those shared amongst controllers, or in the /app/global/functions.cfm
file. This is because we’re only looking at the main Model.cfc
and Controller.cfc
and what it can access.
In CFWheels 2.1, we’ll look at adding a full Controller and Model metadata explorer using the same techniques, and map functions like show()
to their respective routes too.
Environments that match your development stages.
CFWheels allows you to set up different environments that match stages in your development cycle. That way you can configure different values that match what services to call and how your app behaves based on where you are in your development.
The Development environment is the most convenient one to use as you start building your application because it does not cache any data. Therefore, if you make any changes to your controllers and actions, for example, it will immediately be picked up by CFWheels.
Other environment modes cache this information in order to speed up your application as much as possible. Making changes to the database in these most modes will cause CFWheels to throw an error. (Although that can be avoided with a reload
call. More on that later.)
The fastest environment mode in terms of page load time is the Production mode. This is what you should set your application to run in before you launch your website.
By default, all new applications will start in the Development environment which is middle-of-the-road in terms of convenience versus speed.
Besides the 2 environments mentioned above, there are 2 more. Let's go through them all one by one so you can see the differences between them and choose the most appropriate one given your current stage of development.
Development
Shows friendly CFWheels specific errors as well as regular ColdFusion errors on screen.
Does not email you when an error is encountered.
Caches controller and model initialization (the config()
methods).
Caches the database schema.
Caches routes.
Caches image information.
Production
Caches everything that the Development mode caches.
Activates all developer controlled caching (actions, pages, queries and partials).
Shows your custom error page when an error is encountered.
Shows your custom 404 page when a controller or action is not found.
Sends an email to you when an error is encountered.
Testing
Same caching settings as the Production mode but using the error handling of the Development mode. (Good for testing an application at its true speed while still getting errors reported on screen.)
Maintenance
Shows your custom maintenance page unless the requesting IP address or user agent is in the exception list (set by calling set(ipExceptions="127.0.0.1")
in app/config/settings.cfm
or passed along in the URL as except=127.0.0.1
, or as except=myuseragentstring
to match against the user agent instead. Please note that if passing an exception on the URL using the except
parameter, you must also provide the password
parameter if a reload password has been defined. This eliminates the possibility of a rogue actor breaking out of maintenance mode by simply adding an except
to the URL.
This environment mode comes in handy when you want to briefly take your website offline to upload changes or modify databases on production servers.
You can change the current environment by modifying the app/config/environment.cfm
file. After you've modified it, you need to either restart the ColdFusion service or issue a reload
request. (See below for more info.)
The reload Request
Issuing a reload request is the easiest way to go from one environment to another. It's done by passing in reload as a parameter in the URL, like this:
This tells CFWheels to reload the entire framework (it will also run your code in the app/events/onapplicationstart.cfm
file), thus picking up any changes made in the app/config/environment.cfm
file.
Lazy Reloading
There's also a shortcut for lazy developers who don't want to change this file at all. To use it, just issue the reload request like this instead:
This will make CFWheels skip your app/config/environment.cfm
file and just use the URL value instead (testing
, in this case).
Password-Protected Reloads
For added protection, you can set the reloadPassword
variable in app/config/settings.cfm
. When set, a reload request will only be honored when the correct password is also supplied, like this:
Don't forget your reload password in production
You really don't want random users hitting ?reload=development on a production server, as it could potentially expose data about your application and error messages. Always set a reload password!
If you're deploying to a container based environment, or one that you know you'll never want to switch out of production mode, you can disable URL based environment switching completely via:
set(allowEnvironmentSwitchViaUrl = false);
This is just an additional check to ensure that your production mode acts in the way you expect! Application reloading is still allowed, but the configuration can not be altered.\
Finding your way around a Wheels application.
After downloading and unzipping Wheels, here's the directory structure that you will see:
app/ build/ db/ docker/ guides/ public/ tests/ vendor/ .cfformat.json .editorconfig .env CFConfig.json box.json compose.yml server.json
Your configuration settings will be done in the app/config directory.
Your application code will end up in four of the folders, namely app/controllers, app/events, app/models, and app/views.
Static media files should be placed in the public/files, public/images, public/javascripts and public/stylesheets folders.
Place anything that need to be executed outside of the framework in the public/miscellaneous folder. The framework does not get involved when executing .cfm
files in this folder. (The empty Application.cfc
takes care of that.) Also, no URL rewriting will be performed in this folder, so it's a good fit for placing CFCs that need to be accessed remotely via <cfajaxproxy>
and Flash AMF binding, for example.
Place Wheels plugins in the app/plugins folder.
And the last directory? That's the framework itself. It exists in the vendor/wheels directory. Please go in there and have a look around. If you find anything you can improve or new features that you want to add, let us know!
Let's go through all the files and directories now, starting with the ones you'll spend most of your time in: the code directories.
This is where you create your controllers. You'll see a file in here already: Controller.cfc
. You can place functions inside this Controller.cfc
to have those functions shared between all the controllers you create(This works because all your controllers will extend Controller
.).
This is where you create your model files (or classes if you prefer that term). Each model file you create should map to one table in the database.
The setup in this directory is similar to the one for controllers, to share methods you can place them in the existing Model.cfc
file.
This is where you prepare the views for your users. As you work on your website, you will create one view directory for each controller.
If you want code executed when ColdFusion triggers an event, you can place it here (rather than directly in Application.cfc
).
Make all your configuration changes here. You can set the environment, routes, and other settings here. You can also override settings by making changes in the individual settings files that you see in the subdirectories.
Any files that you intend to deliver to the user using the sendFile()
function should be placed here. Even if you don't use that function to deliver files, this folder can still serve as file storage if you like.
For application-wide globally accessible functions
This is a good place to put your images. It's not required to have them here, but all Wheels functions that involve images will, by convention, assume they are stored here.
This is a good place to put your JavaScript files.
This is a good place to put your CSS files.
This is where unit tests for your application should go
Use this folder for code that you need to run completely outside of the framework. (There is an empty Application.cfc
file in here, which will prevent Wheels from taking part in the execution.)
This is most useful if you're using Flash to connect directly to a CFC via AMF binding or if you're using <cfajaxproxy>
in your views to bind directly to a CFC as well.
Place any plugins you have downloaded and want installed here.
Database Migration CFC files and generated SQL files (This directory will only visible once you start using the migrator)
This is the framework itself. When a new version of Wheels is released it is often enough to just drop it in here (unless there has been changes to the general folder structure).
This file is used by Apache, and you specifically need it for URL rewriting to work properly. If you're not using Apache, then you can safely delete it. No longer included by default in 2.x
URL rewriting for version 7 of IIS. If you're not using IIS, then you can safely delete it. No longer included by default in 2.x
These are needed for the framework to run. No changes should be done to these files.
You can add more directories if you want to, of course. Just remember to include a blank Application.cfc
in those directories. Otherwise, Wheels will try to get itself involved with those requests as well.
\
How Wheels handles an incoming request
Wheels is quite simple when it comes to figuring out how incoming requests map to code in your application. Let's look at a URL for an e-commerce website and dissect it a little.
But before we do that, a quick introduction to URLs in Wheels is in order.
URLs in Wheels generally look something like this:
It's also possible that the URLs will look like this in your application:
This happens when your web server does not support the cgi.path_info
variable.
Regardless of your specific setup, Wheels will try to figure out how to handle
the URLs. If Wheels fails to do this properly (i.e. you know that your web
server supports cgi.path_info
, but Wheels insists on creating the URLs with
the query string format), you can override it by setting URLRewriting
in
app/config/settings.cfm
to either On, Partial
, or Off
. The line of code should
look something like this:
"Partial URL Rewriting" is what we call that first URL up there with the
/index.cfm/
format.
In the example URLs used above, shop
is the name of the controller to call,
and products
is the name of the action to call on that controller.
Unless you're familiar with the Model-View-Controller pattern, you're probably wondering what controllers and actions are.
Put very simply, a controller takes an incoming request and, based on the parameters in the URL, decides what (if any) data to get from the model (which in most cases means your database), and decides which view (which in most cases means a CFML file producing HTML output) to display to the user.
An action is an entire process of executing code in the controller, including a view file and rendering the result to the browser. As you will see in the example below, an action usually maps directly to one specific function with the same name in the controller file.
For the remainder of this chapter, we'll type out the URLs in this shorter and prettier way.
Let's look a little closer at what happens when Wheels receives this example incoming request.
First, it will create an instance of the shop
controller
(app/controllers/Shop.cfc
) and call the function inside it named products
.
Let's show how the code for the products
function could look to make it more
clear what goes on:
Because Wheels favors convention over configuration, we can remove a lot of the code in the example above, and it will still work because Wheels will just guess what your intention is. Let's have a quick look at exactly what code can be removed and why.
Therefore, the code above can be changed to:
… and it will still work just fine.
That leaves you with this code:
That looks rather silly, a products
function with no code whatsoever. What do
you think will happen if you just remove that entire function, leaving you with
this code?
…If you guessed that Wheels will just assume you don't need any code for the
products
action and just want the view rendered directly, then you are correct.
In fact, if you have a completely blank controller like the one above, you can delete it from the file system altogether!
This is quite useful when you're just adding simple pages to a website and you
don't need the controller and model to be involved at all. For example, you can
create a file named about.cfm
in the app/views/home
folder and access it at
http://localhost/home/about
without having to create a specific controller
and/or action for it, assuming you're still using wildcard routing.
This also highlights the fact that Wheels is a very easy framework to get started in because you can basically program just as you normally would by creating simple pages like this and then gradually "Wheelsifying" your code as you learn the framework.
params
StructBesides making sure the correct code is executed, Wheels also does something
else to simplify request handling for you. It combines the url
and form
scopes into one. This is something that most CFML frameworks do as well. In
Wheels, it is done in the params
struct.
The params
struct is available to you in the controller and view files but
not in the model files. (It's considered a best practice to not mix your request
handling with your business logic.) Besides the form
and url
scope
variables, the params
struct also contains the current controller and action
name for easy reference.
If the same variable exists in both the url
and form
scopes, the value in
the form scope will take precedence.
To make this concept easier to grasp, imagine a login form on your website that
submits to http://localhost/account/login?sendTo=dashboard
with the variables
username
and password
present in the form. Your params
struct would look
like this:
Now instead of accessing the variables as url.sendTo
, form.username
, etc.,
you can just use the params
struct for all of them instead.
If you're constructing a JSON API, you're inevitably going to come across how to deal with "incoming" json packets to your routing endpoints. Instead of having to test each request with whether it's valid json etc, CFWheels will automatically map the JSON body in a request to the params struct, as long as it has application/json
as it's mime type.
So in the same way that the url
and form
scopes are merged, so a valid json
body would be. The exception to the rule is when a javascript array is the root element, where it's then added to params._json
to follow Rails conventions. (For obvious reasons, we can't merge an array into a struct!)
NOTE
The mapping of a json array to params._json was introduced in CFWheels 2.1
new
If you use Tomcat and Tuckey, or CommandBox , you'll need this file. Otherwise, you can safely delete it.
Mapping an incoming URL to code is only one side of the equation. You will also need a way to create these URLs. This is done through a variety of different functions like (for creating links), (for creating forms), and (for redirecting users), to name a few.
Internally, all of these functions use the same code to create the URL, namely the function. The function accepts a controller and an action argument, which are what you will use most of the time. It has a lot of other arguments and does some neat stuff (like defaulting to the current controller when you don't specifically pass one in). So check out the documentation for the function for all the details.
By the way, by using URL rewriting in Apache or IIS, you can completely get rid
of the index.cfm
part of the URL so that
http://localhost/index.cfm/shop/products
becomes
http://localhost/shop/products
. You can read more about this in the
chapter.
The only thing this does is specify the view page to render using the function.
The function is available to you because the shop
controller extends the main Wheels Controller
component. Don't forget to include that extends
attribute in your cfcomponent
call as you build your controllers!
So, how does work? Well, it accepts the arguments controller
and action
(among others, such as route
), and, based on these, it will try to include a view file. In our case, the view file is stored at app/views/shop/products.cfm
.
You can read the chapter about for more information about the function.
It's important to note that the function does not cause any controller actions or functions to be executed. It just specifies what view files to get content from. Keep this in mind going forward because it's a common assumption that it does. (Especially when you want to include the view page for another action, it's easy to jump to the incorrect conclusion that the code for that action would also get executed.)
The first thing Wheels assumes is that if you call without arguments, you want to include the view page for the current controller and action.
Does Wheels assume anything else? Sure it does. You can actually remove the entire call because Wheels will assume that you always want to call a view page when the processing in the controller is done. Wheels will call it for you behind the scenes.
This concept becomes even more useful once we start getting into creating forms specifically meant for accessing object properties. But let's save the details of all that for the chapter.
For more advanced URL-to-code mappings, you are encourage to use a concept called routing. It allows for you to fully customize every URL in your application, including which HTTP verb can be used. You can read more about this in the chapter called .