---
title: Tidy Views and Beyond with Decorators
teaser:
tags: web,ruby,testing,rails,good code
author: Harold Giménez
published_on: 2011-12-02
---

## The problem

Here's a view serving `monkeys#show`. What's wrong with it?

```erb
<% if @monkey.eating? %>
  <div class="eating">
    <%= @monkey.name -%> is eating. Nom nom
  </div>
<% elsif @monkey.sleeping? %>
  <div class="sleeping">
    <%= @monkey.name  %> cannot be bothered right now
  </div>
<% end %>

<div id="banana-status">
  <% if @monkey.bananas.any? %>
    <div class="banana-count">
      The monkey has had <%= @monkey.bananas_count %> bananas so far
    </div>
  <% else %>
    <div class="hungry">
      The monkey should really have a banana or two
    </div>
  <% end %>
</div>

<div id="sidebar">
  <div id="favorite-dip-sauces">
    <% if @monkey.bananas.any? %>
      <%= @monkey.bananas.map(&:dip_sauce).to_sentence -%>
    <% else %>
      Eat some bananas first
    <% end %>
  </div>
</div>
```

There's quite a bit of logic going on here. Monkeys have different states with
both DOM classes and copy changes based on it.

Not only that, but banana consumption also introduces a few branches in our view
code, increasing markup complexity and threatening maintainability. Now imagine
this view is for a real app where it's probably much larger and complex.

What if instead we were working with the following

```erb
<div class="<%= @monkey.state_class -%>">
  <%= @monkey.status_message -%>
</div>

<div id="banana-status">
  <div class="<%= @banana.status_class -%>">
    <%= @bananas.count_message -%>
  </div>
</div>

<div id="sidebar">
  <div id="favorite-dip-sauces">
    <%= @bananas.favorite_dip_sauces -%>
  </div>
</div>
```

Curious? Good. Here's how you do it:

