Cleaner View Rendering in Rails

We've been using the "Presenter pattern" at ClearSight for some time now. Since everyone seems to have gotten used to the idea of only using one instance variable per controller action, we decided to take it one step further.

We avoid convenience methods such as current_user in the view and provide all data through the presenter in simple data structures rather than full ActiveRecord objects. It makes mocking and testing much easier if there isn't a reliance on exterior state or objects.

We also want to avoid setting any instance variables at all and instead provide a local variable via the locals hash.

Here's how we've accomplished it through POROs (plain old Ruby objects). We're pretty happy with this and excited about how clean it makes our code.

The Controller

To clean up the render action (no ugly locals hash), we provide a class method called build that returns the right hash:

class MyController < ApplicationController  
  def index
    render :index, MyIndexPresenter.build({
      people: User.all,
      current_user: current_user,
    })
  end
end  

The Presenter

Each presenter is something like this:

class MyIndexPresenter < AppPresenter  
  def people
    properties[:people].map do |person|
      {
        profile_url: "/user/#{person.id}",
        display_name: "#{person.first_name} #{person.last_name}",
      }
    end
  end

  def current_user_name
    properties[:current_user].display_name
  end
end  

Simple, direct, to the point. It exposes some convenient methods we can use in our view, referring to the properties hash which is set on initialization. It explicitly provides hashes for any collections (like this group of users above), giving the view only the data it needs in the format it needs.

The View

We use Slim, and our view might look something like this:

header  
  title = presenter.current_user_name
div  
  ul
    - presenter.people.each do |person|
      li = link_to person[:display_name], person[:profile_url]

The presenter local variable has exposed two methods to us, so we use those. In most cases, these are hashes or strings or integers -- no complex objects at all.

The AppPresenter

The AppPresenter is a PORO class that gives you just a few methods.

class AppPresenter  
  def self.build(args={})
    new(args).render_options
  end

  def initialize(args={})
    @properties = args
  end

  def properties
    @properties ||= {}
  end

  def render_options
    { locals: { presenter: self } }
  end
end  

The build method just conveniently calls new(args).render_options for us, so we can render cleanly in our controller (see above). It hangs onto properties that you pass into it, and the render_options method passes back to Rails's built-in render method the option hash it expects; mainly the locals: directive which tells it to expose the presenter to the view.

What do you think of this pattern? Pros, cons? Rails developers never have opinions about this stuff, right? ;-) Let me know on Twitter!