← Back to Upcase

Draper Decorator Refactoring Example


(Justin Gordon) #1

I created this refactoring example for my RailsConf 2014 talk on refactoring fat controllers.

Here is the code for this example:

https://github.com/justin808/fat-code-refactoring-techniques/pull/4

Please feel free to make comments in the PR or in this message thread. Thanks in advance for any feedback on this topic.

Draper Decorator

Draper Steps

  1. Add gem 'draper'= and run =bundle
  2. Run Draper generator: rails generate decorator User, which creates
    app/decorators/user_decorator.rb and
    spec/decorators/user_decorator_spec.rb.
  3. Move presentation specific view code to decorator.
    1. Put h. in front of calls to helpers.
    2. Remove references to the model in the decorator, as the method is
      essentially on the model.
    3. Call model.decorate to get a decorated instance of the model.

Draper Applicable Situations

  1. Extension to model that only applies to views and presentation.
  2. Calculations done in view using model object.
  3. Code in view helper that is more closely aligned with the model.
  4. Code is that seems relatively general as opposed to clearly useful in only
    one view.
  5. If method feels relatively generic for views, but specific for a given model,
    then the decorator is a good place to put the method.

Draper Advantages

  1. Relatively simple way to add functionality to the model that only applies to the
    connection of the model to the view.
  2. Can separate presentation specific code from the model.
  3. Methods added to the model via the decorator have access to both view helper
    methods as well as the model.
  4. It’s super easy to automatically convert the retrieved model object into it’s
    decorated instance, either manually or automatically, at the controller
    layer.
  5. Simple to find the decorator methods, such as using for verification in
    feature specs.

Draper Disadvantages

  1. Shares similar problems with concerns in that the model object is still
    getting fatter.
  2. If there’s multiple methods needed for some complex logic, that should be
    broken into it’s own PORO.
  3. The advantage of ease of adding more methods can also be a disadvantage in
    that the Decorator can turn into a junk-drawer of loosely coupled methods.

(Aaron Mc Adam) #2

The app I work on has definitely hit disadvantage 3! The few decorators that were added have become junk drawers that have attracted lots of unrelated methods. I don’t think that’s Draper’s fault really, it’s just very convenient to add yet another method to a decorator.