Query objects for complex ActiveRecord queries

2822
0

When queries become too complex for scopes—involving multiple joins, subqueries, or raw SQL fragments—I extract them into dedicated query objects. Each query object is a plain Ruby class that encapsulates one specific query pattern and returns an ActiveRecord::Relation so results remain composable. This keeps models lean and makes testing easier since I can verify query logic in isolation. Query objects also improve performance visibility—I can instrument them with logging or metrics to track slow queries. The pattern works particularly well for search and reporting features where query complexity grows over time. I prefer query objects over putting everything in scopes when the logic exceeds 3-4 lines.