RailsConf: Presenters

RailsConf 2014 Talk, Tuesday, 2:30, Ballroom 4, [Concerns, Decorators, Presenters, Service Objects, Helpers, Help Me Decide!](http://www.railsconf.com/program#prop_445)

# Presenters

Code: [Github Fat Code Refactoring Techniques Pull Request Presenters](https://github.com/justin808/fat-code-refactoring-techniques/pull/11/files)

Example: Added `FollowersPresenter` and `FollowedPresenter` to encapsulate
multiple instance variables in the show\_follow view.

**WARNING**: This code change is an over-simplified example of a good case of when
to encapsulate the state passed to a view. As you look at this example, consider
a case where there is far more logic in the view and the controller setup of the
instance variables for the view. 




## A Name for a PORO

-   Some Object for Complicated controller setup for a view
-   Terminology is controversial in the context of prior literature.
-   Trying to describe a object that sits between a controller method and
    a view.
-   Could have used "Facade", but..I didn't like it, and some others gave me a
    thumbs up on the term "Presenter".

## "Presenter"

-   Object used to facilitate presentation of data in the view, typically
    constructed in the controller method or maybe in the view.
-   Smooth sounding.
-   Easy to spell.

## Why?

1.  You're trying to reduce the number of instance variables assigned by the
    controller action to one.
2.  You want to consolidate the view specific Ruby code in one place, rather than
    being spread inside the ERB or HAML code.

## Presenter Applicable Situations

1.  Controller is initializing multiple instance variables for the view.
2.  Controller has several private methods supporting the public method
    associated with the action just to set up the context for the view.
3.  View has lots of inline Ruby code for calculating instance variables
4.  Logic is specific to one controller method and one view, or maybe a couple
    different response types for the same controller method.
5.  Numerous view helper methods interacting just for one action.
6.  If you find same code in multiple presenters for same model, then see if you
    can move to a decorator or concern. A module is another option for DRY'ing up
    duplication.

## Presenter Solution

-   Create directory `app/presenters` and add this code to
      `application.rb`
    
```ruby
  config.autoload_paths += %W(
    #{config.root}/app/presenters
  )
```

-   Create subdirectory `app/presenters/users`
-   Create presenter: `User::FollowPresenter`
-   Controller instantiates the `User::FollowPresenter` that is used by the view.
-   Move ruby code from view and the controller into the presenter.
-   Possibly include this snippet of code so that view instance methods
    are available:
    
```ruby
        include Draper::ViewHelpers
```

## Presenter Advantages

1.  Clearly bundles the code around the work the controller is doing and what the
    view needs.
2.  Simplifies code at the controller and view layers.
3.  Provides the possibility of unit testing the Presenter.
4.  Easy to group related methods and memoize instance variables, which can be
    highly beneficial if fragment caching is used, as compared to instantiating
    instance variables in the controller..
5.  Good place for the calculation of a complicated cache key rather than a view
    helper.

## Presenter Disadvantages

1.  There might be simpler techniques than creating another class and object, such
    as putting some logic in the Draper decorator or a view helper. A few lines of
    inline ruby code may work better than moving this code to a separate class.
2.  Other options for controller simplification include breaking up a controller
    into several classes and using controller concerns. However, those may not
    tackle the issue of passing too many instance variables into the view.
Does this here violate the "Law" of Demeter? The View here needs to know about the User model. It might be better to have a method named "user_name" in the presenter. This way the presenter is the only one that needs to know about the User model. The same could be said for "@presenter.user.microposts.count", although perhaps the User model (or some other object) should have a "microposts_count" method so that the presenter doesn't know about the Microposts model either.

This way, the view is no longer coupled to any other objects but the presenter. It's much easier to test, because you can easily stub out these methods, and it would be much easier to change implementation without breaking things.

Just a thought. :)

By the way, I really enjoyed your talk from RailsConf on this subject. It has given me lots to consider and try for myself. Great work!