I recently started reading “A Layered Design for Ruby on Rails Applications” by Vladimir Dementyev. I have always encountered some pain points when working with Rails applications when the model and controller layers grow in scope. One specific problem is adding complex querying logic to the model. At first, although it does not look like a dangerous pursuit, adding such a burden on the model starts to crack into the code quality. Thankfully, the book talks about the use of Query Objects and how we can use them to extract complex queries from our models.
I want to also emphasize that query objects is specificlly use for complex queries that might better suited to be extracted into its own class. Not every query needs to be a query object.
For loominex.io, a maintenance management system, I have the following model:
As you can see from the example above, our model is increasing in scope. Increasingly, I’m adding more responsibility to the model layer. Although these queries are not as complex, with time and requirements increasing, the WorkOrder model can get out of hand. This is where the bugs start showing up.
Thankfully, query objects help in extracting some of these queries from the models. It would help us make the WorkOrder model a bit leaner, improve the health of the codebase by removing the querying from the model, and help us integrate a new convention that would make it easier to test the app and decouple the application. Let’s look into it:
I can now add my query objects under the model directory in the work_order
directory.
├── work_order │ ├── open_status_query.rb │ └── urgent_status_query.rb
ruby Copy code
With this, I can now call:
We can now conclude that this refactored version makes our codebase healthier, makes it easier to test, removes complex queries from the model layer, and improves our code quality.