How to write ‘thin’ Rails Controllers?

Monika M
The MavenHive Blog
Published in
2 min readFeb 11, 2017
Sounds like a good thing, but I dont know how to do it?

In the last BRUG meet up a beginner, on the way to to be a ninja, showed me the below code asked me a simple question.

“I have read that, it is good to avoid save or update in the controllers. Why is it so? How shall I avoid it? “

Well, there are couple of reasons for it.

  1. Usually, the save/update action would be as simple as the above code. It will always be associated with some other business logic.

Eg: Assume we are building a Ticket Support System. Here is your requirement. “As customer, I should be able to raise the ticket.”

2. It introduces the duplication. Eg. Creation logic would be replicated in controller and seeds.

Now, the customer would enter ticket details such as title, description But we(system) should also maintain other attributes such as status

Our controller would be,

Instead of putting the business logic in the controller, i.e ticket_params.merge(status: :new) we can abstract it and move it another layer like below.

Service would look like.

There are many ways achieving the abstraction. I have introduced a service layer between the controller and model. I have also explicitly defined the result of the operation.

Reasoning:

  1. SRP(Single Responsibility Principle): The controller responsibility is to receive the request and send a response. Which involves authentication, authorisation, validate request params, map request params to respective domain objects, convert models to http responses. Anything related to http protocol should be at the controller level.
  2. It would enable us to keep the code DRY(Don’t Repeat Yourself).
  3. The business logic and controller logic would be de-coupled and easy to test.
  4. Avoid fat controllers.
  5. Helps abstract the implementation which could potentially be extracted as a Micro Service later.

Some examples of where you would want to create the ticket.

1. In seeds.rb, rake tasks or data migrations etc.

2. When you want to version the apis where the underlying model operations remain the same but the api contract changes.

3. Also, when there are different apis for different consumers with different authentication/authorisation but same model operations.

So in conclusion, it has helped using a Service Layer Abstraction as one way to tackle this problem.

Have you had success with any other ideas? Please do post in the comments sections if any of those have worked for you.

--

--