CFWheels in Use at the OII

Obviously, I’ve been a fan of CFWheels for a fair while now. So naturally, when the opportunity came to build a new app from scratch, there was only one real contender.

At the Oxford Internet Institute (OII) – where you can find me from 9-5 (most of the time) – we’ve primarily been a research department, with no students. This changed a few years ago, with the introduction of a DPhil programme, and more recently, an MSc programme.

Naturally, when you throw 30 students a year together, and another 20 or so tutors/lecturers, you’re going to need some sort of organisational/courseware app. For the first year or two, we tried Wikis, Sakai, trialled Moodle, kept well away from Blackboard (due to licensing) but none of them quite did what we wanted them to. They all were built for another purpose – delivering complete courses online, or managing things we didn’t need, creating a lot of UI clutter.

Enter the new CFWheels app, nicknamed ‘Plato’ (not officially called Plato, as I think there’s *already* some existing courseware with that name). Let’s call it cfPlato then.

The aim was to build a closed system which fullfilled the following:

  • To list courses, their outlines and who’s teaching them
  • For Tutors to communicate with their students via bulk email
  • A complete email archive for all courses and groups
  • File storage, with archiving, tagging and bulk downloading via .zip
  • Individual user accounts
  • File submission
  • Deadline listings with notifications
  • Threaded discussion via Forums
  • Facilities for smaller groups, similar to courses
  • Multiple user roles, such as tutor, student, administrator etc.
  • Full logging and audit trail
  • Avatar uploading and cropping
  • Ability for students to provide anonymous Course feedback

I can up with the idea that we should give access to pretty much everything to authenticated users, then allow student to ‘subscribe’ to their areas of interest; Subscribing means they get email notifications etc, and various shortcuts in the system to their courses of choice. Whilst this puts the responsibility of subscribing to courses in the hands of the students, it removes a large administrative overhead.

As this is currently a closed system, I can’t demo it properly, but I thought it might interest other people to get an idea of the sort of apps which are starting to spring up based on CFWheels.

Tonnes of screenshots here as a Flickr slideshow. Turn on Descriptions/comments for some more info:

http://www.flickr.com/photos/oxfordalto/sets/72157625977093921/show/

Built using CFWheels, CF8, BlueprintCSS, JQuery, JQuery Tools, TinyMCE, JCrop.

Comments & Questions welcome!

CFWheels – logging the flash

One of the most useful features of CFWheels is ‘the Flash’.

Essentially, it’s a session scope which is designed to carry messages over page redirects, and only remove itself once it’s actually been viewed by the user.
I usually use it when a user has updated, deleted or requested something which requires some sort of feedback – like a password reset, a profile change etc.
Using filters, we can start using these flash scope messages as a basic logging device; did the user see an error message when they tried to update their profile? Was their password change successful? Were they told about it? etc.
In my Users.cfc controller, I’ve got one important line which makes this possible;

<cfset filters(through="logFlash", type="after")>

This means after any function in my Users.cfc controller is executed, logFlash() is called.

And in my Controller.cfc (where functions which may be required by all controllers live), I’ve got the two logging functions called logFlash, and addLogLine:

 
<cffunction name="logFlash" hint="Grabs the message in the flash scope and logs it">
<cfif structkeyexists(session.flash, "error")>
<cfset addLogLine(name=session.flash.error, type="error")>
</cfif>
<cfif structkeyexists(session.flash, "success")>
<cfset addLogLine(name=session.flash.success, type="success")>
</cfif>
</cffunction>

This function looks for struct keys of ‘error’ or ‘success’  in the flash scope and calls addLogLine() – this example creates a db row in a table called logfiles, but you could easily rewrite this to suit your needs (i.e email you, or write to a static file): I’m also logging the current userid, what type of message it was, and the calling IP address – plus I’m using createdAt in the logFiles table to automatically timestamp the entry.

 
<cffunction name="addLogLine" hint="Manually add a log line">
<cfargument name="name" required="yes" hint="The Actual Log Message">
<cfargument name="type" required="no" default="admin" hint="example options: public | admin | login | file | error | success">
<cfif NOT structkeyexists(session, "currentUser")>
<cfset thisuserid=0>
<cfelse>
<cfset thisuserid=session.currentUser.username>
</cfif>
<cfset logline=model("logfile").create(name=arguments.name, userid=thisuserid, 
type=arguments.type, ip=cgi.REMOTE_ADDR)>
<cfreturn true />
</cffunction>

