Using plain MVC in Rails is great... for small applications. When your application starts to get complex, and when you start to ask the classic question "should this code be in controller or in model?" you'll feel that MVC is't enough.

The new hit hotness is splitting monolithic Rails Apps into micro-services. However, proponents of micro-services rarely mention how big of a pain in the ass deployment is. We can do better. We can split up a monolithic Rails App without taking all of this pain by being a little more intelligent about code structure by dividing them into:

Controller

Like uncle Bob mentioned in his talk, I see controllers in Rails as the delivery mechanism that is HTTP specific. My controller only does three things:

ActionController::Base already handles a lot of the HTTP related stuff and it also gives us a render method. This means when we inherit from it #1 and #3 is mostly taken care of. #2 should just be a few lines to invoke the application's entry point using interactor. Usually my controller looks something similar to this:

      class BusinessesController < ApplicationController

        def create
          result = CreateBusiness.call(input_params)

          if result.success?
            @business = result.business
            render :show, status: 201
          else
            render json: { errors: camelized_errors(result) }, status: 422
          end
        end

        private

        def input_params
          params.merge(business_id: params[:id])
        end

      end   

As you can see the controller contains very little logic. With such little logic I would argue you don't even need controller test.

Interactor

I use the interactor gem to encapsulate all the the business logic. It represents one thing the application does. For example creating a post, or updating a user. This is the entry point to our application. It should thus be named accordingly like CreatePost or UpdateUser. Interactor usually goes into the app/interactors folder. When someone views our code for the first time, it should be very clear to them what the application is capable of. They just open the app/interactors folder and scan through the file names.

So what is the advantage of using interactor instead of just putting the logic in controller:

Model

Rails model usually inherits from ActiveRecord::Base which gives them an incredible amount of responsibilities even without any domain logic added:

With these 3 big responsibilities, model violates SRP (Single Responsibility Principal) all over the place. I would love to be able to take all three of them out of the model and only let a model contain the domain logic. In fact, I have tried to factor them out, but I have failed on the persistence and association part. I came to the realization that it's not only very hard to factor those things out (for example using Repository pattern), but the ease of persistence and declaring associations is really what made ActiveRecord so powerful and popular in the first place.

Validations on the other hand is a different story. I discovered a gem called reform that does exactly this, and frees my model of validations. Freeing model from validation gives us another good side effect. We can mow create a model for testing without filling all the attribute that is normally required. Remember the time you just want to testing something small but because of validations you have to make up a valid value for every single attribute and there is like 20 of them? It gets even worst if the model validates on the association and the associated model has another 20 attributes. Now you are free create model as you please.

With reform handling the validation now each model is left with the following responsibilities:

Form

As mentioned above I use the gem reform to separate validation logic out of the model. Interactor make uses of the form to validate the requests and then if everything is confirmed as valid, then the interactor proceeds to saving the model or other actions with the input.

I usually name the form according to the interactor. For example, if the interactor is called CreatePost then my Form will be named CreatePostForm. This clearly articulates that the form is for validating the input of that specific interactor.

Policy

I use policy for authorizations. Interactor initiates a policy with a model and then asks the policy whether the requestor is allowed to perform actions on that model. A popular gem for this is pundit, however I usually just use PORO because my authorization happens within the interactor so I don't really need the controller helper from pundit.

Presenter

Presenter is usually what I return from an interactor. It wraps around a model and only exposes the method or attribute that the view should use. The reason I use this is that I treat the interactor as the boundry of my application. Interactor should return dumb data. To my application, the controller is its client and I don't want controller messing around with things it is not suppose to mess around. For example we don't want controller to be calling .where on the model.

In the past, I have tried manually constructing structs from my model and return that from the interactor. I found this process very tedious and Presenter facilitated a good middle ground. The Presenter usually takes in two things:

The Presenter has the following responsibilities:

#2 May seem a bit confusing, so here's an example: Let's say I'm building a twitter style application that allows users to follow eachother. When viewing a user profile, we want to determine whether or not i'm following this user. My user model would probably have a method that looks like:

      def followed?(user)  
          ...
      end 

If we expose this through the presenter to a controller which then passes it to the view, what is the view supposed to do with it? The naive answer is: just call it with the current user. But the problem is, the view doesn't know who the current user is. In my architecture, even the controler doesn't know the current user because of all the business logic is within the interactor. Of course you could have a interactor that is called GetCurrentUser and use that to get it, but I think a better approach is to use Presenter:

      class UserPresenter < ApplicationPresenter  
          presents :name, :handle

          def initialize(object, viewer)
              @object = object
              @viwer = viwer
          end

          def followed?
              object.followed?(viwer)
          end
      end

      class GetUser < ApplicationInteractor

          def call
              ...
              context.user = UserPresenter.new(@user, @requestor)
          end

      end 

Now the controller doesn't need to know about the current user but still has all the information and can pass it down to view for rendering.

MVC

When I said MVC is not enough in the beginning, I don't really mean that MVC (or more accurately Model 2) as a design pattern is not enough. What I meant is that we should not be afraid of using PORO. To think that only class that inherit ActionController::Base is a controller and only class that inherit from ActiveRecord::Base is a model is a misconception that many Rails developer have. MVC itself is a design pattern that has nothing to do with what the object's parent class is.

In my architecture we are actually using an MVC within an MVC. On the application level:

On the business logic level:

I hope this code structure will give you some inspiration for how you can organize your code and increase the maintainability of your next Rails app.

Follow me @royybao for more updates and let me know what you think of this post via the comments!

ps - we just wrapped up a project and looking for our next one. Drop us an email if you'd like our team to help out =)