Hola,
Estoy buscando cambiar la propiedad de todas las publicaciones iniciales en temas de eventos etiquetados con “ethan” para que el propietario cambie de “system” al usuario “Ethan_Hoom1”. Estoy ejecutando una instancia autoalojada y tengo acceso a la consola de Rails.
Después de revisar las recomendaciones en Administrative Bulk Operations y Change ownership of all posts by a specific user, he preparado el siguiente script. Agradecería cualquier sugerencia o mejores prácticas antes de ejecutarlo en producción:
# Encuentra el objeto de etiqueta con el nombre "ethan"
tag = Tag.find_by(name: "ethan")
# Detente inmediatamente si la etiqueta no se encuentra
raise "Tag not found" unless tag
# Encuentra el usuario que se convertirá en el nuevo propietario de las publicaciones
# username_lower es más seguro que username (insensible a mayúsculas y minúsculas)
new_owner = User.find_by(username_lower: "ethan_hoom1")
# Detente inmediatamente si el usuario de destino no existe
raise "New owner user not found" unless new_owner
# Encuentra la cuenta de usuario del sistema
# Recurre a Discourse.system_user en caso de que la búsqueda del registro falle
system_user = User.find_by(username_lower: "system") || Discourse.system_user
# Detente inmediatamente si no se puede encontrar el usuario del sistema
raise "System user not found" unless system_user
# Cuando sea verdadero, el script solo imprimirá lo que CAMBIARÍA
# y no modificará nada en la base de datos
DRY_RUN = true
# Límite de seguridad opcional para la primera ejecución (ej. 10 o 50)
# Establécelo en nil para procesar todas las publicaciones coincidentes
LIMIT = nil
# Construye una consulta ActiveRecord para las publicaciones que queremos modificar
scope = Post
# Une publicaciones → temas → topic_tags para poder filtrar por etiqueta
.joins(topic: :topic_tags)
# Solo apunta a la publicación inicial en cada tema
.where(post_number: 1)
# Solo apunta a las publicaciones actualmente propiedad del usuario del sistema
.where(user_id: system_user.id)
# Solo incluye temas que tienen la etiqueta "ethan"
.where(topic_tags: { tag_id: tag.id })
# Excluye mensajes privados y temas eliminados
.where(topics: {
archetype: Archetype.default,
deleted_at: nil
})
# Si LIMIT está configurado, restringe cuántas publicaciones se procesan
scope = scope.limit(LIMIT) if LIMIT
# Itera a través de las publicaciones coincidentes por lotes para evitar problemas de memoria
scope.find_each(batch_size: 100) do |first_post|
# Almacena el ID del tema para la salida de registro
topic_id = first_post.topic_id
# Si el modo dry-run está habilitado, no modifiques nada
if DRY_RUN
puts "[DRY RUN] Would change owner for topic #{topic_id} (post #{first_post.id})"
next
end
begin
# Usa el servicio oficial de cambio de propietario de Discourse
PostOwnerChanger.new(
# Solo cambia la propiedad de la publicación inicial
post_ids: [first_post.id],
# El tema que contiene la publicación
topic_id: topic_id,
# El usuario que se convertirá en el nuevo propietario
new_owner: new_owner,
# El usuario que realiza la acción (usuario del sistema)
acting_user: system_user,
# No crear una revisión de edición para este cambio
skip_revision: true
).change_owner!
# Registra el éxito en la consola
puts "Changed owner for topic #{topic_id} (post #{first_post.id})"
rescue => e
# Si algo falla, registra el error pero continúa procesando otros
puts "FAILED topic #{topic_id} (post #{first_post.id}): #{e.class}: #{e.message}"
end
end
Preguntas:
- ¿Hay alguna advertencia o caso extremo que deba tener en cuenta con
PostOwnerChangerpara este caso de uso? - ¿Es aconsejable actualizar también el campo
topic.usercomo se muestra en la línea opcional? - ¿Tiene alguna recomendación para mejorar aún más la seguridad o el rendimiento con respecto a este proceso por lotes?
¡Gracias por su ayuda y por toda la excelente documentación!