Overall, a really useful way of working out what the user is seeing, and once you’ve set up these functions, calling them from other controllers is simply a matter of adding one line!

CFWheels – Don’t forget your filter

One of the features of CFWheels which I’ve been guilty of ignoring in the past is the combination ‘filter’ and init().

In your controller model, you have two really powerful tools at your disposal. The init() function, which runs before each request to the controller, can allow you to do lots of preprocessing logic, and make sure everything is ‘good to go’ with displaying your view. The filter function, when combined with init(), means you can call specific functions for a view, and keep any recurring code out of the view function itself.

I often have caught myself doing this multiple times in a controller (in this case, users.cfc)

<!---View User--->
<cffunction name="view">
<cfset currentuser=model("user").findOneByUsername(session.currentUser.email)>
</cffunction>

<!---Edit User--->
<cffunction name="edit">
<cfset currentuser=model("user").findOneByUsername(session.currentUser.email)>
</cffunction>

etc.

All I want is the current Users data, and often I’d want it for the view, list, edit functions etc. If you find that you’re repeating code in wheels, stop and ask your self whether there’s a better way.

Using the init function and filter, we can replace each call by simply writing the function once, and popping the call to the function in the filter. So:

<!--- init --->
<cffunction name="init">
<!---Filters--->
<cfset filters(through="getCurrentUser", only="view,edit")> 
</cffunction>

<!--- My new private function --->
<cffunction name="getCurrentUser" access="private">
<cfset currentuser=model("user").findOneByUsername(session.currentUser.email)>
</cffunction>

This means our object of currentuser is now available to the view and edit functions. We could also add some checks to see whether the session is valid, the object is returned, etc. Your resulting function might look something like this:

<cffunction name="getCurrentUser" access="private">
<cfif structkeyexists(session.currentuser, 'email')>
<cfset currentuser=model("user").findOneByUsername(session.currentUser.email)>
<cfif NOT isObject(currentuser)>
<cfset userError()>
</cfif>
<cfelse>
<cfset userError()>
</cfif>
</cffunction>

<!---An additional private function to throw a user related error--->
<cffunction name="userError" access="private">
<cfset flashInsert(error="User Not Found")>
<cfset redirectTo(back=true)>
</cffunction>

Once you get your head round this relatively simple principle, it makes creating your controllers very quick indeed..!

CFWheels Wallpaper

Ok, so I had 5 minutes to myself; inspired by the Model Glue Wallpapers I saw the other day (http://www.model-glue.com/wallpaper.cfm) I thought I’d brush up on my Photoshop skills, and do some CFWheels based ones.

Enjoy the below! All are 1920×1200.

Select Multiple Values for select() CFWheels

Just found this nice little feature, which is basically undocumented..

There are two Form helpers for drop down select boxes in CfWheels – one is the standard selectTag(), and the other is select() which will bind itself to an object automatically. The selectTag() function is just designed for bog standard forms with no object property.

In CfWheels, you can pass normal HTML attributes into the form helpers, like ‘id’, ‘class’ etc.. these are largely undocumented in the CfWheels docs, as they’re well, fairly obvious.

What I’ve just found, which plesantly surprised me, is that you can pass ‘multiple=true’ into the select() form helper, and if the corresponding object’s value is a comma deliminated list, it automatically puts in the necessary markers for it to be selected: this is one step up from the standard logic of just passing through the attribute, as CfWheels seems to be doing conditional statements to determine whether it’s selected or not. Nice.

So with the following (with the options ‘allBlocks’ being a query of available blocks):

#select(objectName="page", 
    multiple='true', 
    label="Prepend to Content", 
    property="prepend_blockid", 
    options=allBlocks)#

If in my object ‘page’, page.prepend_blockid = ’1,4,5,6,7′, then wheels will automatically give me

<select id=“page-prepend_blockid” multiple=“multiple” name=“page[prepend_blockid]“>
<option value=“”></option>
<option selected=“selected” value=“1″>About Menu Block</option>
<option value=“2″>About Us Quick Text</option>
<option value=“3″>Site Information Menu</option>
<option selected=“selected” value=“4″>What We Do Menu Block</option>
<option selected=“selected” value=“5″>Google Search Form</option>
<option selected=“selected” value=“6″>Contact Form</option>
<option selected=“selected” value=“7″>Twitter Update</option>
<option value=“8″>Resources Menu</option>
<option value=“9″>Latest 5 Webcasts</option>
<option value=“10″>Latest 5 Podcasts</option>
</select>

Starting out with CfWheels + jQuery + Colorbox

