# StrongPresenter
[](http://badge.fury.io/rb/strong_presenter)
[](https://travis-ci.org/ronalchn/strong_presenter)
[](https://coveralls.io/r/ronalchn/strong_presenter)
[](https://codeclimate.com/github/ronalchn/strong_presenter)
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 deal with presentation, so your models can concentrate on domain logic. Instead of using a helper methods, you can implement the method in a presenter instead.
Others have used decorators for this purpose - while they can 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. Decorators are a coding pattern which can be used for presentation - a product-oriented solution.
The decorator coding pattern involves using delegation to wrap the model, adding new behaviour to the base object, possibly overriding some methods to present data in a visually appealing way. The decorator pattern not only wraps an object, but also involves keeping the decorated object acting like an instance of the base object (allowing multiple redecorations) - but this is not really what you want for presentation.
When we consider presentation, we are interested in reading the information, not further mutating the object, so we want to hide attribute setters, or other domain logic. We are also not interested in wrapping multiple layers around the object (we can use multiple still use presenters of the same object). If we want to share presentation logic between different models, we should instead use one presenter per model, including various behaviour using mixins.
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
Or to use the edge version, add this to your Gemfile:
gem 'strong_presenter', :github => 'ronalchn/strong_presenter'
## Usage
### Writing Presenters
Presenters are stored in `app/presenters`, they inherit from `StrongPresenter::Presenter` and are named based on the model they present. We also recommend you create an `ApplicationPresenter`.
```ruby
# app/presenters/user_presenter.rb
class UserPresenter < ApplicationPresenter
# ...
end
```
### Accessing the Model and Helpers
As shown below, rails helpers can be accessed through `h`. You can access the model using the `object` method, or the model name (in this case `user`). For example:
```ruby
class UserPresenter < ApplicationPresenter
presents :user
def avatar
h.tag :img, :src => user.avatar_url
end
end
```
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`.
```ruby
class UserPresenter < ApplicationPresenter
delegate :username, :email
end
```
### Wrapping Models with Presenters
#### Single Objects
Just pass the model to a new presenter instance:
```ruby
@user_presenter = UserPresenter.new(@user)
```
#### Collections
Pass the model to a corresponding collection presenter:
```ruby
@users_presenter = UserPresenter::Collection.new(@users)
```
To add methods to your collection presenter, inherit from `StrongPresenter::CollectionPresenter`:
```ruby
# app/presenters/users_presenter.rb
class UsersPresenter < StrongPresenter::CollectionPresenter
def pages
(collection.size / 20).ceil
end
end
```
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. The `::Collection` constant of each presenter will automatically be set to the collection presenter with a matching plural name.
### Model Associations
To automatically wrap associations with a presenter, use `presents_association` or `presents_associations`:
```ruby
# app/presenters/users_presenter.rb
class UsersPresenter < StrongPresenter::CollectionPresenter
presents_association :comments
end
```
A specific presenter can be specified using the `:with` option, otherwise it is inferred from the association. A scope can be specified using the `:scope` option. It can also yield the new presenter to a block.
### 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:
```ruby
class UserController < ApplicationController
def show
@user = User.find(params[:id])
@user_presenter = UserPresenter.new(@user)
end
end
```
But you can use the `presents` method to add a helper method that returns the presenter lazily:
```ruby
class UserController < ApplicationController
presents :user, with: UserPresenter, only: :show
def show
@user = User.find(params[:id])
end
end
```
Subsequently, in our view, we can use:
```erb
Username: <%= user.username %>
Email: <%= user.email %>
```
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! and `present`
#### Basics
You can simply use the presenter in the view:
```ruby
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 quite useful because it controls the display of not just the attribute value, but everything that is passed in the block. If no block is given, the results are returned in an array.
```erb
<% fields = { :username => "Username", :name => "Name", :email => "E-mail" } %>
<% @user_presenter.presents *fields.keys do |key, value| %>
<%= fields[key] %>: <%= value %>
<% end %>
```
The `present` method is also available to display a single attribute. If no block is given, the result is returned, ready to display.
```erb
Hello <%= user.present :name %>
<% user.present :username do |value| %>
Username: <%= value %>
<% end %>
```
To permit the display of the attributes, call `permit!` on the presenter with the attribute symbols in the controller.
```ruby
class UserController < ApplicationController
def show
@user = User.find(params[:id])
@user_presenter = UserPresenter.new(@user).permit! :username, :name # but not :email
end
end
```
You can also call it when using the `presents` method in the controller:
```ruby
class UserController < ApplicationController
presents :user do |presenter|
presenter.permit! :username, :name
presenter.permit! :email if current_user.admin?
end
def show
@user = User.find(params[:id])
end
end
```
There is also a `select_permitted` method to help you with tables. For example, we use `select_permitted` below to check which of the columns are visible.
```erb
<% fields = { :username => "Username", :name => "Name", :email => "E-mail" } %>
<%= fields[key] %> | <% end %>
---|