Hi everyone,
I’m facing a persistent issue trying to bulk suspend/deactivate users on my Discourse instance (version 3.5.0.beta5-dev) via the Rails console. I’m trying to exclude my admin account (hoangthai
, user ID 100
) and permanently suspend all other active non-admin/non-moderator users with a custom reason “Chưa gia hạn tài khoản” (Account renewal pending).
I’ve tried several approaches based on common Discourse console commands and debugging suggestions, but the accounts remain active: true
even though suspended_at
and suspended_till
might get set.
Here’s a breakdown of what I’ve attempted and the errors/results:
My Goal: Suspend all users permanently (except hoangthai
, ID 100) with the reason “Chưa gia hạn tài khoản” (Account renewal pending).
Attempts & Issues:
-
Initial Attempt (Setting
suspend_reason
,suspended_at
,suspended_till
directly):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." # First reason attempt 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
- Result:
NoMethodError: undefined method 'suspend_reason=' for an instance of User
(suggestedsuspended_at=
). This indicatedsuspend_reason
was not the correct attribute.
- Result:
-
Second Attempt (Using
UserSuspension.suspend_user
as suggested for newer versions):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
- Result:
NameError: uninitialized constant UserSuspension
(suggestedUserSuspender
). This indicated the class name was incorrect.
- Result:
-
Third Attempt (Corrected class name to
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( # Still trying 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
- Result:
NoMethodError: undefined method 'suspend_user' for class UserSuspender
(suggestedUserSuspended?
). This showed the method name was also incorrect.
- Result:
-
Fourth Attempt (Using
UserSuspender.new(...).suspend
as the service object pattern):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 # For permanent suspension ).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
- Result: This command ran without errors in the console. It printed “Đã khóa tài khoản: [username]”.
- However, when checking user status in the admin UI or directly querying
user.active
in console, users still showedactive: true
. Onlysuspended_at
andsuspended_till
were updated (e.g.,suspended_at: "2025-05-26 00:37:01.406064419 +0000", suspended_till: nil
). The accounts were still able to log in.
-
Fifth Attempt (Directly setting
active = false
along with suspension fields):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 # Permanent user.custom_suspension_reason = "Chưa gia hạn tài khoản" # Custom reason user.active = false # Crucial part 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
- Result: This command also ran without errors and printed success messages.
- However, the outcome was the same:
active: true
remained, andsuspended_at
/suspended_till
were updated, but accounts were not actually deactivated or prevented from logging in.
My Current Situation:
I can manually suspend users via the admin UI (Admin → Users → Suspend) and they get correctly suspended (e.g., as shown in your previous screenshot with “Tạm khóa bởi: hoangthai, Lý do: Chưa gia hạn tài khoản”, and they cannot log in). This confirms the core functionality works.
I suspect there’s a specific API nuance in Discourse 3.5.0.beta5-dev
for programmatically suspending/deactivating users that I’m missing, or perhaps a caching issue that’s not being cleared, or a background job that needs to run.
Could anyone with experience in Discourse 3.5.x beta versions or deep Rails console knowledge offer some guidance on how to correctly achieve a bulk, permanent suspension that actually prevents user logins and sets the active
status to false
?
Thank you for your time and help!