Parameter objects
Here is a technique I’m experimenting with on gomore.dk. I suspect that I’m reinventing some pattern here. Please let me know in the comments if you recognize it.
When searching for rides on Gomore, users may specify from-location, to-location and a date. For the locations I use the Google Places API, giving the user access to the nice autocompleter commonly known from Google Maps. This also means that the chosen location is geocoded on the client side.
The date can be entered manually or chosen in a jQuery UI date picker.
This can go wrong in so many ways:
- Location is not geocoded for some reason. Happens a lot with older browsers.
- Browser screws up date format (we’ve seen a leading minus sign!)
- Invalid dates, dates in the past etc.
The controller to handle these parameters was getting way too complicated from
supporting all these cases. Also, testing controllers can be pretty painful, so
I decided to pull this complexity out to a separate class, SearchParams
. Not
the best name, but the best I could come up with at the time.
I expect to use this pattern for several other actions, so I created a home for these classes: app/params
This class is reponsible for cleaning up all parameters to the search action.
This means that it is tightly coupled to the this action, which is OK. If I need
to reuse some of this (eg. the code to clean up dates), I can easily pull
it out to a separate class which can be used from several Params
classes.
Obviously the goal here is that the controller can assume that all parameters are OK and the complexity goes away.
Let’s see some code.
app/params/search_params.rb
In the controller, I create a SearchParams
object from the params
. Then, two
method calls make it very clear how the params are processed:
- Force encoding
- Geocode if necessary
More than this happens, but these are the steps that are not naturally linked
to fetching a parameter value. For example, the #timestamp
method handles
dates in the past and other cases.
Next, we need to decide whether to render the search results or redirect. This decision is delegated to the search params object. If the parameters were OK to begin with, we proceed to render the search results. If not, we redirect using the corrected params. This prevents the user from ever seeing (and sharing) invalid search URLs.
app/controllers/rides_controller.rb
I’ve glossed over a lot of details in this writeup, but I hope you found it useful anyway. Let me know if something needs to be clarified.