Loading "Extra" Queries for a Form in CFWheels
11/23/2011
Many times, you’ll see this sort of situation when writing a form, where you need to load "extra" queries for things like state and country selectors:
There are many ways that you can load the data that this view template is requiring, each with their pros and cons. I’ll cover 3 different approaches.
Approach #1: Use before filters to stay DRY
One way to solve this problem in the controller is to run before filters on the new, create, edit, and update actions:
Notice the call to filters() in init() to load the $setStates() and $setCountries() private filter methods.
Yes, this works. But one problem is that you only need to load states and countries if the form needs to be shown with errors. On create and update, those queries may not even need to be run, but they’re running anyway. Why hit the database if you don’t need to?
Depending on your caching strategy, this may not matter if you are caching the findAll() calls. But let’s say that you are running at least one of those queries in real time. How do you avoid running them if you don’t need them?
Approach #2: Limiting the use of filters and calling them manually in create and update
An approach that alleviates that problem is to limit the before filters to new and edit and only run them when needed in create and update:
Notice the modified call to filters() in init() and the manual calls to $setStates() and $setCountries() in the create and update actions.
This is better because now the states and countries are only being loaded when absolutely needed. This does make things slightly less DRY, but it’s not too bad of a trade-off.
Approach #3: Using automatic data functions to load data for the form
Yet another approach is to factor out the form into a partial and use what’s called an automatic data function to load the extra queries.
So the view template changes to this (which you may be doing anyway):
And now you create a partial:
You may now notice that the countries and states variables are now being referenced in the arguments scope. That’s because we’re going to load them from an automatic data function.
The controller should now look like this:
The true points of interest in this example are the init() and form(). We’re now no longer running before filters in init() to load the states and countries.
Also, there is a new private method named form() that acts as an automatic data function. Every time you call a partial, Wheels checks for a method in your controller with the name of the partial, private access, and a return type of struct. If it finds that method, it’ll run it and merge the struct that it returns into the arguments scope in the view.
So form() is only being run when the form is shown via the call to #includePartial("form")#. And the data loading is still happening in the controller where it belongs.
I’ve only begun playing around with this method and so far have been enjoying the results. I am slightly torn because I like the “self-documenting” nature of declaring filters in init(), but that method does have the caveat that I mentioned before. The automatic data function solves this problem, but it does make the functionality a little less obvious. You need to remember the extra step of checking to see if there is a method in the controller with the same name as the partial when you run across one.
Has anyone else play with this method? If so, how has this worked out for you?

Nice post Chris! I’ll give this a try in my apps. I must ask though… is this feature even documented on the Wheels website? I had no idea this was even an option until I read this.
Also, I’m dying for someone to help me understand how to write test for my Wheels applications. I’m tired of my apps breaking but testing using RocketUnit or MXUnit + Wheels confuses me. I need to be able to test the models, the controllers, and the views. The only thing I can find is a few partial writeups on the matter here http://code.google.com/p/cfwheels/w/list but they’ve only confused me more.
Thanks Grant.
Yes, the feature is documented:
1. See the “Automatic Calls to a Data Function” section in the Partials chapter.
2. There is also an argument for includePartial called dataFunction if you need to override which method it calls on the controller.
3. I blogged about automatic data functions back in 2010 just before we released version 1.1 of Wheels.
Yes, the docs/system for testing is a mess. Man, I wish there was something like rspec and Cucumber for ColdFusion, but everyone is stuck in Test::Unit-style land in the CFML world.
i never understood why we don't have a filter that fires before and after the view renderer gets called. then approach #1 would be the perfect choice since the filters would only fire if the logic got to the point of actually rendering the view template. another approach is obviously creating private method that you call in each action that you want to use it in. it's kind of the manual way of doing the automatic data function, but it's still an option.
Yeah, it's almost as if you could apply the "callback" principle to the controller. beforeRequest, afterRequest, beforeRender, afterRender, etc.
Filters are pretty sweet though.
Thanks Chris! Somehow I missed this feature in the documentation :-(
With Wheels, is it currently possible to test output from your views or test for variables set in the controllers like Rails? If anyone is currently doing this in their Wheels apps, I'd love to know how. If not, is this something we can expect to be included in Wheels in the near future?