Is a Rails controller a motley crew of leftover code that needs a home? Is it a glob of glue sticking other parts of the app together? Is it a tangled mess hiding inside a wiring closet?
What, exactly, is the purpose of a Rails controller?
It turns out that a Rails controller has not one, but two main responsibilities. The first is to act as a translator between the language of HTTP and the language of your application.
The Model Layer Is the Application
To fully understand this, it helps to have a good grasp on what the model layer in a Rails app actually is. It’s not just a collection of classes that interface with the database. It’s the entire brains of your application. All of the domain concepts, logic and behavior live in the model layer.
In fact, I find it useful to sometimes refer to the model layer as “the application”. This emphasizes the fact that everything that your application does happens there. Controllers and views simply serve as an interface to “the application”.
So the controller doesn’t actually do the work; it delegates. It receives an HTTP request (in a convenient Ruby form, of course) and translates it into a command the application can understand.
For example, if a POST request comes in with some parameters, a controller will translate this into the language of the application by creating a new ActiveRecord object and calling
save on it.
Often, controllers will try to do too much. But a controller should pretty much only be calling one command on the model layer. It shouldn’t be instantiating two or three different ActiveRecord objects and orchestrating them.
The controller also translates the results of your application to the language of HTTP. Often this is simply a 200 OK with HTML. Notice that it’s not the responsibility of the controller to construct the HTML, just the HTTP.
Also notice that it’s not the responsibility of a controller to prepare data for a view to consume. That’s the responsibility of a presenter, a missing–but necessary–piece of Rails.
And that’s it. Just two things. Your controller should only be (1) translating between the language of HTTP and the language of your app, or (2) making authorization decisions. Anything else does not belong in a controller.