One of the things I’m writing at the moment is a fairly complex bespoke content management system. I’ve done a fair few CMSes in my time, but most of them have had relatively simple back ends – you know the type, where you’ve got a separate ‘admin’ section, which in CF terms is often a completely different application; this is usually for authentication’s sake (let’s face it, it’s fairly easy to secure an entire application.cfc) and to keep it relatively contained in a single folder.

As I’ve been playing around with CfWheels of late, I thought I’d force myself to use it with this project, as for me, that’s usually the best way to learn something – plus I always had the ‘get out’ clause of being able to override internal wheels behaviour if needed. Wheels instantly throws you into a different mindset when it comes to CMS-like apps; as there are various conventions like MVC and ORM already in place, it makes sense to approach everything from that ‘wheels’ point of view.

As building forms is so insanely easy in wheels (see the form helpers), I very quickly got to the point where I started to crave a little more interaction; especially when starting to deal with many to many relationships, and how to update those. But my main objective was to break out of the ‘separate-page-in-a-different-application-to-update’ mindset.

Enter jQuery & colorbox based forms. Having not really played around with jQuery that much (I know, I know) I’ve been pretty shocked about how quickly I managed to pull together some proof of concept forms. Add something like colorbox into the mix, and suddenly you’ve got instant editing ability from any page in your application, without going to have to find the entry in the admin section.

I’m going to try my best to explain where I’ve got to, with the usual caveats – there’s almost always a better way to do this, and I’ve probably just not come across it yet – so comments welcomed..

I’m going to assume you have a basic wheels framework in place, complete with your datasource. For this example, I’m just going to concentrate on one controller and a couple of views.

Starting up – the layout file

The first thing is to include the necessary JS & CSS files, so in my layout.cfm file I’ve got

#styleSheetLinkTag(sources="colorbox", media="screen,projection")#
#javaScriptIncludeTag("jquery-1.3.2,jquery.colorbox")#

The Main View page

We need a page view which will output our page object, and provide our edit link: so in /views/pages/view.cfm you might have something like this:

<cfparam name="page">
<cfoutput><p class="admin-links">
#linkTo(text="Edit This Page", class="colorbox", action="edit", key=page.id)#
</p>
#page.content#
</cfoutput>

Note the class=”colorbox” – this we will use later to tie in the form submission with javascript. So this page is essentially providing a link which points at /pages/edit/[pageid].

Next, we need a form:

In my /views/pages folder, I’ve got a ‘partial’ called _form.cfm, which is basically a view designed to be called without layout.

#startFormTag(action="update")#
#hiddenField(objectName="page", property="id")#
#textArea(objectName="page", property="content")#
#submitTag()#
#endFormTag()#

Nothing too unusual there, move along..

Controller: Pages.cfc

In this file, i’ve got 3 functions: A view, edit and update function. The edit function is fired when the form is loaded, and the update function is fired on the submission of the form.

<cffunction name="view">
     <cfset page = model("page").findAllBySESURL(value=params.title)>
</cffunction>

<cffunction name="edit">
     <cfset page = model("page").findByKey(key=params.key)>
      <cfset renderPartial("pageform")>
</cffunction>
        
<cffunction name="update">
     <cfset page = model("page").findByKey(params.page.id)>
     <cfset page.update(params.page)>      
     <cfif page.hasErrors()>             
             <cfset flashInsert(error="Page Content couldn't update.")>
             <cfset redirectTo(back=true)>
     <cfelse>
            <cfset flashInsert(success="Page Content updated successfully.")>
            <cfset redirectTo(back=true)>
     </cfif>
 </cffunction>

Note the renderPartial(“form”) line. This makes wheels look for a “_form.cfm” file in my /views/pages/ folder. The other bit of note is ‘redirectTo(back=true)’ – this closes the modal window and updates our initial page.

Tie it all together:

