ActiveRecord в Rails — мощный инструмент для работы с PostgreSQL, но даже опытные разработчики сталкиваются с неочевидными ошибками при использовании group, having и merge. В этой статье разберём типичные подводные камни при построении сложных SQL-запросов через ActiveRecord и способы их избежать.
Кажется, всё просто: добавил joins, сгруппировал group(...), отфильтровал через having(...).
А потом внезапно ActiveRecord::StatementInvalid, nil вместо поля или теряются условия. Почему?
😵 select + group
User.select("users.id").group("users.id").first.name
# => nil 😱
Ты сгруппировал по id, но name не выбрал. В User-объекте нет name, а Rails не жалуется — просто nil.
🔍 having без group — ошибка
User.having("count(posts.id) > 10")
# => ActiveRecord::StatementInvalid: HAVING clause requires GROUP BY
having работает только с group. В обычных запросах используй where.
⚠️ merge и потеря условий
scope :active, -> { where(active: true) }
Post.joins(:user).merge(User.active)
Это работает! Но если ты используешь includes или eager_load, merge может не сработать или превратиться в WHERE 1=0, если условия невалидны.
👀 А если joins + merge?
User.joins(:posts).merge(Post.published)
Это корректный способ наложить условия из другого scope, но важно: merge не работает без joins, если ассоциация ещё не загружена.
🧨 Итого — частые ловушки
| Конструкция | Подводный камень |
|---|---|
select("...") |
поля вне select будут nil |
group(...).having(...) |
having без group — ошибка |
merge(...) |
требует joins / includes |
joins(:assoc).merge(...) |
ok, но scope должен быть валиден |
eager_load + merge |
может неожиданно дать пустой результат |
📌 Если запрос стал сложнее пары методов — проверь SQL через .to_sql.
Rails гибкий, но легко превратить цепочку в минное поле.