Почему default_scope = боль

Ruby on Rails предлагает мощные инструменты для работы с данными, но некоторые из них, например default_scope, могут принести больше проблем, чем пользы. В этой статье разберём подводные камни автоматического применения условий к запросам и альтернативные подходы, которые помогут избежать неожиданного поведения при работе с PostgreSQL и сложных SQL-запросах.


default_scope кажется удобным способом избавиться от повторяющегося фильтра. Но чаще всего он становится источником боли.

😇 Наивное использование

class User < ApplicationRecord
  default_scope { where(active: true) }
end

Кажется, ты избавился от дублирования. Теперь User.all — это только активные пользователи.


💥 А потом приходит боль

📌 Тесты не видят “неактивных”

User.create!(active: false)
expect(User.count).to eq(1) # 💥 Nope. 0

📌 Админка не показывает “всех”

Ты случайно написал User.all, а не User.unscoped.

📌 Сложность с join’ами и merge

Company.joins(:users).merge(User)
# накладывается лишний where(active: true)

🧯 Обходы и костыли

Ты начинаешь:

  • использовать unscoped
  • добавлять “сюрприз” в SQL
  • гуглить, почему merge не работает как надо

🔍 Что делать вместо?

Используй scope, а не default_scope:

class User < ApplicationRecord
  scope :active, -> { where(active: true) }
end

User.active

Если хочешь переопределить .all, сделай это явно.


🚨 TL;DR

Проблема Причина
Невидимые записи default_scope добавляет where
Ошибки в тестах Ожидание всех записей не работает
merge не как ожидалось default_scope неявно мешает

Итог: default_scope стоит использовать только в очень узких кейсах — и всегда помнить, что он по умолчанию везде.

🗓 Дата публикации: 09.03.2025, но это не точно...

Ruby Rails default_scope PostgreSQL SQL запросы