Разбираем баг в Forem, где счетчик статей не совпадает с содержимым. Учимся находить и исправлять такие ошибки. Читайте и применяйте!
Вы когда-нибудь замечали, что счетчик на сайте показывает одно, а на деле — другое? В этой статье мы разберем реальный баг из Forem (движка dev.to), где у пользователя с одним постом счетчик показывал 2. Вы узнаете, как находить и исправлять подобные расхождения, и почему важно проверять свой код, а не просто доверять компиляции.
Проблема была описана в одном issue: пользователь опубликовал ровно один пост, а на панели управления счетчик «Посты» показывал 2. Разработчик, взявшийся за исправление, не знал Ruby, но смог разобраться. Как? Он прочитал код и увидел, что счетчик считает все статьи пользователя, включая те, которые не отображаются в списке. Это классическая проблема рассинхронизации кэша и фильтров.
В Forem счетчик статей пользователя хранится в поле articles_count в модели User. Оно обновляется через библиотеку counter_culture при каждом создании или удалении статьи. Проблема в том, что он считает все статьи без фильтрации по типу или статусу. Вот как это выглядит в коде:
# app/models/article.rb
counter_culture :userА вот как отображается список статей на дашборде. Он фильтрует статьи: показывает только полноценные посты, не архивные:
# app/controllers/dashboards_controller.rb
@articles = target.articles.from_subforem.includes(:organization)
@articles = params[:state] == "status" ? @articles.statuses : @articles.full_posts
@show_archived = params[:filter].to_s.casecmp("archived").zero?В Forem есть три типа статей: full_post (обычный пост), status (короткое обновление) и fullscreen_embed (встраиваемый контент). Счетчик же считает все, включая статусы и архивные. Поэтому если пользователь хоть раз публиковал статус или архивировал пост, счетчик будет больше, чем реальное количество постов в списке.
Исправление не трогает общий счетчик articles_count, потому что он используется в других местах (например, для бейджей или антиспама), где важно общее количество. Вместо этого в контроллере добавили отдельный метод, который считает только те статьи, что попадают в список:
# Метод для подсчета постов, которые реально видны на вкладке "Посты"
def posts_count_for(user)
user.articles.from_subforem.full_posts.where(archived: false).count
endТеперь и полная страница, и AJAX-запросы используют этот метод вместо сырого счетчика.
Разработчик не мог запустить тесты локально (нет Ruby и Postgres), поэтому он написал регрессионные тесты и отправил их в CI. Первый запуск CI поймал ошибку в тестах: создание статьи типа status не проходило валидацию, потому что такие статьи не должны содержать markdown. Пришлось исправить фабрику. Это доказывает, что тесты нужны не для галочки, а для реальной проверки.
Если вы столкнулись с похожей проблемой, когда счетчик не совпадает с реальным списком, проверьте, не считаете ли вы все записи без фильтрации. И всегда пишите тесты, даже если кажется, что все работает. Не доверяйте только тому, что код компилируется — проверяйте, что он делает правильно.
Хочешь закрепить знания на практике?
Решай задачи на Algolit — интерактивная платформа для обучения
Начать бесплатно →