Class: BasePresenter

Inherits:
Object
  • Object
show all
Extended by:
Forwardable
Defined in:
app/presenters/base_presenter.rb

Overview

A BasePresenter object represents a resource (i.e. data object) in the view layer of application delivery.

Creation

You create a Presenter object by subclassing BasePresenter:

class ProjectPresenter < BasePresenter
end

The constructor takes the resource as its single parameter:

p = Project.new(:name => "Test project")
presenter = ProjectPresenter.new(p)

This presenter is not yet capable of anything:

presenter.name # => NoMethodError: ...

You can easily create delegates to existing attributes of the represented resource:

class ProjectPresenter < BasePresenter
  def_delegators :project, :name, :description
end

This creates a Presenter class for Project objects and delegates the name and description attributes to the original project object.

presenter.name # => "Test project"

Exposing presenters through the controller

To use presenter objects in the view layer, we can expose them through the controller. This works by defining which instance variables should be available as presenter objects in the view layer.

class ProjectController < ApplicationController
  expose_presenters :project, :projects
end

This defines two (helper-)methods project and projects, that look up @project and @projects and convert them to presenter objects.

Now, the following view code works:

<h1><%= project.name %></h1>

Adding custom methods

Adding custom methods enables you to represent information in a context-sensitive way:

class ProjectPresenter < BasePresenter
  def_delegators :project, :name, :description

  def label
    if project.active?
      project.name
    else
      "[OLD] " + project.name
    end
  end
end

presenter.label # => "Test project"
presenter.active = false
presenter.label # => "[OLD] Test project"

Using presenters for associations

To illustrate this suppose we have a model Station that is associated with a Project.

class StationPresenter
  def_delegators :branch, :project
end

p = BranchPresenter.new(...).project # => Project
p.label # => NoMethodError: ...

This is because the project method is delegated to the resource and returns such a data object itself. This is were use_presenters helps:

class BranchPresenter
  use_presenters :project
end

p = BranchPresenter.new(...).project # => ProjectPresenter
p.label # => "[OLD] Test project"

Defined Under Namespace

Modules: ControllerMethods

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(resource) ⇒ BasePresenter

Returns a new instance of BasePresenter.

Parameters:


98
99
100
# File 'app/presenters/base_presenter.rb', line 98

def initialize(resource)
  @resource = resource
end

Class Method Details

.inherited(subclass) ⇒ void

This method returns an undefined value.

Defines a reader method named according to the presenter that returns the presenters resource, so can refer to your data object in a natural way.

Example:

class ProjectPresenter < BasePresenter
  def label
    if project.active?
      project.name
    else
      "[OLD] " + project.name
    end
  end
end

136
137
138
139
# File 'app/presenters/base_presenter.rb', line 136

def inherited(subclass)
  name = subclass.to_s.gsub(/Presenter$/, '').split("::").last.underscore
  subclass.__send__(:define_method, name) { @resource }
end

.use_presenters(*names) ⇒ void

This method returns an undefined value.

Defines associations which should return a Presenter object rather than an ActiveRecord object.

Example:

class StationPresenter
  def_delegators :station, :project
end

StationPresenter.new(...).project # => Project

class StationPresenter
  use_presenters :project
end

StationPresenter.new(...).project # => ProjectPresenter

159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
# File 'app/presenters/base_presenter.rb', line 159

def use_presenters(*names)
  names.each do |name|
    define_method(name) do
      if var = instance_variable_get("@#{name}")
        var
      else
        var = @resource.__send__(name)
        if var
          if var.respond_to?(:map)
            instance_variable_set "@#{name}", var.map(&:to_presenter)
          else
            instance_variable_set "@#{name}", var.to_presenter
          end
        end
      end
    end
  end
end

Instance Method Details

#to_modelActiveRecord::Base, Object

Returns the actual resource object the presenter is representing.

Example:

p = Project.new
ProjectPresenter.new(p).to_model # => p

In this case to_model returns the original Project object.

This is called by rails helper methods (e.g. 'dom_id')

Returns:


114
115
116
# File 'app/presenters/base_presenter.rb', line 114

def to_model
  @resource
end