Using Active Decorator
03 Oct 2012
This is a work in progress adapted from http://d.hatena.ne.jp/kitokitoki/20120904/p1
Creating a decorator for the User model. Below is an active_decorator example.
$ rails g decorator user
create app/decorators/user_decorator.rb
invoke test_unit
create test/decorators/user_decorator_test.rb
app/decorators/user_decorator.rb is an empty module.
Modifying the profile page
In order to edit a profile page with Draper you have to change UsersController#show, but with active_decorator it’s not necessary.
In that case we can start to arrange the view, first by changing the code that displays the user’s avatar.
That portion of the view can be replaced with the following code:
Next, we’ll change the code to display the username. We’ll replace this code.
We’ll rewrite it this way:
The decorator is changed as below. It’s roughly the same as the avatar_name method.
The template has gotten nicer in ten minutes, but there’s still room for improvement. Next we’ll refactor a large part within the view code. This code snippet shows a link to the user’s web site.
<dt>Website:</dt>
<dd>
<% if @user.url.present? %>
<%= link_to @user.url, @user.url %>
<% else %>
<span class="none">None given</span>
<% end %>
</dd>
We’ll replace it with the contents below.
<dt>Website:</dt>
<dd>
<% if @user.url.present? %>
<%= link_to @user.url, @user.url %>
<% else %>
<span class="none">None given</span>
<% end %>
</dd>
We’ll make a similar method in the decorator.
We can use the same technique in the template section when showing a user’s Twitter info and a user’s bio.
<dt>Twitter:</dt>
<dd>
<% if @user.twitter_name.present? %>
<%= link_to @user.twitter_name, "http://twitter.com/#{@user.twitter_name}" %>
<% else %>
<span class="none">None given</span>
<% end %>
</dd>
<dt>Bio:</dt>
<dd>
<% if @user.bio.present? %>
<%=raw Redcarpet.new(@user.bio, :hard_wrap, :filter_html, :autolink).to_html %>
<% else %>
<span class="none">None given</span>
<% end %>
</dd>
like this:
<dt>Twitter:</dt>
<dd><%= @user.twitter %></dd>
<dt>Bio:</dt>
<dd><%= @user.bio %>
</dd>
We will write the decorator like so:
We’ll pull out the else clause repeated in the website()
, twitter()
, bio()
/deco_bio()
methods.
Another correction we can make — pulling Markdown’s display processing into ApplicationDecorator and calling that method from another decorator. We’ll create a new markdown method that handles an expression with text passed to it.
▼ active_decorator / application_decorator.rb
▼ active_decorator / user_decorator.rb
Modifying the Model
Now that we’ve got the decorator set up the way we want, we’ll have a look at the model and if there’s any view-related code we’ll deal with it by moving it to the decorator. For example, in the User model, we are formatting the time that the user is created with the member_since method. This code can be considered view related since it only returns a formatted string. This is moved to the decorator.
▼ Model: /app/models/user.rb
▼ Decorator: /app/decorators/user_decorator.rb
In active_decorator there is no way to restrict access to model methods as there is in Draper, another decorator gem.
Hopefully this helps you to get your feet wet with the active_decorator gem. I (Cameron) started using this at work and am enjoying it. I’m not a native Japanese speaker, but the examples here should be straightforward enough for basic use cases.