Discourse 'Hacking' Snippets - handy helpers in the Rails Console

I’m going to curate a list here of useful snippets to run in the Rails console, as much as a personal aide-memoire as anything else.

Over the years I’ve been running Discourse fora, the community owners / customers will occasionally need something doing which cannot be done using the normal or admin UI, and only needed to be done once, therefore not worthy of needing a plugin.

Much of this is just obvious Rails code, but it helps to have it ready-formulated and copy-and-paste-able, rather than working it out from first principles each time.


Command Aliases

If you do a lot of this type of dangerous, irresponsible messing about under the hood of your Discourses, you may find it saves time to add an alias to /etc/profile which will make you sudo, and enter the container for you:

alias app='sudo su && cd /var/discourse && ./launcher enter app'

then you just type rails c and you’re ready to cause serious damage!


Select some users by Group

users = User.joins(:groups).where(groups: {name: "GROUP_NAME_SLUG"})


Change UserOptions for a group of users

This can be useful when changing everyone to use mailing_list_mode on small fora with low traffic, for example. Until users are used to setting Watching/Muted etc on Categories, you can kill off a forum’s traffic if users are not receiving notifications via email, especially in fora that have recently been migrated from an email listserver or other mailing list.

  • Work out the name of the UserOption OPTION_NAME you want to change, and the DESIRED_VALUE to set. The Discourse source code is your friend here.
  • Obtain the group of users you need (see above for getting user by Group) and assign them to users
  • (optional) check the current status of the option:
    users.each { |u| p u.user_option.OPTION_NAME }
  • Then run the change:
    users.each { |u| u.user_option.OPTION_NAME=DESIRED_VALUE; u.user_option.save! }
  • Check the change worked:
    users.each { |u| p u.user_option.OPTION_NAME }
  • If you want to change ALL users then just change users.each to User.all.each above and skip the ‘get list of users’ bit

Change Notification level for a group of users (relating to a Category)

  • get your list of Users (see above for Groups or find by another method) assigned to users
  • find which DESIRED_NOTIFICATION_LEVEL you want to set (from the CategoryUser source code)
  • find out the CATEGORY_ID (Category.where(name: "CATEGORY_NAME").first.id)
users.each do |user|
CategoryUser.set_notification_level_for_category(
  user,
  CategoryUser.notification_levels[DESIRED_NOTIFICATION_LEVEL], CATEGORY_ID) unless CategoryUser.exists?(user_id: user.id, category_id: CATEGORY_ID)
  # 'unless' means if there's already a preference we don't override it
  # remove the unless if you want it to overwrite existing prefs (and annoy your users)
end

Change Notification level for a user (relating to a Tag)

  • WIP
TagUser.change(
  user,
  tag_id,
  TagUser.notification_levels[desired_notification_level]) unless TagUser.exists?(user_id: user.id, tag_id: tag_id
)