태그별 첫 게시물의 소유권 일괄 변경 – 스크립트 검토 및 제안

안녕하세요,

“ethan” 태그가 붙은 이벤트 토픽의 모든 첫 번째 게시글(Opening Post)의 소유자를 "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


  # 드라이 런 모드(DRY_RUN)가 활성화된 경우 아무것도 수정하지 않습니다
  if DRY_RUN
    puts "[DRY RUN] 토픽 #{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개의 좋아요