1

I have often seen pattern 1 used the most for Rails presenters.

1) Why does the presenter need a view context?

2) Between pattern 1 and 2, pattern 2 seems easier, since you don't need to wrap the entire code with a block. Why isn't this used more often? Is there a downside to using this? vs pattern 1?

3) With pattern 3, why don't people use this pattern at all?

Presenter

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

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

class ApplicationPresenter < SimpleDelegator
  def initialize(model, view)
    @model, @view = model, view
    super(@model)
  end
end

Pattern 1


Using a presenter helper in the view with a block

View

<% @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 %>

Pattern 2


Using a presenter in the view and setting variable

View

<% @users.each do |u| %>
  <% user = UserPresenter.new(user, self) %>
    <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 %>

Pattern 3


Using the presenter in the controller, assuming you can pass the view context in using a solution like so. https://github.com/endofunky/oprah

UserController

def show
  @user = UserPresenter.new(User.find(params[:id]), view_context)
end

def index
   @users = Users.all.map {|user|  UserPresenter.new(user, view_context) }
end
Kris
  • 19,188
  • 9
  • 91
  • 111
user2012677
  • 5,465
  • 6
  • 51
  • 113
  • The Presenter pattern has many downsides, although this question may be closed as opinion based, maybe [read this post](https://gist.github.com/somebox/5a7ebf56e3236372eec4) – lacostenycoder Sep 21 '19 at 12:53

1 Answers1

2

1) Why does the presenter need a view context?

The view context allows access to view helps like link_to etc. which you normally would not be able to access in the presenter without including the necessary modules. For example you might do:

def deactivate_button
   view_context.link_to('Deactivate', '...', disabled: deactivated?)
end

2) Between pattern 1 and 2, pattern 2 seems easier, since you don't need to wrap the entire code with a block. Why isn't this used more often? Is there a downside to using this? vs pattern 1?

There is no practical difference other than with the block you get access to both the unpresented user and presented user. But do you need to access the unpresented user? I'd say not and would would prefer to use the non-block option.

3) With pattern 3, why don't people use this pattern at all?

They do and it is preferred to set a var in the controller than do it in the view.

Kris
  • 19,188
  • 9
  • 91
  • 111