Skip to content

Instantly share code, notes, and snippets.

@Dacello
Last active August 29, 2015 14:06
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Dacello/b2bb6223ca1884d0885e to your computer and use it in GitHub Desktop.
Save Dacello/b2bb6223ca1884d0885e to your computer and use it in GitHub Desktop.
Skinny Everything Blog Post Draft

#Skinny Everything (Part 1 of 3)

At Revelry, we build web apps using Rails. Working with Rails, or any MVC/MVP framework for that matter, you will come across the saying "Fat model, Skinny Controller". The idea is to slim the the controller down to basic CRUD actions, and put the rest of the more complex functionality in the model. It definitely is good to have a slim controller for sake of code reusability, readability, and testing. However, it is also good to have a skinny model. For the exact same reasons. In fact, its just good to have a skinny everything.

What tends to happen when you move all logic into models is that you get "God like Models" which become impossible to understand and maintain. Jon Cairns also wrote a great article about why "Fat model, Skinny Controller is a load of rubbish."

Unfortunately, Cairns doesn't list any of the ways to keep everything skinny. So, I have decided to write a three part article that will explain some of the tactics we use at Revelry to maintain "Skinny Everything" in our Rails applications. The rest of this article will cover the first of these tacticts:

##1. Decorators

Sometimes you need a way to implement display logic on an object. For example, you have an Event object. In your view you want to call @event.start_date, and have it be a correctly formatted date (because Rails doesn't store dates the way humans like to look at them). You might think it would make sense to just add a method to the model:

def start_date
  start_date.strftime("%A, %B %e")
end 

That seems like a good idea, because then you will be able to call @event.start_date everywhere that you have an Event object. However, according to MVP, the model isn't supposed to deal with presentation; that's meant to happen primarily in the controller. Not to mention, display methods like this can add up, leading to fat models. You might consider writing a helper method that formats the date for you. That is probably a bad idea. Here's an article about why Rails helpers are shit.

Instead, the best option is to use a decorator. At Revelry, we use Draper for decorators. Here's an example of solving the above issue with a with Draper decorator:

#app/decorators/event_decorator.rb
class EventDecorator < Draper::Decorator
  delegate_all

  def start_date
    object.start_date.strftime("%A, %B %e")
  end
end

Then in the controller, you decorate the @event object with EventDecorator.decorate(@event), which returns the decorated @event object. So now you have the start_date method accessible via the decorated object.

It's important to remember that you need to decorate the event object in order to get the decorator methods. It might seem obvious, but consider this situation:

Before you knew it was a bad idea, you put a display logic based method in a model. Now that you know better, you decide you want to move it into a decorator. Smart. Thing is, if that method was already being called all over the application, you're gonna need to make sure that all instances of that model are getting decorated before the new decorator method is called. When it was just a model method, you could call it on any instances of the at model, but with a decorator, you can only call it on a decorated instance object.

Decorators are great because they keep display logic out of the models, and they keep your models skinnier (without resorting to using helpers).

The next part to this article, Skinny Everything (Part 2 of 3), will cover Concerns, which are another great way to skinny down both controllers and models alike.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment