Even More Diet for Fat Rails Models

Krzysiek shows us how to make Rails model easier to maintain and easier to test.

#

Tech

#

Knowledge

Fat cat
Krzysztof Knapik's avatar
Author:

Krzysztof Knapik

“Thin controller, fat model” – noooooo!!!

We probably all agree that “Thin controller, fat model” was a misconception. When “thin controller” sounds good, “fat model” is just a pain in the…let’s say – lower back ;)

Last week Ania Ślimak was talking about putting model on a diet. She presented a nice approach of reducing fat from models using validation factory. This solution is useful in many cases, but may not solve all the problems, so I wanted to continue this topic.

In the validation factory approach, validations are still stuck to the model and this responsibility is not fully extracted.

Validation rules and the model schema are like to change during their lifetime.

Every time you add/remove a rule or field, you may make existing records invalid in terms of the validation rules connected to the model. You have to maintain their validity, which is often unnecessary.

Validations are often contextual.

Sticking them with models may make using them in other places (e.g. another action or admin panel) is much harder and ends with adding plenty of ifs and unnecessary attributes describing the context.

The same issue happens with other stuff like sending emails in callbacks, which are often (unnecessarily) the model’s responsibilities.

The solution

Let’s not only move validations to the service object, but make model fully isolated from them and keep the data representation as its only job.

Validation service defines validations’ rules, takes a record as an argument and delegates it to the record. Some general logic is extracted to BaseValidator to be usable by other validation services:

And the happy model doesn’t know anything about validations:

But, where to actually call the validations? Model? – we said ‘no’ to that already. Controller? – well… we don’t need to put more responsibilities than handling the request and responding there.

So, let’s introduce another service object called Handler (Creator would a good name too), which sticks everything together:

What’s about the controller? It’s thin and happy as well:

Additionally, we could extract parameter sanitization logic to a service object and make controller even more clean.

Outcome

This way we have code:

  • with reduced model responsibilities
  • a way easier to maintain
  • easy to (unit) test
  • more OOP & closer to Single Responsibility Principle.

Want To Discuss
Your Next Project?

Our team is excited to work with you and create something amazing together.

let's talk

let's talk

More articles

We don’t just build software, we understand your business context, challenges, and users needs so everything we create, benefits your business.

thumbnail image for blog post
plus sign
thumbnail image for blog post
plus sign
thumbnail image for blog post
plus sign
Arrow