Working with large controllers
How many times have you encountered large controller methods? If you are lucky like me, probably many times.
One of the most common practices to start refactoring a long controller is to move the code to a service.
Services are great, and if we code them in an atomic way, they will be easy to test and understand. But the problem is when we use the services it's like using a Swiss Army knife.
-"Hey, I don't know how to properly refactor this piece of code" -"Dude, just do a new service"
But no!, making a new service is not always the best option. In some cases, we are reinventing the wheel and maybe there is a pattern that already fits with our needs.
So here comes YAAF, yet another active form to save our day. YAAF is a gem that lets you create form objects using Rails in an easy and friendly way. It makes use of [.c-inline-code]ActiveRecord[.c-inline-code] and [.c-inline-code]ActiveModel[.c-inline-code] features, to provide you with a form object that behaves like a Rails model while remaining completely configurable.
When to use YAAF?
Let's imagine that we have an API endpoint that saves a new post on our database. A post has a title, body, publisher, and could also have tags and a category.
Tags and categories can be created as soon as the publisher sends the post. (If our inputs don't find the correct tag or category, they will let the user write the name of a new one).
So, in the worst-case scenario, our controller could have something like this:
It looks terrible, right? Maybe our first thought about that piece of code is to make a refactoring that moves the creation of the post to a service named [.c-inline-code]PostCreationService[.c-inline-code]. This could be useful and might be used in the future in another part of the system. But, what have we said about reinventing the wheel?
When using YAAF, we should create a new [.c-inline-code]PostForm[.c-inline-code] class that is going to encapsulate all the logic of post creation and related models inside it. And it is very simple to implement it! Just look at this code:
Note: We have also added a custom validation named [.c-inline-code]amount_of_tags[.c-inline-code], as YAAF helps us to encapsulate business rules in our Form Object.
And then, in our controller, we have the following:
Tip: Having an [.c-inline-code]ApplicationForm[.c-inline-code] which inherits from [.c-inline-code]YAAF::Form[.c-inline-code] is a good practice.
That's it, now we have a [.c-inline-code]PostForm[.c-inline-code] which encapsulates all the persistency logic of post/tags/categories, leaving our controller and models clean, with an easy to follow code.
Another good thing is that YAAF provides a similar API to [.c-inline-code]ActiveModel[.c-inline-code] models, so you can treat them interchangeably.
Why not a Service or PORO's?
- Making customized Services or PORO's could be disorganized if you're working in a team.
- YAAF helps you to apply the Form Pattern in an easy way.
- YAAF is only 64 lines long.
- It's well tested and maintained.
- It helps you keep your models, views, and controllers thin by providing a better place to put business logic. In the end, this will improve the quality of your codebase and make it easier to maintain and extend.
- And a lot more.
Well, if you've got this far, I hope this article helps you to integrate YAAF in your project, while also helping you use the [.c-inline-code]FormObject[.c-inline-code] Pattern to make your code even better. You can see more examples here. YAAF is open-source and is open to receive new contributions.
So check it out and see what you think!