Working with collections of objects

A common problem when displaying data comes when we display collections of objects that contain collections of other objects.

I solved this for myself in a simple way with my existing presenters.

My application needed to display search results from an event management system and we called this the Agenda. Our agenda had sessions, days, and time slots and we needed a way to handle presentation details for all of them.

All of these items needed their own code, but we only needed to work with them together. From the start, we didn’t break these presenters out into separate files.

This kept our related details together and kept us focused in one place.

Custom iterators

When in came to using these in our view templates, we didn’t want to leak knowledge of the object classes into the views. From the start, a simple approach would be to initialize the presenters where you need them. Here’s what it could have looked like in our ERB files:

This creates the each_session method which accepts a block that we use for each session in the collection.

The first part of this method may look strange: we initialize a SessionPresenter wrapping nil and providing the view object.

The presenter requires some object to initialize properly and since we’re setting the session object later, we can just use nil as a placeholder. But we do this so that we can avoid creating a new presenter with each iteration of the block.

While this would work, there’s no need to create a new presenter object each time. Our handy session= method does the trick.

Benefits of custom iterators

Providing our own iteration method gave us the ability to change the behavior as we needed. If we merely rely on an Array with agenda.sessions.each, we’re tied to that dependecy.

If we decide we don’t need a SessionPresenter at all, we don’t need to change our view code, we’d only need to remove that from our each_session method.

Following the pattern

We had this need for custom iterators in several places (sessions, days, and time slots) so we have an established pattern. The next step was to move this to our Presenter class so we didn’t have to rewrite the same procedure each time.

The only differences between our iterators were the collection of objects (sessions, days, and time slots) and the class of the presenters needed.

We went back to our SimpleDelegator __setobj__ method to avoid knowledge about the domain of the presenter.

Iterating over and presenting items from our collections became so much easier and our views so much simpler. This allowed us to treat our views more like readable configuration. A title method called in the view template could be the actual title from our wrapped object just passing the data through, or, as we change our requirements, could become anything else without requiring changes to our template.