Build Status Gem Version Code Climate

Uber simple presenters using Ruby's SimpleDelegator.


Add this line to your application's Gemfile:

gem 'resubject', '~> 0.2.2'

And then execute:

$ bundle

Ruby/Rails versions

This gem is compatible with Ruby 1.9 and 2.0 and Rails 3 and 4.


Checkout the documentation in


Resubject uses Ruby's SimpleDelegator class to create its presenters.

SimpleDelegator is a concrete implementation of the Delegator class. Basically, it delegates any method calls to the object passed into the constructor:

require 'delegate'

array =[1, 2, 3])

array.count # => 3   # => #<Enumerator: ...>

It doesn't override the class name, but you still can access the original object.

array.class# => SimpleDelegator

array.__getobj__.class# => Array

This means you can create a class that inherits from SimpleDelegator and customize its behaviour:

class ForeverZeroArray < SimpleDelegator
  def omg!

  def count

You can define new methods or override existing ones:[1,2,3]).count# => 0[1,2,3]).omg!# => OMG!


Using the Resubject::Presenter class, you can create Presenters from it. Example:

class Box <, :items)

class BoxPresenter < Resubject::Presenter
  def contents
    items.join(', ')

Then use the delegator:

box ='Awkward Package', ['platypus', 'sloth', 'anteater'])

presentable =
presentable.contents# => platypus, sloth, anteater

If you have a collection of objects and want to add a presenter to each one, use Resubject.all

boxes = [box1, box2, box3]
BoxPresenter.all boxes# => [<BoxPresenter>, <BoxPresenter>, <BoxPresenter>]


If you're using rails, Resubject automatically includes helpers in your controllers and views

class BoxesController < ActionController::Base
  def index
    @boxes = present Boxes.all

The #present method will automatically identify the presenter class by the object's class name. If you want to customize the class:

def index
  @boxes = present Boxes.all, SpecialBoxPresenter

It also accepts multiple presenters:

def index
  @boxes = present Boxes.all, BoxPresenter, ExtendedBoxPresenter

Or if you prefer, you can use the #present method directly into your views

<%= present(@box).contents %>


You can define presentable attributes:

class PostPresenter < Resubject::Presenter
  presents :title
  presents :comments # or => presents :comments, CommentPresenter

Then the attributes will return an instance of those presenters:

post.title# => <TitlePresenter>

post.comments# => [<CommentPresenter>, <CommentPresenter>, <CommentPresenter>]

Or if you wish, you can use the present method inside your class

class PostPresenter < Resubject::Presenter
  def comments
    present(to_model.comments, SomePresenter)

Helpers on Rails

Resubject can generate some rails helpers for your attributes:

class ProductPresenter < Resubject::Presenter
  currency :price, precision: 2

Will generate:

product.price# => $10.00

Available helpers

Presenter           Maps to                     Class/Module

currency            number_to_currency          ActionView::Helpers::NumberHelper
percentage          number_to_percentage        ActionView::Helpers::NumberHelper
time_ago            time_ago_in_words           ActionView::Helpers::DateHelper
date_format         to_s                        ActiveSupport::TimeWithZone

More helpers will be added. Feel free to contribute with yours! Also, Check out the extensions file.

Helpers without rails

If you'd like to use the generated helpers but you're not using Rails, you can either use ActionView or create your own template handler:

require 'action_view'

post =, Or

post =,

If you want to use your own template handler and still use Resubject helpers, you may want to define the same ActionView helpers in your handler (or only the ones you will actually use).


Resubject introduces a new context for RSpec that helps testing your presenters:

# spec/presenters/my_presenter_spec.rb
# require 'action_view' # require this first if you want to test action view helpers
require 'resubject/rspec'
require 'presenters/my_presenter'

describe UserPresenter do
  let(:object) { mock :user }

  it 'has full name' do
    object.stub(first: 'User', last: 'Name')
    expect( eq 'User Name'

By placing the file into spec/presenters, Resubject automatically includes the subject and template variables into your spec, so you don't need to define them on every spec.

NOTE: Please note that the presenter is tested on isolation. It's not required but very recommended.



  1. Fork it
  2. Create your feature branch (git checkout -b my-new-feature)
  3. Commit your changes (git commit -am 'Add some feature')
  4. Push to the branch (git push origin my-new-feature)
  5. Create new Pull Request