![''](http://stillwatters.files.wordpress.com/2011/05/monkey_banana_crazy.jpg)

## The pattern

Let's look at how we can simplify this view by introducing a few objects that
collaborate with monkeys and bananas to cleanly get at the required logic.

What we need is an object that behaves just like a monkey but with some added
presentation behavior: a Decorator. A decorator allows you to add, replace or
extend an object's behavior based on its runtime characteristics without
resorting to any metaprogramming hacks.  It is an object that wraps another
object adding any required functionality, and proxies the interface you care
about to original decorated object.

## The refactor

We decorate a monkey object with the appropriate messages and DOM classes based
on it's state:

```ruby
class MonkeysController < ApplicationController
  def show
    @monkey = decorated_monkey(Monkey.find(params[:id]))
  end

  protected
  def decorated_monkey(monkey)
    if monkey.eating?
      EatingMonkey.new(monkey)
    elsif monkey.sleeping?
      SleepingMonkey.new(monkey)
    else
      raise NoMoreMonkeysJumpingOnTheBed
    end
  end
end
```

The implementation for the eating and sleeping monkeys are quite simple:

```ruby
class EatingMonkey
  def initialize(monkey)
    @monkey = monkey
  end

  def state_class
    "eating"
  end

  def state_message
    "#{@monkey.name} is eating. Nom nom."
  end

  def name
    @monkey.name
  end
end

class SleepingMonkey
  def initialize(monkey)
    @monkey = monkey
  end

  def state_class
    "sleeping"
  end

  def state_message
    "#{@monkey.name} cannot be bothered right now"
  end

  def name
    @monkey.name
  end
end
```

They are merely extending the monkey object with some view related logic. The
view establishes a contract that that all monkey-like object must adhere to, but
that's it. Note that decorators also proxy message invokations to the wrapped
object. In this case we're forwarding the `name` method. Some folks will use
`method_missing` to proxy all method calls over, but I'm of the mind that you
should only expose the interface you care about and nothing more. This also
helps document the actual contract established between the view and its
collaborators.

The result is a view that  is much smaller, easier to work with and extend. Not
only that, but the system is now also trivial to test. Here's an example for the
`state_message` method on `EatingMonkey`

```ruby
describe EatingMonkey do
  it "displays that it's eating on the state_message" do
    monkey = stub(:monkey, name: 'George')
    EatingMonkey.new(monkey).state_message.should match /George.*eating/
  end
end
```

This test is great. It's simple, verifies behavior and &#8212; because we pass
in a thin test double &#8212; it informs us of the expected interface of the
wrapped object: an
[unobstrusive](https://thoughtbot.com/blog/post/10125070413/unobtrusive-ruby)
thing that responds to `name`.

These are great improvements already, but we shouldn't stop there. We still have
some view logic around bananas that is used to control two sections of our view:
the `banana-status` as well as the `sidebar`. The two cases we need to think
about is when a monkey has eaten bananas, and when it hasn't.

When it has eaten bananas, we can supply a wrapper object that helps present it.
When it hasn't, we have the special case of an empty collection. The NullObject
pattern that you learned about on [Josh's
post](https://thoughtbot.com/blog/post/12179019201/design-patterns-in-the-wild-null-object)
works well.

```ruby
class MonkeysController < ApplicationController
  def show
    bananas = monkey.bananas
    if bananas.any?
      @bananas = Bananas.new(bananas)
    else
      @bananas = EmptyBananas.new
    end
  end
end

class Bananas
  def initialize(bananas)
    @bananas = bananas
  end

  def status_class
    "banana-count"
  end

  def count
    @bananas.size
  end

  def count_message
    "The monkey has had %{ count } bananas so far"
  end

  def favorite_dip_suaces
    @bananas.map(&:dip_sauce).to_sentence
  end
end

class EmptyBananas
  def status_class
    "hungry"
  end

  def count_message
    "The monkey should really have a banana or two"
  end

  def favorite_dip_suaces
    "Eat some bananas first"
  end
end
```

## The OO Principles at work

We can also think of these improvements in terms of a few Object-Oriented design
principles:

* The system obeys the *Tell don't Ask* principle where you should tell an
  object to do something as opposed to extracting data from it and implementing
  behavior on the caller code. Here, instead of asking a monkey if it is eating
  in order to display a state message, we tell it to give us the message
  simplifying and [removing branches](http://www.antiifcampaign.com/) from the
  client code.
* By not polluting the Monkey model, we're also obeying the *Single
  Responsability Principle* where every object should have only one
  responsability and it should be encapsulated by one class. The Monkey class
  handles database finders, field abstraction, and data consistency via
  validations, not more than that. On the other hand, the decorators handle
  presentation related state and logic while delegating to Monkey when
  appropriate.
* Finally, it obeys the *Open/Closed Principle* where each object is open for
  extension but closed for modification. There is no reason to modify the Monkey
  class in order to add the required behavior. Instead we extend a monkey's
  behavior with another set of collaborating objects.

## Not only for views

Decorators are not only useful as view cleanup, although it is a very common use
case. Jeff Casimir's [draper](https://github.com/jcasimir/draper) is a gem that
embodies the pattern and also allows you to invoke Rails' view helpers by
exposing the view context in your decorators.

But Decorators are useful in other scenarios as well. For example, you could use
them to handle all the types of notifications should occur when saving a record
without resorting to a nasty callback soup:

```ruby
class UserCreatedNotifier
  def initialize(saveable)
    @saveable = saveable
  end

  def save
    Mailer.user_created(@saveable).deliver
    @saveable.save
  end
end
```

Maybe in some cases an admin should be notified as well:

```ruby
class UserCreatedAdminNotifier
  def initialize(saveable)
    @saveable = saveable
  end

  def save
    AdminMailer.user_created(@saveable).deliver
    @saveable.save
  end
end
```

This frees your User model from complex state or parameter checking in an
already complex callback chain, and it also allows you to easily add
notification mechanisms to the user creation process, or even avoid notification
altogether when that's the need:

```ruby
#notify nobody
user.save
# notify the user
UserCreatedNotifier.new(user).save
# notify the user and an admin
UserCreatedNotifier.new(UserCreatedAdminNotifier.new(user)).save
# notify the user and post to twitter
TwitterNotifier.new(UserCreatedNotifier.new(user)).save
# etc
```

### Next Steps & Related Reading

Detect emerging problems in your codebase with [Ruby Science][ruby-science].
We'll deliver solutions for fixing them, and demonstrate techniques for building
a Ruby on Rails application that will be fun to work on for years to come.

[Grab a free sample of Ruby Science today!][ruby-science]

[ruby-science]: http://rubyscience.com?utm_source=giantrobots&amp;utm_medium=blog&amp;utm_campaign=remarket&amp;utm_term=testing
