Coldfusion On Wheels, the forgotten framework

Published February 8, 2007 on adamfortuna

    One framework that was unfortunately not represented at the Frameworks Conference was Coldfusion on Wheels . Although it was heavily developed at first, it's started to split off with some question of the direction it's going in. The idea is that it will be a port of Ruby on Rails for Coldfusion. There are a lot of concerns that people put out about Rails structure, one of those being that it's impossible to use it without the model layer bleeding into the controller. Coldfusion on Wheels at the moment is in a big state of flux, but ColdFusion on Wheels 0.6 Lite comes without the model layer at all. On my way home from the frameworks conference I decided to give this framework some time on the plane home and was pleasantly surprised with the status of the project, and the flexibility of the current version. Getting it setup Downloading the latest lite version of the framework requires no real setup actually. The current version must be in document root from what I have been able to gather though so keep that in mind. The core framework files reside in the "cfhweels” folder which can be removed from the main app and mapped in cf administrator. Search Engine Safe URLs One of the initial draws for me was to see just how the url rewriting works. For those unfamiliar with Ruby On Rails or CF Wheels, these two offer what's known as search engine safe (SES) URLs where the URLs no longer have query parameters in them 9for the most part). For instance, instead of referring to a page like http://localhost/index.cfm?event=user.profile&id=123 , a search engine safe URL might be something like http://localhost/user/profile/123 . The end result of this is that it's (supposedly) better for search engines and (definitely) better for the user when trying to type in URLs. CF Wheels handles this in both IIS and apache (tested both to work) in their own ways. For apache it uses the familar .htaccess tag, while in IIS it relies on Isapi Rewrite . What's important with both of these is that it's optional, and requires no knowledge of how .htaccess or isapi rewrite rules work. Those files are static and do one thing but do it well. They translate a link like http://localhost/user/profile/123 to something like <http://localhost/dispatch.cfm?wheelsaction=> /user/profile/123 The key factor being that you can opt to use these safe URLs or not, it's up to you. So what does this resolve to? Well that's configured in the /config/routes.ini file. By default there are three routes already: [cfm] [/cfm] What this means is that when this request comes in, it will go through those and find the first one it matches. In this case it'll be the first one because it has 3 parameters, controller, action, id. Think of this as calling the user.profile action, to put it in fuseaction terms. In that action, there will be a variable defined, request.params.id, which contains the value 123 in this case. To expand on that a little, you could easily add another route if we wanted the username in the url instead of the id. So if we wanted something like this: http://localhost/user/profile/AdamFortuna We could add another router in our routes.ini file that looks like this: [cfm][/cfm] The same user.profile action will be executed, but there will be a variable defined, request.params.username, with the value "AdamFortuna”. Sounds easy enough, doesn't it? CF Wheels handles this completely internally using routes. Although I haven't traced through the code for this, the end result is the same as rails. Webserver setup I grabbed this piece of code from the CF Wheels Google Group , which works on my 2.0.59 apache setup as well as the posters 2.2.x installation: [xml] ServerName cfwheelsroottest DocumentRoot "C:/inetpub/devroot/cfwheelsroottest” AllowOverride All [/xml] I like to edit my local hosts file so that 127.0.0.2 will resolve to the name of the site I'm working with as well. So locally I'll go to dev.mysitename.com and due to the hosts file addition (note hosts file is in C:WindowsSystem32driversetchosts) this will resolve to my local website instead of the actual one. Easy way to test things locally. In order to get safe URLs setup in IIS, you must be able to modify the isapi filters and add in a new one. For shared hosting in IIS you might not be able to run this feature of wheels, but if you have control over this it's a very easy install. Form helpers URL rewriting is one thing that's helpful for it to handle, as otherwise there is a lot more work involved in getting something like this setup, but there's one other very helpful feature that is so simple to implement in any language that it might be overlooked — grouping form inputs from a form in an easy to use manner. What I mean might best be explained with an HTML example. Lets look at a sample form for a user to signup for a site. [html]Username:Email:Password:Password Again:[/html] When this is submitted, it'll go to the user controller, and the create action with the contents of th form. Similar to the URL parameters above, they will be available in the request.params variable. Note the naming convention in there though — user[username]. Wheels translates this a little bit before it gets to your controller, and turns request.params.user into a structure containing username, email, password and password_confirmation. Does this sound like anything? request.params.user is a transfer object! If the UserDAO is cofigured in Coldspring and Reactor, you could do something like this to insert this record. [cfm][/cfm] With that one line in your controller, you'd technically have everything you need to insert the form values assuming the form is complete. Putting it all together To be realistic though, you have to take into account a few more things. Obviously this shouldn't be run when they call the user/create page, it should be run when thy submit the form. Also, what if there are errors? What if we have more related fields so it's not just dealing with the user but a few other things? Well, I'm not quite there yet in some of those cases, but we can make it a little cleaner. As I said, this version of cfwheels has no model components, it is ONLY a controller. The question is what do you want in your framework? Brian Koteks presentation on Designing framework agnostic models showed just how little the framework can handle, and how important it can be to have things defined in a service layer. So what if you use Cfwheels with this service layer? Turns out it plays pretty well. First a little preliminary information about cfwheels setup. In the app/controllers directory, you'll have controllers whose names match the controllers in your urls. So those requests to /user/create will go to /app/controllers/user_controller.cfc, with the create() method being called. Consider this the application logic that exists to execute your service layer. This would be in your controllers in Model-Glue, your circuit.xml (or act pages) in fusebox- - that kind of logic. After that it will automatically run a view associated with that page (unless overwritten in that create() method). The view page that it would run is located in /app/views/user/create.cfm. So looking at that URL you can know you need to mess with the create() method and that other display page. What does that create() method look like? [cfm] [/cfm] Whats this do? Well, if that user structure exists within the request.params structure then we create the new user, generate a message saying it was successful and redirect the user to a new page. Otherwise we get a new blank user object filled in with any defaults. Without getting too far into how the service layer is setup, it's basically the same as in Brian Koteks examples. our create() method in the service looks like this… [cfm] [/cfm] This just passes on that value to reactor which does the real work. In my working examples this is done in a BaseService which is extended by the UserService, but I'll get more into that another time, once I figure out how to get error handling and multiple table inserts working easily. CF Wheels is certainly a lot farther along than I would've thought it to be. Although it has no model components for which rails earns a lot of it's fame, that can be easily substituted with a service layer generated by coldspring and reactor.