Skip to content
haines edited this page Dec 12, 2012 · 8 revisions

A lot has changed in Draper 1.0! Here's a quick guide to the changes that might affect your app. work in progress

Renaming

The most obvious change is that a lot of things have been renamed.

  • Draper::Base is now Draper::Decorator.
  • Draper::DecoratedEnumerableProxy is now Draper::CollectionDecorator.
  • Draper::ModelSupport is now Draper::Decoratable. It's automatically included in ActiveRecord::Base and Mongoid::Document, so if your models inherit from these you're good to go. If not, you can manually include this module, which adds a decorate instance method to your models.

Other changes

In Decorator

.decorate and .decorate_collection

Decorator.decorate(my_object) is now just a simple alias for Decorator.new(my_object). The :infer option has been removed, so if you want to infer the decorator from the source object, just use my_object.decorate.

This also means that it no longer creates CollectionDecorators when you pass it an enumerable. You can therefore use a decorator on an array or similar, and it will decorate the collection itself instead of the items of the collection.

When you want to decorate each item of a collection, you should use the aptly named decorate_collection method instead. ProductDecorator.decorate(Product.all) becomes ProductDecorator.decorate_collection(Product.all).

.decorates_finders

Automatic decoration of ActiveRecord finder methods is no longer included by default. If you want to do ProductDecorator.find(1) instead of ProductDecorator.decorate(Product.find(1)) or Product.find(1).decorate, you need to call decorates_finders in your decorator definition.

class ProductDecorator < Draper::Decorator
  decorates_finders
end

.decorates

decorates is now optional. If you follow the standard naming convention that ProductDecorator decorates a Product, you can omit decorates. In fact, if you don't intend to delegate class methods from the decorator to the model, you can omit it even if you don't follow the convention!

Previously, if you omitted decorates, the decorator would use the class of the first object it decorated:

ProductDecorator.some_class_method  # NoMethodError
ProductDecorator.decorate(Widget.first)
ProductDecorator.some_class_method  # calls Widget.some_class_method

Now, the decorator infers the source class from its own name:

ProductDecorator.some_class_method  # calls Product.some_class_method
ProductDecorator.decorate(Widget.first)
ProductDecorator.some_class_method  # still calls Product.some_class_method

#model and #source

To get the object being decorated, there are several options. You can use my_decorator.model, my_decorator.source, or my_decorator.to_source. Because decorators can be used on objects that are not models, we now prefer to use source, which also works on collection decorators to get the undecorated collection. If you prefer it, model is still available.

Previously, the decorator automatically aliased source to the name of the model (e.g. a ProductDecorator would have a product method). This is no longer the case, and you should use alias_method :product, :source in your decorator if you want to restore this behaviour.

In specs

Matchers

You can take advantage of the free RSpec matchers that come with the new decorated? and decorated_with? methods:

my_object.should be_decorated
# or
my_object.should be_decorated_with ProductDecorator