I created this refactoring example for my RailsConf 2014 talk on refactoring fat controllers.
Here is the code for this example:
Please feel free to make comments in the PR or in this message thread. Thanks in advance for any feedback on this topic.
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 Facade???
- Fascades just don’t sound very positive to me!
-
http://www.merriam-webster.com/dictionary/facade
- the front of a building;
- a false, superficial, or artificial appearance or effect
- OK, too negative!
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.
Presenter Applicable Situation
- Controller is initializing multiple instance variables for the view.
- Controller has several private methods supporting the public method
associated with the action. - View has lots of inline Ruby code for calculating instance variables
- Logic is specific to one controller method and one view, or maybe a couple
different response types for the same controller method. - Numerous view helper methods interacting just for one action.
- 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 toapplication.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
- Clearly bundles the code around the work the controller is doing and what the
view needs. - Simplifies code at the controller and view layers.
- Provides the possibility of unit testing the Presenter.
- 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… - Good place for the calculation of a complicated cache key rather than a view
helper.
Presenter Disadvantages
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.