The last bit is just the javascript to tie the link into loading the form in a modal window:

 <script type="text/javascript">
 $(document).ready(function(){
$(".colorbox").colorbox({
                         transition: 'fade',
                         speed: 200
  });
 </script>

This tells colorbox to open any link with a class of .colorbox.

So really, it’s three simple things to remember:

  • opening the form via colorbox requires a class/id in the link (at least, that’s one way of doing it, there are many others)
  • Using partials in modal windows means you don’t have to have the layout, and you can reuse that form from anywhere (you could also use renderPage(layout=false))
  • Using redirectTo(back=true) does refresh the page, but the most important thing is, you’ve not really left it due to the overlay.

Using Helicon ISAPI_Rewrite 3 with cfwheels URL rewriting

Maybe one for the cfwheels docs..

The URL rewriting chapter in the CFWheels docs mentions Ionic’s ISAPI Rewrite Filter. However, I’ve got a machine which is running IIS6 and version 3 of the Helicon Tech ISAPI rewrite module. Version 3 of this module uses .htaccess, rather than the .ini files of version 2.

If you’re planning on running CFWheels with full rewriting using Version 3 of this module, you’ll need to modify the .htaccess file supplied for use with apache. Don’t worry, it’s just a full stop (that’s period to you USA people) needs removing..

in the last line:

RewriteRule ^(.*)$ ./rewrite.cfm/$1 [L]

Should read

RewriteRule ^(.*)$ /rewrite.cfm/$1 [L]

Then it appears to play nicely.

Discovering CFWheels

I’ve spent the past week or so with my head down, coding, and completely loving it.

CFWheels is a CFML framework based on Ruby on Rails – at least it shares a lot of the same concepts from what I can tell. My previous experience with frameworks hasn’t been too great. I got put off the ‘big player’ names like Model Glue, Fusebox et al, as when I investigated them (admittedly a few of years ago) I got instantly put off by XML configuration, and quite frankly, some concepts I just couldn’t grasp at the time. Also, loading 100’s of templates for the apps I was writing at the time was just unnecessary.

Maybe the timing’s good, but I’ve been blown away by CFWheels.

My own coding style has changed a lot in the last 12 – 36 months, and I was getting to the point where I was writing lots of custom code to do certain things – a good example would be URL rewriting – each application I’d write would have similar, if not the same requirements. I’m a big fan of logical and symantically meaningful URL paths, and where I can, I’ve been trying to gradually make all my apps follow some sort of pattern. Once you find something which works, you basically cut and paste it into every new app you make, and each application might it’s own quirks, meaning you have multiple, similar versions of the same block of code.

Basic CRUD operations too – it’s incredible how much code I’ve written over the years which is based around what I’d call a ‘CRUD switch’ – i.e  a cfswitch block with cases of ‘view,add,edit,delete’. Almost without realising it , I’d been gradually moving towards the MVC pattern of coding, it just made sense.

Enter CFWheels: I downloaded it, and started playing. Within about 2-3 hours, I’d mastered enough of the basics to port an existing (simple) site over. I even got to the point where I was using an internal Wheels function, and just *guessed* what the arguments should have been; low and behold, it worked. When you find a framework which actually ‘thinks’ like you do, it’s a pretty great feeling.

My particular highlights thus far:

  • Basic jawdropping when I realised the power of the internal ORM engine.
  • ‘Routes’ – very, very useful.
  • The separate configuration setting options for development/design/production etc
  • Caching is, well, just painless.
  • HasMany() – running out of superlatives, but to be able to say, ‘Departments hasMany People’ and then in the People model, ‘People BelongsTo Departments’, and then refer directly to the relationship without a line of SQL? cool.
  • The Form Helpers save a lot of code.
  • The CFWheels Google group guys have been really helpful, and the documentation is excellent.
  • The Global Helpers bit is very useful, previously, you’d have to cache all your Utility functions in a CFC and chuck it in the Application scope – now you just add it to one place to make it available to all your views.
  • All the internal Wheels functions – when I’d hit a point where I thought ‘there should be a function for this’, there was.
  • It’s fast. Especially on Railo (disclaimer: it just ‘feels’ fast! And no, i’ve not tried it on CF9, and no, I’ve got no figures to back this one up)

Naturally, some low points too:

  • Note to self: don’t casually, or accidently dump extremely large objects on a production server. It appears to eat up RAM very quickly.
  • Associations – amazing concept, but out of everything, took me the longest time to get my head around; then I found ‘shortcuts’ and it all made sense.
  • I did get initially confused when something which I expected to be a query turned out to be an object..(then I found you can override that behaviour!)
  • The routes system could really do with a better ‘catchall’ system – it works, but I don’t want to have to specify all my controllers routes: I want Wheels to introspect them and work it out 🙂 (I’m aware there is talk going on re: this issue)
  • I still want to see some more example applications of best practice / example apps generally.
  • It took me a while to be comfortable with *NOT* scoping everything 🙂

All in all, I’m really enjoying this one, and it’s made me reconsider my previously (slight naïve) position on frameworks.

Well worth a couple of hours of your life to try.

http://cfwheels.org/