批量更改标签的首批帖子所有权 - 脚本审查和建议

您好,

我希望更改所有标记为“ethan”的事件主题中初始帖子的所有权,将所有者从“system”更改为用户“Ethan_Hoom1”。我正在运行自托管实例,并且可以访问 Rails 控制台。

在查看了 Administrative Bulk OperationsChange ownership of all posts by a specific user 的建议后,我准备了以下脚本。在生产环境中运行它之前,我希望得到任何建议或最佳实践:


# 查找名称为“ethan”的标签对象
tag = Tag.find_by(name: "ethan")

# 如果未找到标签,立即停止
raise "Tag not found" unless tag


# 查找应成为帖子新所有者的用户
# username_lower 比 username 更安全(不区分大小写)
new_owner = User.find_by(username_lower: "ethan_hoom1")

# 如果未找到目标用户,立即停止
raise "New owner user not found" unless new_owner


# 查找系统用户账户
# 如果记录查找失败,则回退到 Discourse.system_user
system_user = User.find_by(username_lower: "system") || Discourse.system_user

# 如果找不到系统用户,立即停止
raise "System user not found" unless system_user


# 如果为 true,脚本将仅打印它将更改的内容
# 并且不会修改数据库中的任何内容
DRY_RUN = true

# 首次运行时可选的安全限制(例如 10 或 50)
# 设置为 nil 以处理所有匹配的帖子
LIMIT = nil


# 构建一个 ActiveRecord 查询,用于我们想要修改的帖子
scope = Post
  # 连接帖子 → 主题 → 主题标签以便按标签过滤
  .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 "[DRY RUN] Would change owner for topic #{topic_id} (post #{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 "Changed owner for topic #{topic_id} (post #{first_post.id})"

  rescue => e
    # 如果出现任何故障,记录错误但继续处理其他帖子
    puts "FAILED topic #{topic_id} (post #{first_post.id}): #{e.class}: #{e.message}"
  end
end

问题:

  • 对于这种情况,我应该注意 PostOwnerChanger 的哪些注意事项或边缘情况?
  • 建议像可选行中显示的那样也更新 topic.user 字段吗?
  • 对于这种批量处理,您对进一步的安全或性能改进有什么建议吗?

感谢您的帮助以及所有出色的文档!

1 个赞