Glad You're Ready. Let's Get Started!

Let us know how we can contact you.

Thank you!

We'll respond shortly.

Dumb Controllers, Layered Models

“I like to make my views so dumb, there’s no reason to test them.”

Uncle Bob Martin said that at some point, or something very close to it. I’d like to take that a step further: I like to make my (Rails) controllers so dumb, there’s no reason to test them (unless there’s no higher level acceptance test that would exercise the actions in them).

Complicated controllers are painful. Each controller action is like a mini main() function. That’s a lot main()s. The more each action knows about your underlying application, the more brittle your application gets. Think of an action as a launching point into your business domain.

I have some rules (that I occasionally break). It goes something like this:

1) Controllers should be RESTful. No custom actions. new, create, update, destroy, edit, show. That’s it.
2) Controllers should manage a single resource. If you’re instantiating more than a single object in your controller, you’re probably going to regret it.

There’s some great gems out there that can support this restrictive approach to Rails development:

1) Responders ( Responders are built into Rails, but the FlashResponder in the responders gem is essential. Replace all of your tedious flash message management code with defaults that can be overriden in your localization files. You can create your own responders to replace any tedious bookkeeping in your controllers.

2) Informal::Model ( Since you’re limited to instantiating a single object in your controllers, it’s likely that you won’t get by with just ActiveRecord models. You’ll need to create higher level models that can coordinate the work of all your lower level database models (and action mailers, etc.). Heads up, Rails 4 will obsolete this gem with ActiveModel::Model.

3) ActiveModel::Serializer ( This only applies if you’re creating a JSON API. But if you are, consider this gem. It’s convention over configuration for your API. It works with responders and makes all of the JSON format choices for you so that you can focus on more important things.

I’ll leave with you this:

= simple_form_for @widget_search do |f|
  = f.input :query
  = f.submit

= render @widget_search.results
class WidgetSearchController
  def new
    @widget_search =

  def create
    @widget_search = WidgetSearch.create(query: request.query_parameters)
class WidgetSearch
  include Informal::Model

  attr_accessor :query

  validates_presence_of :query

  def self.create(options={})
    new(options).tap &:save

  def save
    return false unless valid?
    @results = Widget.periscope query

  def results
    @results || []

You might have noticed a “periscope” method in there. Yet another fantastic gem.

  1. I use inherited resources to enforce this. I try not to use any customisations it provides.

  2. […] Dumb Controllers, Layered Models – Pivotal Labs via […]

Post a Comment

Your Information (Name required. Email address will not be displayed with comment.)

* Copy This Password *

* Type Or Paste Password Here *