Loading “Extra” Queries for a Form in CFWheels
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
Notice the call to
init() to load the
$setCountries() private filter methods.
Yes, this works. But one problem is that you only need to load
countries if the form needs to be shown with errors. On
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
An approach that alleviates that problem is to limit the before filters to
edit and only run them when needed in
Notice the modified call to
init() and the manual calls to
$setCountries() in the
update actions. This is better because now the
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
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
form(). We’re now no longer running before filters in
init() to load the
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.
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?