404 Error Handling in CFWheels
March 30, 2010 · Chris Peters
This is fairly simple, but I figured that I would share my approach for 404 error pages in CFWheels and see if anyone has a different/better way of doing it. This example demonstrates code used on cfwheels.org.
This is fairly simple, but I figured that I would share my approach for 404 error pages in CFWheels and see if anyone has a different/better way of doing it. This example demonstrates code used on cfwheels.org.
The Strategy
What I really wanted was a function that I could call whenever a given view’s record could not be found.
In my example case, I wanted to handle user IDs in the [CFWheels People Directory] that represent records that don’t exist. I had ended up removing user 31 (and a few others), so I wanted to display a helpful 404 error message every time http://cfwheels.org/user/profile/31 was accessed. (Note: the CFWheels People Directory doesn’t exist anymore.)
404 Error Page
So the first step was to create the 404 page itself, which I stored at views/main/error404.cfm.
| <cfset layout.title = "Page Not Found | ColdFusion on Wheels"> | |
| <cfset layout.header1 = "Page Not Found"> | |
| <cfset layout.breadcrumbs = ["Page Not Found"]> | |
| <!--- 404 error ---> | |
| <cfheader statuscode="404" statustext="Not Found"> | |
| <cfoutput> | |
| <p> | |
| We're sorry. We couldn't find the page that you're looking for. It has either been removed, or perhaps | |
| you are accessing an inaccurate <abbr title="Uniform Resource Locator">URL</abbr>. | |
| </p> | |
| <h2><label for="search-query-404">Search</label></h2> | |
| #startFormTag(controller="search", id="cse-search-box", method="get")# | |
| <div> | |
| <input type="hidden" name="cx" value="005724978648843866544:jpej79qhz14" /> | |
| <input type="hidden" name="cof" value="FORID:10" /> | |
| <input type="hidden" name="ie" value="UTF-8" /> | |
| <input id="search-query-404" type="text" name="q" /> | |
| <input type="submit" name="sa" value="Search" /> | |
| </div> | |
| #endFormTag()# | |
| <h2>Start from the Home Page</h2> | |
| <p><strong>#linkTo(text="ColdFusion on Wheels Home »", route="home")#</strong></p> | |
| </cfoutput> |
The real meat is the fact that I put the <cfheader> 404 reference in the view file. I look at anything that’s sent to the browser as a job for the view to handle, so that’s why I put the call there instead of in the controller file. In fact, because the page is fairly “dumb,” I didn’t put anything in the Main controller.
Rendering Helper
I also put a quick render404() function in the base controller at controllers/Controller.cfc so that I wouldn’t need to manually call renderPage(controller="main", action="error404") every time that I wanted to reference this new view. Your preference may be to not do this, but I’ll leave that up to you.
| <cffunction name="render404" hint="Renders a 404 error page."> | |
| <cfset renderPage(controller="main", action="error404")> | |
| </cffunction> |
Handling 404 Errors in the Controller
The last step involved actually using this functionality in the case that an invalid record ID was passed in the URL. So the user/profile action now looks like this:
| <cffunction name="profile" hint="Displays user profile."> | |
| <cfset user = model("customer").findByKey(params.key)> | |
| <cfset loggedInUser = getLoggedInCustomer()> | |
| <!--- If profile found, show it ---> | |
| <cfif IsObject(user)> | |
| <cfset sites = user.sites(where="isApproved=1")> | |
| <cfset plugins = user.plugins(where="isApproved=1")> | |
| <!--- 404 error if not found ---> | |
| <cfelse> | |
| <cfset render404()> | |
| </cfif> | |
| </cffunction> |
Fairly simple stuff. When loading the user object, I check to see if an object was returned. If not, then show the 404 page. Pretty reusable, and it only requires an additional if/else block in the controller to decide what to do.
Plus the file at events/onmissingtemplate.cfm can just use <cfhttp> to phone http://cfwheels.org/main/error404 in order to display the exact same error message during a more generic “template not found” scenario.
Besides identifying other places in the application to call render404(), that’s pretty much it.
