---
title: Using the Draper Gem, Round One
teaser:
tags: web,rails,testing
author: Josh Clayton
published_on: 2012-08-23
---

[Draper](http://github.com/jcasimir/draper) is a handy new gem for extracting
logic normally held in helpers and views into something Ruby developers love:
objects! Helpers are a great means to an end, but most of the time, our
helpers accept arguments, a great sign that the method is procedural instead
of being a method on the object we're passing.

In my [Intro to Test-Driven Rails
workshop](https://thoughtbot.com/upcase/test-driven-rails)
(which I'm holding September 17-18 in San Francisco and September 24-25 in
Boston), one of the apps we build is a simple todo tracker. I decided to try
out Draper in the codebase and see how things turned out; let's dig in to some
code and see what it can do!

Here's the helper in question:

```ruby
# app/helpers/todos_helper.rb
module TodosHelper
  def completion_link(todo)
    if todo.completed_at?
      link_to 'Incomplete', todo_completion_path(todo), method: :delete
    else
      link_to 'Complete', todo_completion_path(todo), method: :post
    end
  end

  def todo_state(todo)
    if todo.completed_at
      'complete'
    else
      ''
    end
  end
end
```

Fairly straightforward: we have `completion_link`, which either `POST`s or `DELETE`s to `/todos/:id/completion` (adding or removing the timestamp of `completed_at`), and `todo_state`, which generates an <abbr title="HyperText Markup Language">HTML</abbr> class for us.

The view shouldn't be much of a surprise:

```erb
<%= link_to 'Create a Todo', new_todo_path %>

<ul id='my-todos'>
  <% @todos.each do |todo| %>
    <li class='<%= todo_state todo %>' id='<%= dom_id todo %>'>
      <%= todo.description %>
      <%= completion_link todo %>
    </li>
  <% end %>
</ul>
```

As I mentioned above, helper methods that accept some instance of a model are
begging to be moved to an object that can instead be instantiated with that
model; in this case, a `TodoDecorator`.

My ideal interface would look like:

```erb
<%= todo.list_item do %>
  <%= todo.description %>
  <%= todo.completion_link %>
<% end %>
```

This provides the flexibility of adding whatever markup within the `<li>`
while moving the logic for id/class generation (as well as the
complete/incomplete links) out of the helper. Now that I know the interface,
let's write some tests.

First, require the correct file in the RSpec helper:

```ruby
require 'draper/test/rspec_integration'
```

To generate the decorator and its test, run:

    rails generate decorator Todo

With that added, let's test-drive the implementation. First, the `list_item`
method:

```ruby
# spec/decorators/todo_decorator_spec.rb
describe TodoDecorator do
  context 'list_item' do
    it 'renders list item for complete todo' do
      todo = build_stubbed(:todo, :completed)
      result = TodoDecorator.new(todo).list_item do
        'string'
      end

      markup = Capybara.string(result)
      markup.should have_css("li#todo_#{todo.id}.complete",
                             text: 'string')
    end

    it 'renders list item for incomplete todo' do
      todo = build_stubbed(:todo)
      result = TodoDecorator.new(todo).list_item do
        'string'
      end

      markup = Capybara.string(result)
      markup.should have_css("li#todo_#{todo.id}:not(.complete)",
                             text: 'string')
    end
  end
end
```

I test both complete and incomplete todos, ensuring that the text within the
block is present. `Capybara.string` makes it really easy to write assertions
against the generated markup.

Next, let's test `completion_link`:

```ruby
describe TodoDecorator do
  include Rails.application.routes.url_helpers

  context 'completion_link' do
    it 'generates a link to complete the todo when incomplete' do
      todo = build_stubbed(:todo)
      result = TodoDecorator.new(todo).completion_link
      markup = Capybara.string(result)
      markup.should have_css("a[data-method='post'][href='#{todo_completion_path(todo)}']",
                             text: 'Complete')
    end

    it 'generates a link to mark the todo as incomplete when complete' do
      todo = build_stubbed(:todo, :completed)
      result = TodoDecorator.new(todo).completion_link
      markup = Capybara.string(result)
      markup.should have_css("a[data-method='delete'][href='#{todo_completion_path(todo)}']",
                             text: 'Incomplete')
    end
  end

  # context 'list_item' ...
end
```

Finally, the decorator implementation:

```ruby
class TodoDecorator < Draper::Base
  decorates :todo

  def list_item(&block)
    h.content_tag(:li, list_item_options, &block)
  end

  def completion_link
    if completed_at?
      h.link_to 'Incomplete', completion_path, method: :delete
    else
      h.link_to 'Complete', completion_path, method: :post
    end
  end

  private

  def completion_path
    h.todo_completion_path(self)
  end

  def dom_id
    h.dom_id(self)
  end

  def list_item_options
    { id: dom_id, class: state }
  end

  def state
    if completed_at?
      'complete'
    end
  end
end
```

This should look familiar since the majority of it came from the existing
helper. The biggest thing to note is accessing helper methods versus methods
on the decorated component. Helper methods are accessed by calling them on
`h`, which represents Rails' helpers; this includes routes, record identifiers
(like `dom_id`), and tag generators (`link_to`, `content_tag`).  Methods on
the decorated component (todo) can be invoked directly. Finally, if you don't
want to prefix helper methods with `h.`, just `include Draper::LazyHelpers` in
your decorator.

The view can now be changed to my desired implementation, and the suite is
still green! What are the benefits to a decorator versus leaving logic in the
view and helpers?

1. Logic is encapsulated: conditionals generating ids, classes, and markup
   are now in one spot.
1. Code is object-oriented: things dealing with markup on a todo are
   (surprise!) methods on our decorated todo instead of that procedural junk
   we were using before.
1. Everything is more testable: because the view logic and helper logic is
   rolled into one location, unit-tests for all of this are a breeze.
   Acceptance tests are still important, but if we want to change the
   structure or move forward with more data, it'll be a relatively simple task.

I've only recently started playing with the draper gem but I really enjoy it.
The benefits are pretty clear to me and I love the fact that it's so easily
testable. If you've got procedural code or logic in your views (or methods on
your models that are purely view-specific) I'd recommend moving those methods
to a better place: a decorator.
