If you’re like most Rails developers I know, you probably vomited a little in your mouth after looking at that code.
At first glance its biggest issue is that is violates the skinny-controller-fat-model guideline that’s become popular
recently, so following that guideline you decide to put your controller on a diet:

Take 2: The Fat Model

In an effort to make the controller skinny, you move most of the registration logic to the User model like so:

Skinny controller, fat model, ship it – right? Well, if I had to make the choice, I would choose the fat-controller option any day.
While the fat-controller code is ugly, at least it’s isolated. The fat model code:

pollutes the entire model – tightly coupling User to Business

adding network calls in models

adding controller concerns like IP addresses to the model

Practically speaking, it adds overhead to every User creation throughout the app. Let’s say for example that you merge
codebases with another site (like through an acquisition) and you need to add all the other site’s users to your user
base – do you add fake IP addresses and confirmations, or do you add conditional logic to skip those callbacks? In addition,
you have overhead when creating a User in your test suite.

After looking at that, you might decide to introduce a form-backing object.

Take 3: Skinny Controller, Skinny Model, and Form-backing Object

Form-backing objects, also known as Presenters (not to be confused with the concept of view presenters), are objects
whose sole purpose is to take user-entered form data and perform some unit of work. Creating and testing form-backing objects
is simple. In this situation, you might add a Registration object.

In my opinion this type of form-backing object combines the best of all worlds – it keeps the controller skinny and the
view simple but it does’t pollute the domain at all.

Testing form-backing objects

Form-backing objects are just plain ruby objects, so testing them is very straightforward with unit tests. The only
thing that you probably want to do is make sure that your form-backing object is compatible with form_for by using
the ActiveModel::Lint::Tests. With Test::Unit it’s as simple as:

Staying Dry

If you have a lot of these form-backing objects, you can easily move all of that plumbing to a base class or module. Or
you can use an off-the-shelf gem like Josh Susser’s Informal or James Golick’sActive Presenter

9 Comments

Really like this approach, especially the activemodel part, we used something similar before, but the activemodel-ness was missing, and would have made it much more readable.

I think the upper 10 lines or so should be extracted into something like ‘FormBacker’, maybe get a bit more meta-magic there and support belongs_to :user and also handle the saving logic, then only bussiness-logic would remain, which imo is an even more ideal solution.

May 21, 2011 at 10:33 pm

Peter Jaros says:

Amen! Small objects, small responsibilities. Now mock and stub the underlying `User` object in the form object’s test, and you should have a tight, readable test which reads like a set of user story requirements. If not, you may still need to refactor.

Did you know? Object obesity is the leading cause of death among software projects 3 months and older.

May 22, 2011 at 7:54 am

Jeff Dean says:

@grosser – Checkout the Informal gem and ActivePresenter – they take care of some of the plumbing you mention.

I don’t use either of those gems, and I prefer to write these objects from scratch in Rails 3 because it’s so simple to write the plumbing, and because almost none of my form-backing objects are similar enough to really be able to use a declarative style without adding a lot of unnecessary complexity.

Awesome stuff. My only quibble is about introducing a new term for an already well-understood concept. Just call it a Presenter.

May 23, 2011 at 8:26 am

Jeff Dean says:

Thanks! I think the term “form-backing object” is becoming more well known outside of Rails, especially in the Spring framework. I think of it as a way to reference a particular subset of object being used in a presenter pattern.

With current Rails, presenter patterns require 2 sets of objects – form-backing objects tend to do work, and view-presenter objects that take care of formatting, calculations etc… View-presenter objects often need access to the view template in order to have access to link_to and other view helpers, whereas form-backing objects tend to take params and perform a unit of work.

May 23, 2011 at 10:07 am

Casey Provost says:

This is a pretty nice OO solution to a common problem in rails. The only tweak I have is that the following lines don’t seem to belong in save:

Filling out a registration form from a SOP standpoint has nothing to do with delivering emails or logging. The caveat to logging is if all form entries are logged. This makes testing simpler and keeps the success case in the controller that glues the form, email, log, rendering together.

I have been using the form object pattern now for a while and it has been working out really great. Really handy as well when handling variations of a form with different requirements.

Great article. Really nice illustration of both the problem and a very clean solution to it. I’d love to see Form objects become part or Rails Core or at least the Rails Way. In the meantime it’s great to see them championed.