Decorators

Using Draper

Jason Charnes

@jmcharnes

The Project

ConnectHope Hub

A way to connect people in need with places that can help them.

Let's start with a problem.

= link_to church_path(c) do
  .col-sm-4
    .well.church-box.text-center
      %h5= c.name.split(" ").reject{ |e| e == "Church" }.join(" ")
      %p
        = c.address_1
	%br
	= "#{c.city}, #{c.state} #{c.zip}"
	%span
	  Date Joined: 
	  %strong
	    = c.created_at.strftime("%m/%d/%y")

/churches

index.html.haml

Thought: How can I clean this up?

Procedural Helpers

= link_to church_path(c) do
  .col-sm-4
    .well.church-box.text-center
      %h5= remove_church_from_name(c.name)
      %p
        = c.address_1
	%br
	= "#{c.city}, #{c.state} #{c.zip}"
	%span
	  Date Joined: 
	  %strong
	    = c.created_at.strftime("%m/%d/%y")
module ChurchesHelper
  def remove_church_from_name(name)
    name.split(" ").reject{ |e| e == "Church" }.join(" ")
  end
end

Gross: Where did the OOP go?

Class Methods

= link_to church_path(c) do
  .col-sm-4
    .well.church-box.text-center
      %h5= c.name
      %p
        = c.address_1
	%br
	= "#{c.city}, #{c.state} #{c.zip}"
	%span
	  Date Joined: 
	  %strong
	    = c.created_at.strftime("%m/%d/%y")
class Church < ActiveRecord::Base
  def name
    self.name.split(" ").reject{ |e| e == "Church" }.join(" ")
  end
end

Better... but still feels weird.

The Solution

Decorators

https://github.com/drapergem/draper

Draper

"Draper adds an object-oriented layer of presentation logic to your Rails application."

Install Draper

gem 'draper', '~> 1.3'
bundle install
rails generate resource Church
rails generate controller churches_controller
rails generate decorator Church

or in my case, with an existing controller:

Use Draper

ChurchesController

def index
    @churches = Church.approved
end
def index
    @churches = Church.approved.decorate
end
= link_to church_path(c) do
  .col-sm-4
    .well.church-box.text-center
      %h5= c.name
      %p
        = c.address_1
	%br
	= "#{c.city}, #{c.state} #{c.zip}"
	%span
	  Date Joined: 
          %strong
            = c.created_at.strftime("%m/%d/%y")

app/views/churches/index.html.haml

class ChurchDecorator < Draper::Decorator
  def name
    model.name.split(" ").reject{ |e| e == "Church" }.join(" ")
  end
end

app/decorators/church_decorator.rb

class ChurchDecorator < Draper::Decorator
  def name
    model.name.split(" ").reject{ |e| e == "Church" }.join(" ")
  end

  def location
    "#{model.city}, #{model.state} #{model.zip}"
  end
end
= link_to church_path(c) do
  .col-sm-4
    .well.church-box.text-center
      %h5= c.name
      %p
        = c.address_1
	%br
	= c.location
	%span
	  Date Joined: 
          %strong
            = c.created_at.strftime("%m/%d/%y")
class ChurchDecorator < Draper::Decorator
  delegate_all

  def name
    model.name.split(" ").reject{ |e| e == "Church" }.join(" ")
  end

  def location
    "#{model.city}, #{model.state} #{model.zip}"
  end

  def joined
    model.created_at.strftime("%m/%d/%y")
  end
end
= link_to church_path(c) do
  .col-sm-4
    .well.church-box.text-center
      %h5= c.name
      %p
        = c.address_1
	%br
	= c.location
	%span
	  Date Joined: 
          %strong
            = c.joined

Finishing Draper

  • Decorators can be tested
    • RSpec
    • MiniTest::Rails
    • TestUnit::Rails
  • Decorators can be shared
    • ApplicationDecorator
  • ​Access to Rails helpers
  • ​Specific/All methods can be delegated

Decorators

Using Draper

Jason Charnes

@jmcharnes

Decorators in Rails, Using Draper

By Jason Charnes

Decorators in Rails, Using Draper

  • 3,319