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&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.