Ruby on Rails is an awesome framework to quickly build web applications. The "build a blog in 15 minutes" video caught everybody's attention a few years ago. To reach this result, Rails relies on the MVC pattern, and lots of conventions.
Yet, having more than 5 developers working over several months on the same Rails application is not the same story.
Every team hits the same wall after only a few months, code becomes complex to maintain, productivity starts to decrease, etc. We can find a lot of reasons to this (too much logic in controllers, fat models, lack of services layers, etc.), but, I will just name one: logic in view.
Logic in view is bug prone, difficult to test, and can be a pain for front end developers.
Let's consider a classic use case: having ACL on models because we do not want our precious resources to be writable by all users.
Libraries like CanCan make adding ACLs to a Rails applications quite easy. But, views can be easily polluted with stuff like:
<% if can? :update, @article %> <%= link_to "Edit", edit_article_path(@article) %> <% end %>
Yes, you got it, logic in view. And, since we do not have proper view inheritance, this code will have to be copy-pasted over and over. I would rather have something like:
<%= @article.link_to_edit %>
So, how can we remove logic from the view?
Decoration saves the day
As usual, we can find a solution with a pattern. Today, the decorator pattern will help us remove logic from views in our Rails applications.
The idea is to insert an object between the model and the view. This object
will know of the model, the context (most of the time, a
and have access to the view's helper methods.
We will use Draper in the next examples. So, let's create a decorator for the
class ArticleDecorator < Draper::Decorator delegate_all def link_to_edit if h.can? :update, object h.link_to "Edit", h.edit_article_path(object) end end end class ArticlesController < ApplicationController def edit respond_with @article = Article.find(params[:id]).decorate end end
A few things to notice here. From the controller, we call the
on a instance of
Article, this will return a decorated version of the article
ArticleDecorator class, we have access to the decorated object with the
object method, and to all view helpers through the
We can now call the
link_to_edit method on the
article object from our view,
and the decorator will take care of the logic, and return a formatted link if
the user has the right to edit this resource, and nothing if he does not.
The code is easier to test, we just instantiate a new instance of the
ArticleDecorator, and check the output of the
link_to_edit method. No need to
test the whole rendered view, searching through the DOM object tree.
This is a classic Ruby class, so we have access to inheritance and modules to
easily share behavior through several objects. It would not be hard to write a
LinkToAction module to provide
So, we gain code readability, code reuse, better testing, and in addition, we even lost a few lines of duplicated code. It seems a good deal to me.