Невозможно массово приостановить/деактивировать пользователей в консоли Rails на Discourse 3.5.0.beta5-dev

Всем привет,

У меня возникла устойчивая проблема при попытке массово приостановить/деактивировать пользователей на моём экземпляре Discourse (версия 3.5.0.beta5-dev) через консоль Rails. Я пытаюсь исключить свою учётную запись администратора (hoangthai, ID пользователя 100) и навсегда приостановить всех остальных активных пользователей, не являющихся администраторами или модераторами, с указанием причины «Chưa gia hạn tài khoản» (Ожидание продления аккаунта).

Я пробовал несколько подходов, основанных на распространённых командах консоли Discourse и предложениях по отладке, но учётные записи остаются с флагом active: true, даже если поля suspended_at и suspended_till могут обновляться.

Ниже приведён разбор моих попыток и возникших ошибок/результатов:

Моя цель: Навсегда приостановить всех пользователей (кроме hoangthai, ID 100) с причиной «Chưa gia hạn tài khoản» (Ожидание продления аккаунта).

Попытки и проблемы:

  1. Первая попытка (Прямая установка suspend_reason, suspended_at, suspended_till):

    admin_id_to_exclude = 100
    User.where.not(id: admin_id_to_exclude).each do |user|
      if user.active? && !user.admin? && !user.moderator?
        user.suspend_reason = "Tài khoản tạm khóa do nghỉ phép dài hạn." # Первая попытка причины
        user.suspended_at = Time.current
        user.suspended_till = Time.current + 100.years
        user.save!
        puts "Khóa tài khoản: #{user.username}"
      end
    end
    
    • Результат: NoMethodError: undefined method 'suspend_reason=' for an instance of User (предложено suspended_at=). Это указало на то, что suspend_reason не является правильным атрибутом.
  2. Вторая попытка (Использование UserSuspension.suspend_user, как рекомендуется для новых версий):

    admin_id_to_exclude = 100
    User.where.not(id: admin_id_to_exclude).each do |user|
      if user.active? && !user.admin? && !user.moderator?
        UserSuspension.suspend_user(
            user,
            Time.current + 100.years,
            nil, # suspend_reason_id
            "Tài khoản tạm khóa: Nghỉ phép dài hạn.", # custom_suspend_reason
            Discourse.system_user
        )
        puts "Đã khóa tài khoản: #{user.username}"
      end
    end
    
    • Результат: NameError: uninitialized constant UserSuspension (предложено UserSuspender). Это указало на неверное имя класса.
  3. Третья попытка (Исправление имени класса на UserSuspender):

    admin_id_to_exclude = 100
    User.where.not(id: admin_id_to_exclude).each do |user|
      if user.active? && !user.admin? && !user.moderator?
        UserSuspender.suspend_user( # Всё ещё пытаюсь использовать suspend_user
            user,
            Time.current + 100.years,
            nil,
            "Tài khoản tạm khóa: Nghỉ phép dài hạn.",
            Discourse.system_user
        )
        puts "Đã khóa tài khoản: #{user.username}"
      end
    end
    
    • Результат: NoMethodError: undefined method 'suspend_user' for class UserSuspender (предложено UserSuspended?). Это показало, что имя метода также неверно.
  4. Четвёртая попытка (Использование UserSuspender.new(...).suspend как паттерна сервис-объекта):

    admin_id_to_exclude = 100
    User.where.not(id: admin_id_to_exclude).each do |user|
      if user.active? && !user.admin? && !user.moderator?
        begin
            UserSuspender.new(
                user,
                Discourse.system_user,
                reason: "Tài khoản tạm khóa: Nghỉ phép dài hạn.",
                suspended_till: nil # Для постоянной приостановки
            ).suspend
            puts "Đã khóa tài khoản: #{user.username}"
        rescue => e
            puts "Lỗi khi khóa tài khoản #{user.username}: #{e.message}"
        end
      end
    end
    
    • Результат: Эта команда выполнилась без ошибок в консоли. Она вывела «Đã khóa tài khoản: [username]».
    • Однако, при проверке статуса пользователя в админ-интерфейсе или при прямом запросе user.active в консоли, пользователи всё ещё отображались как active: true. Обновлялись только suspended_at и suspended_till (например, suspended_at: "2025-05-26 00:37:01.406064419 +0000", suspended_till: nil). Учётные записи всё ещё могли входить в систему.
  5. Пятая попытка (Прямая установка active = false вместе с полями приостановки):

    admin_id_to_exclude = 100
    User.where.not(id: admin_id_to_exclude).each do |user|
      if user.active? && !user.admin? && !user.moderator?
        begin
            user.suspended_at = Time.current
            user.suspended_till = nil # Постоянно
            user.custom_suspension_reason = "Chưa gia hạn tài khoản" # Кастомная причина
            user.active = false # Критически важная часть
            user.save!
            puts "Đã **khóa VĨNH VIỄN** và vô hiệu hóa tài khoản: #{user.username}"
        rescue => e
            puts "LỖI khi xử lý tài khoản #{user.username}: #{e.message}"
        end
      end
    end
    
    • Результат: Эта команда также выполнилась без ошибок и вывела сообщения об успехе.
    • Однако результат остался прежним: active: true сохранялся, suspended_at/suspended_till обновлялись, но учётные записи не были фактически деактивированы и не были заблокированы для входа.

Моя текущая ситуация:

Я могу вручную приостанавливать пользователей через админ-интерфейс (Admin → Users → Suspend), и они правильно приостанавливаются (например, как показано на вашем предыдущем скриншоте с надписью «Tạm khóa bởi: hoangthai, Lý do: Chưa gia hạn tài khoản», и они не могут войти в систему). Это подтверждает, что основная функциональность работает.

Я подозреваю, что в Discourse 3.5.0.beta5-dev есть какая-то специфическая особенность API для программной приостановки/деактивации пользователей, которую я упускаю, или, возможно, проблема с кэшированием, которое не очищается, или фоновая задача, которую нужно запустить.

Мог бы кто-то с опытом работы с бета-версиями Discourse 3.5.x или глубокими знаниями консоли Rails предложить руководство о том, как правильно выполнить массовую постоянную приостановку, которая действительно предотвращает вход пользователей и устанавливает статус active в false?

Спасибо за ваше время и помощь!

Я не считаю, что деактивация является частью процесса приостановки пользователя. В интерфейсе вам нужно будет отдельно нажать кнопку «Деактивировать», если вы хотите, чтобы вернувшийся приостановленный пользователь также повторно подтвердил свой адрес электронной почты.

Возможно, будет лучше принять решение о том, нужно ли это, и выполнить это как отдельную операцию. :crossed_fingers:

В этой теме есть некоторые рекомендации по массовой приостановке, если это поможет: Administrative Bulk Operations

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