StrongPresenter

StrongPresenter adds a layer of presentation logic to your application. The presenters also give you a strong_parameters-like syntax to specify what attributes can be read, helping you push authorization logic from the view layer back to the controller layer. The view layer can be dumber, and concentrate on page layout rather than authorization logic flow.

A number of features have been copied from Draper and refined.

Why use Presenters?

Presenters wrap your models, to deal with presentation, so your models can concentrate on domain logic. Instead of using a helper method to display some information in a view, you can implement the method in a presenter instead.

Others have used decorators, which are very similar, for this purpose. While decorators can also be used for presentation logic, it may cause some confusion in your application. Presenters are designed to help you to present - a market-oriented solution where unneccessary features can be discarded. Decorators are a coding pattern which can be forged to help you present - a product-oriented solution.

The decorator coding pattern involves using delegation to wrap the model, adding new behaviour to the base object. It may involve overriding some methods to present the data in a visually appealing way. The decorator pattern will generally wrap a object, but also keep the decorator acting like an instance of the base object - but this is not really what you want for presentation. It is also supposed to allow you to decorate a decorated object multiple times - to keep adding new behaviour to the object.

However, when we consider presentation, we are interested in reading the information, not in mutating the object, so we want to hide any attribute setters, or other "non-constant" methods. We are also not necessary interested in wrapping the object with multiple layers - if we really wanted, we could use a separately wrapped copy of the object. On the other hand, if we want to share some presentation logic between different models, instead of trying to wrap the a model with multiple presenters - to take into account the various behaviour we want, we should be using one presenter, which can include various behaviour using mixins. That is what StrongPresenter tries to give you.

While there exist other gems for presentation, we hope to provide a more natural interface to create your presenters.

Installation

Requires Rails. Rails 3.2+ is supported (probably works on 3.0, 3.1 as well).

Add this line to your application's Gemfile:

gem'strong_presenter'

And then execute:

$ bundle

Or install it yourself as:

$ gem install strong_presenter

This installs 0.0.1, which has a slightly different API. Version 0.1.0 is under development. While basic features have specs, newer features are not completely tested, so may not be stable for complex use-cases. Use gem 'strong_presenter', :github => 'ronalchn/strong_presenter' to install the development version.

Usage

Writing Presenters

Presenters are stored in app/presenters, they inherit from StrongPresenter::BasePresenter and are named based on the model they decorate. We also recommend you create an ApplicationPresenter where you can write macros for each presenter.

The model name is either inferred from the class name - taking UserPresenter, and converting the part before "Presenter" to lower case with underscores between each word, or it can be set using the presents method as shown above.

Delegating Methods

If no changes are necessary, a method can be delegated to the model. The :to option defaults to object.

classUserPresenter<ApplicationPresenterdelegate:username,:emailend

Wrapping Models with Presenters

Single Objects

Just pass the model to a new presenter instance:

@user_presenter=UserPresenter.new(@user)

Collections

Pass the model to a corresponding collection presenter:

@users_presenter=UserPresenter::Collection.new(@users)

If you want to add methods to your collection presenter, inherit from StrongPresenter::CollectionPresenter:

It wraps each item in the collection with the corresponding singular presenter inferred from the class name, but it can be set using the :with option in the constructor, or by calling presents_with :user (for example), in the class definition.

Model Associations

Sorry, this feature has not been implemented yet.

When to Wrap the Model with the Presenter

You will normally want to wrap the model with the presenter at the end of your controller action:

If the :with option is not passed, it will be inferred by using the model class name. :only and :except sets the controller actions it applies to.

Permit!

You can simply use the presenter in the view:

Avatar: <%= @user_presenter.avatar %>

However, sometimes you will want to display information only if it is permitted. To do this, simply pass the attribute symbols to the presents method on the presenter, and it will only display it if it is permitted. This is especially powerful because it controls the display of not just the attribute value, but everything that is passed in the block.

Because of the permit checks, there is no danger that private information will be revealed.

Testing

RSpec

The specs are placed in spec/presenters. Add type: :presenter if they are placed elsewhere.

Isolated Tests

In tests, a view context is built to access helper methods. By default, it will create an ApplicationController and then use its view context. If you are speeding up your test suite by testing each component in isolation, you can eliminate this dependency by putting the following in your spec_helper or similar:

StrongPresenter::ViewContext.test_strategy:fast

In doing so, your presenters will no longer have access to your application''s helpers. If you need to selectively include such helpers, you can pass a block:

Acknowledgements

License

Mozilla Public License Version 2.0

Free to use in open source or proprietary applications, with the caveat that any source code changes or additions to files covered under MPL V2 can only be distributed under the MPL V2 or secondary license as described in the full text.