fat-code-refactoring-techniques icon indicating copy to clipboard operation
fat-code-refactoring-techniques copied to clipboard

RailsConf: Presenters

Open justin808 opened this issue 11 years ago • 2 comments

RailsConf 2014 Talk, Tuesday, 2:30, Ballroom 4, Concerns, Decorators, Presenters, Service Objects, Helpers, Help Me Decide!

Presenters

Code: Github Fat Code Refactoring Techniques Pull Request Presenters

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
  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:
        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.

Review on Reviewable

justin808 avatar Apr 18 '14 19:04 justin808

Regarding the coding style to set at most one instance variable in a controller action, what about having using controller filters (before_action) set instance variables?

I got that comment in response to whether or my Presenters pattern (https://github.com/justin808/fat-code-refactoring-techniques/pull/11) is justified.

Unless one uses such before_action filters to set other instance variables, what would be other alternatives than this "presenters" pattern?

justin808 avatar Apr 20 '14 19:04 justin808

Why do you make separate stereotypes for draper decorators and presenters ? Why not just use draper decorators as presenters and have multiple possible decorators for a given resource - a resource being an ActiveRecord, or an ActiveModel, or any kind of object which need to be manipulated by the controller.

If you have multiple draper decorators sharing behaviour, you could just use modules or concerns.

Systho avatar May 17 '14 15:05 Systho