Rails View Adapter
Closely related to the Presenter Pattern, we have been recently applying a similar approach in order to achieve thinner Controllers responding with name/value pair based data, in order to achieve Views which are decoupled from the rest of our application’s layers.
The main ViewAdapter module looks something like this:
require "ostruct"
module ViewAdapter
module ClassMethods
def prepare(records)
records.map do |record|
view_data = OpenStruct.new
yield view_data, record
view_data
end
end
end
extend ClassMethods
def self.included(receiver)
receiver.extend(ClassMethods)
end
end
Each View Adapter includes the ViewAdapter module which allows for a clean, easily testable, declarative setup of the View Data that will be eventually rendered on the screen.
class ConcertViewAdapter
include ViewAdapter
def concerts
prepare Concert.find(:all) do |view_data, concert|
view_data.artist = concert.artist
view_data.venue = concert.venue
view_data.price = concert.currency + concert.price
end
end
end
As a general rule, we maintain a one-to-one relationship between the Controllers and the corresponding View Adapters.
class ConcertsController < ApplicationController
def index
@concerts = ConcertViewAdapter.concerts
end
end
These Adapters are mainly used to consolidate and format data, as returned by a Controller’s action, for display.
Advantages/Trade-offs
Distinct decoupling of the View from the rest of the application layers which provides a single, well known point of maintenance to accommodate easy code changes or refactorings.
Established codebase location for view logic and formatting operations. Particularly useful for internationalization.
Easily testable. Tests for the View Adapters can run as part of a Fast Rails Test Suite because they don’t require any Rails environment setup.
As a possible downside, this approach will break some of the standard Rails view helpers which depend on ActiveRecord objects being exposed in ERB templates. I personally do not consider this a big issue, because I don’t find much benefit in most of these HTML helpers, especially considering the way they cross MVC boundaries by exposing Domain Objects to the View, or mask relatively straightforward mark up.

September 7th, 2007 at 6:12 pm
Sprinkle a little meta-programming and you can dry up the common case of one-to-one mapping, here’s a really bad sample syntax:
copy_to_adapter :artist, :venue
You get the idea…