So you want to create a CFWheels application? (Part 6)

August 20, 2009 by Mike Henke    9 Comments
Posted under: CFWheels · ColdFusion

This CFWheels series is heavily borrowed from Dan Wilson's "So You Want to" series about Model Glue:Unity and matches to this post.

Previously in this series, we installed CFWheels, discussed some concepts in CFWheels, added our basic flow and navigation, created add and list functionality, added validation, and talked in more detail about the CFWheels ORM.

Here is a zip, if you want to start from this post. Unzip it in an empty webroot.

Today, we will cover the CFWheels ORM a little more. Specifically the return differences between some built in ORM calls and the logic why, specify the SQL order by clause and other sql fine-tuning, and build update and delete functionality.

Let's create an edit action in /Models/contact.cfc:

<cffunction name="edit">
<cfset newContact = model("contact").findByKey(key=params.key, include="type")>
<cfset newContact1 = model("contact").findOne(where="id=#params.key#", include="type")>
<cfset types = model("type").findAll() />

<cfdump var="#newContact1#"><br>
<cfdump var="#newContact#"><br>
<cfdump var="#types#">
<cfabort>
</cffunction>

Now add this <th>Actions<th> to the end of the first tr tag. And add this code to to the end of our last tr tag.<td>#linkTo(text="Edit", action="edit", key=allContacts.id)#</td> in \views\list.cfm.

\views\list.cfm should look like this now.

URL Rewriting On = http://localhost/contact/list

URL Rewriting Partial = http://localhost/index.cfm/contact/list

URL Rewriting Off = http://localhost/index.cfm?controller=contact&amp;amp;action=list

Click on an Edit link and you should see this:

What you see here is two objects and one query. You may think this is odd since you are using the CFWheels built in ORM and you thought the ORM calls would return the same structure. I thought the same thing but when talking to Per Djurner, it made perfect sense.

Here is what he said: "The convention is that when you are fetching a single record from the database (using findOne, findByKey etc) you will get an object back.When you are fetching multiple records you will get a query result set back. The "returnAs" argument is a way to override this convention (and it will be improved a little more before we release 1.0)."

"The reasoning behind the convention is that when you are asking the database for multiple records it is likely that you intend to display them (rather than edit/delete them). In this case objects are overkill (and even more so because of the poor performance of object creation in ColdFusion)."

See the CFWheels guys are always thinking. Don't be afraid to ask @ the CFWheels Google Group.

One other thing, I would like to point out is <cfset newContact1 = model("contact").findOne(where="id=#params.key#", include="type")>. See how, I easily added a where clause. This get the same results as <cfset newContact = model("contact").findByKey(key=params.key, include="type")>.

FindByKey(), FindOne() and FindAll() accept arguments as you can see from above. We are using the where clause and include for Associations. They also accept select, order, maxRows, and a couple arguments for pagination and caching.

For more Reading Records.

Remove from our edit action:

<cfdump var="#newContact1#"><br>
<cfdump var="#newContact#"><br>
<cfdump var="#types#">
<cfabort>

Test our Edit link again, and then update the contact. It should update the contact and return us to the List page

For more Updating Records.

Lets add order by to our list action in controllers/contact.cfc. Replace <cfset allContacts = model("contact").findAll(include="type") /> with <cfset allContacts = model("contact").findAll(include="type",order="name") />

And reload our list again.

See the SQL now has an "Order By" clause.

Lets wrap this entry up by adding delete functionality. Go to /Views/list.cfm, and add #linkTo(text="Delete", action="delete", key=allContacts.id)# after #linkTo(text="Edit", action="edit", key=allContacts.id)#.

In /Controllers/contact.cfc add:

<cffunction name="delete">
<!--- delete will return true or false depending on success --->
<cfif model("contact").findByKey(params.key).delete()>
<cfset flashInsert(success="Contact #params.key# was deleted.")>
<cfelse>
<cfset flashInsert(error="There was an error deleting the contact.")>
</cfif>
<cfset redirectTo(action="list")>
</cffunction>

Load our list again and you should see the delete link. Give it a try.

Success!

For more Deleting Records

We have a fully working Contact-O-Matic Application. Next in the series, I'll talk about Routing and Plugins in CFWheels.

9 Comments + Add Comment

  • Clarke

    In the 5th paragraph:

    "Let's create an edit action in /Models/contact.cfc:"

    Shouldn't that be /controllers/contact.cfc?

  • Mike Henke

    That is correct, good catch. Thanks. It should read "Let's create an edit action in /Controllers/contact.cfc:" These posts with the code coloring are a pain to edit.

  • Brian

    Yep, I got caught on this type-o too. :)

    A GREAT GREAT GREAT series Mike - I can't wait for the follow-up on Routing!

  • Brian

    Also, I think you may have wanted to add this to the EDIT controller in order to have a working edit page:

    <cfset renderPage(action="new") />

  • Brad

    Mike,

    Thanks so much for this series! You include a download file for the previous series and I was wondering if you can provide the final one as well. I'm missing the edit page for this series.

    I created the edit file in view/contact/edit.cfm with the following code.
    <cfoutput>
    #includePartial("banner")#
    <p>#errorMessagesFor("newContact")#</p>
    #startFormTag(action="edit")#
    <div>#textField(objectName="newContact", property="name", label="Contact")#</div>
    <div>#select(objectName="newContact", property="typeid_fk", options=types, label="Type", includeBlank="")#</div>
    <div>#submitTag()#</div>
    #endFormTag()#
    </cfoutput>

    In the controller/contact.cfc i have this code.
    <cffunction name="edit">
       <cfset newContact = model("contact").findByKey(key=params.key, include="type")>
          <cfset types = model("type").findAll() />
    <cfset newContact.Update()>

    </cffunction>

    when I submit the edit form i get an error "Element KEY is undefined in PARAMS."

    on line 33
    32 : <cffunction name="edit">
    33 :    <cfset newContact = model("contact").findByKey(key=params.key, include="type")>

    Thanks in advance for your help! I've learn so much and I can't wait to create my first Wheels application.

  • Brad

    After trouble shooting this issue further I think I'm missing the Update action in the contact controller. here is what I have but it's not working.

    <cffunction name="update">
       
          <cfset newContact = model("Contact").new(params.newContact)>

          <cfif newContact.update()>
             <cfset flashInsert(success="User #params.newContact.name# created successfully.") />
             <cfset redirectTo(action="list") />
          <cfelse>
       <cfset flashInsert(success="Unable to perform update.")>
             <cfset redirectTo(action="list") />
          </cfif>
    </cffunction>

  • Dave

    I have been trying to get the edit/update functions to work. I cannot figure it out. Do you have any complete code for this tutorial that I can download and look at to see where I'm going wrong?

  • Mike Henke

    Hi Dave,

    I don't have the sample code anymore for this series :-( Bad planning on my part. I do have some from my CFObjective presentation http://github.com/mhenke/cfobjective2010_wheels

    Also the google group would be a great place to paste your code and get some more help.

  • Dave

    Hi Mike,

    Thanks for the info. Too bad about the code, but I will check out your presentation. I've posted on the CFWheels group and will hopefully hear back soon.

  • Got anything to say? Go ahead and leave a comment!