안녕하세요,
“ethan” 태그가 붙은 이벤트 토픽의 모든 첫 번째 게시글(Opening Post)의 소유자를 "system"에서 “Ethan_Hoom1” 사용자로 변경하려고 합니다. 자체 호스팅 인스턴스를 운영하고 있으며 Rails 콘솔 접근 권한이 있습니다.
Administrative Bulk Operations와 Change 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필드도 업데이트하는 것이 권장되나요? - 이 배치 프로세스에 대한 추가적인 안전성 또는 성능 개선에 대해 추천 사항이 있나요?
도와주셔서 감사합니다. 훌륭한 문서도 감사합니다!