The Presenter Pattern With POROs for Rails Applications
When I first started making Rails applications, I ended up with views as shown in the below User Report Page code block after a while.
%h1 User Report Page
- @user.each do |user|
  - if user.exists?
    %p User exists
  - else
    %p User does not existI would check whether a user exists or not. If a user existed, I would display certain HTML markup. If you start trying to scale this type of logic over multiple lines, it becomes quite a mess to maintain.
Then I found out about the presenter pattern with POROs (Plain Old Ruby Objects).
What is a presenter pattern and why use it?
A presenter pattern takes your logic out of the views. It helps make your Rails views more maintainable.
Imagine if we started doing something more complicated such as displaying a different message if a user had an attached image file.
%h1 User Report Page
- @user.each do |user|
  - if user.exists? && user.has_image?
    %p User exists
  - elsif user.exists? && !user.has_image?
    %p User exists with no image
  - else
    %p User does not existHopefully, you are starting to see how messy the above can be to maintain. If we used a presenter pattern, our view code might look something like this:
%h1 User Report Page
- present(@user) do |user|
  %p= user.user_reportNotice how much cleaner the view looks! No conditional logic is needed in the view. Because of this, it will be easier to maintain.
Step 1 – Make a BasePresenter class
As a first step, let’s make a BasePresenter class that will house common behavior.
class BasePresenter < SimpleDelegator
  include ActionView::Helpers
  def initialize(model, view)
    @model, @view = model, view
    super(@model)
  end
  def h
    @view
  end
endStep 2 - Make a Presenter
Next, we make a presenter class that inherits from BasePresenter to encapsulate our “view” logic. In this example, I define a method called user_exists_message.
This method returns a message with some HTML markup regarding the existence of a User object.
class UserPresenter < BasePresenter
  def user_exists_message
    if @model.user_exists?
      h.content_tag(:h3, "User does not exist")
    else
      h.content_tag(:h3, "User exists")
    end
  end
endStep 3 - Testing Your Presenter
Finally, if you want to add tests in RSpec, you need to instantiate a view instance of ActionController::Base.new.view_context.
require 'spec_helper'
RSpec.describe UserPresenter do
  let(:view) { ActionController::Base.new.view_context }
  let(:user) { FactoryGirl.create(:user) }
  describe '#user_exists_message' do
    let(:user_presenter) { UserPresenter.new(user, view) }
    it "should say User exists" do
      expect(user_presenter.user_exists_message).to include("User exists")
    end
  end
endSummary
Use the Ruby language to create presenter patterns to simplify code in your views. The presenter pattern will help you maintain your views over the life of a code base.
