Presenter

A presenter (facade) base class.

Declaring Presenters

When you declare a presenter in a Presentability collection, the result is a subclass of Presentability::Presenter. The main way of defining a Presenter’s functionality is via the ::expose method, which marks an attribute of the underlying entity object (the “subject”) for exposure.

class MyPresenter < Presentability::Presenter
  expose :name
end

# Assuming `entity_object' has a "name" attribute...
presenter = MyPresenter.new( entity_object )
presenter.apply
# => { :name => "entity name" }

Presenter Collections

Setting up classes manually like this is one option, but Presentability also lets you set them up as a collection, which is what further examples will assume for brevity:

module MyPresenters
  extend Presentability

  presenter_for( EntityObject ) do
    expose :name
  end

end

Complex Exposures

Sometimes you want to do more than just use the presented entity’s values as-is. There are a number of ways to do this.

The first of these is to provide a block when exposing an attribute. The subject of the presenter is available to the block via the subject method:

require 'time'

presenter_for( LogEvent ) do
  # Turn Time objects into RFC2822-formatted time strings
  expose :timestamp do
    self.subject.timestamp.rfc2822
  end

end

You can also declare the exposure using a regular method with the same name:

require 'time'

presenter_for( LogEvent ) do
  # Turn Time objects into RFC2822-formatted time strings
  expose :timestamp

  def timestamp
    return self.subject.timestamp.rfc2822
  end

end

This can be used to add presence checks:

require 'time'

presenter_for( LogEvent ) do
  # Require that presented entities have an `id` attribute
  expose :id do
    id = self.subject.id or raise "no `id' for %p" % [ self.subject ]
    raise "`id' for %p is blank!" % [ self.subject ] if id.blank?

    return id
  end
end

or conditional exposures:

presenter_for( Acme::Product ) do

  # Truncate the long description if presented as part of a collection
  expose :detailed_description do
    desc = self.subject.detailed_description
    if self.options[:in_collection]
      return desc[0..15] + '...'
    else
      return desc
    end
  end

end

Exposure Aliases

If you want to expose a field but use a different name in the resulting data structure, you can use the :as option in the exposure declaration:

presenter_for( LogEvent ) do
  expose :timestamp, as: :created_at
end

presenter = MyPresenter.new( log_event )
presenter.apply
# => { :created_at => '2023-02-01 12:34:02.155365 -0800' }