Rails Presenters

Episode #149 by Teacher's Avatar David Kimura

Summary

Separating view logic from bloated models can help maintain the model in the long run.
view rails 9:15

Resources

Download Source Code

Summary

# app/presenters/application_presenter.rb
class ApplicationPresenter < SimpleDelegator
  def initialize(model, view)
    @model, @view = model, view
    super(@model)
  end
end

# app/presenters/user_presenter.rb
class UserPresenter < ApplicationPresenter
  def full_name
    "#{@model.first_name} #{@model.last_name}"
  end

  def birth_year
    return nil unless @model.birthdate
    @model.birthdate.year
  end

  def nickel_per_year
    return nil unless @model.birthdate
    difference = Date.today.year - birth_year
    @view.number_to_currency(difference * 0.05)
  end
end

# app/helpers/application_helper.rb
module ApplicationHelper
  def present(model, presenter_class=nil)
    klass = presenter_class || "#{model.class}Presenter".constantize
    presenter = klass.new(model, self)
    yield(presenter) if block_given?
  end
end

# views/users/index.html.erb
<% @users.each do |u| %>
  <% present(u) do |user| %>
    <tr>
      <td><%= user.full_name %></td>
      <td><%= user.email %></td>
      <td><%= user.birthdate %></td>
      <td><%= user.birth_year %></td>
      <td><%= user.nickel_per_year %></td>
      <td><%= link_to 'Show', user %></td>
      <td><%= link_to 'Edit', edit_user_path(user) %></td>
      <td><%= link_to 'Destroy', user, method: :delete, data: { confirm: 'Are you sure?' } %></td>
    </tr>
  <% end %>
<% end %>