Массовое изменение владельцев первых сообщений по тегу — обзор скрипта и предложения

Здравствуйте,

Я хочу изменить владельца всех стартовых сообщений в темах событий, помеченных тегом «ethan», так, чтобы владелец сменился с «system» на пользователя «Ethan_Hoom1». Я работаю с самохостинговой версией и имею доступ к консоли Rails.

После изучения рекомендаций в статьях Массовые административные операции и Изменение владельца всех сообщений конкретного пользователя, я подготовил следующий скрипт. Буду признателен за любые предложения или рекомендации по лучшим практикам перед запуском в производственной среде:


# Найти объект тега с именем "ethan"
tag = Tag.find_by(name: "ethan")

# Немедленно остановиться, если тег не найден
raise "Тег не найден" unless tag


# Найти пользователя, который должен стать новым владельцем сообщений
# username_lower безопаснее, чем username (регистронезависимый поиск)
new_owner = User.find_by(username_lower: "ethan_hoom1")

# Немедленно остановиться, если целевой пользователь не найден
raise "Пользователь-новый владелец не найден" unless new_owner


# Найти учетную запись пользователя системы
# В случае неудачи поиска записи использовать Discourse.system_user
system_user = User.find_by(username_lower: "system") || Discourse.system_user

# Немедленно остановиться, если пользователь системы не найден
raise "Пользователь системы не найден" unless system_user


# Если значение true, скрипт будет только выводить то, что ОН БЫ ИЗМЕНИЛ,
# но ничего не будет изменять в базе данных
DRY_RUN = true

# Опциональный предел безопасности для первого запуска (например, 10 или 50)
# Установите nil для обработки всех подходящих сообщений
LIMIT = nil


# Построить запрос ActiveRecord для сообщений, которые нужно изменить
scope = Post
  # Присоединить сообщения → темы → topic_tags, чтобы можно было фильтровать по тегу
  .joins(topic: :topic_tags)

  # Нацелиться только на стартовое сообщение в каждой теме
  .where(post_number: 1)

  // Нацелиться только на сообщения, принадлежащие пользователю системы
  .where(user_id: system_user.id)

  // Включить только темы с тегом "ethan"
  .where(topic_tags: { tag_id: tag.id })

  // Исключить личные сообщения и удаленные темы
  .where(topics: {
    archetype: Archetype.default,
    deleted_at: nil
  })


# Если установлен LIMIT, ограничить количество обрабатываемых сообщений
scope = scope.limit(LIMIT) if LIMIT


# Итерироваться по подходящим сообщениям пакетами, чтобы избежать проблем с памятью
scope.find_each(batch_size: 100) do |first_post|

  # Сохранить ID темы для вывода в лог
  topic_id = first_post.topic_id


  # Если включен режим пробного запуска, ничего не изменять
  if DRY_RUN
    puts "[ПРОБНЫЙ ЗАПУСК] Будет изменен владелец темы #{topic_id} (сообщение #{first_post.id})"
    next
  end


  begin
    # Использовать официальный сервис Discourse для изменения владельца
    PostOwnerChanger.new(
      // Изменить владельца только стартового сообщения
      post_ids: [first_post.id],

      // Тема, содержащая сообщение
      topic_id: topic_id,

      // Пользователь, который должен стать новым владельцем
      new_owner: new_owner,

      // Пользователь, выполняющий действие (пользователь системы)
      acting_user: system_user,

      // Не создавать черновик редактирования для этого изменения
      skip_revision: true
    ).change_owner!


    // Записать успех в консоль
    puts "Изменен владелец темы #{topic_id} (сообщение #{first_post.id})"

  rescue => e
    // Если что-то пойдет не так, записать ошибку, но продолжить обработку остальных
    puts "ОШИБКА тема #{topic_id} (сообщение #{first_post.id}): #{e.class}: #{e.message}"
  end
end

Вопросы:

  • Есть ли какие-либо нюансы или крайние случаи, о которых мне следует знать при использовании PostOwnerChanger для этого сценария?
  • Целесообразно ли также обновлять поле topic.user, как показано в опциональной строке?
  • Есть ли у вас рекомендации по дальнейшему повышению безопасности или производительности этого пакетного процесса?

Спасибо за вашу помощь и за отличную документацию!

1 лайк