Obtener el ID del tema cuando se carga la página de visualización del tema

En mi tema, cuando se carga la página de visualización de un tema, necesito obtener el ID de ese tema (y también el nombre, si es posible, pero el ID sería suficiente).

Luego uso esta información en mi tema para realizar una llamada a la API y obtener información sobre el tema (con una llamada a un endpoint como nombre-foro/t/nombre-tema/id.json…)

¿Cómo puedo obtener el ID del tema cuando se carga la página de visualización del tema?

Los métodos obvios no son suficientes

La solución obvia es usar window.location.href o window.location.pathname para obtener información de la URL. El problema es que la URL de la página de visualización del tema puede tener diferentes formas. A menudo, sería:
nombre-foro/t/nombre-tema/id-tema

Si esa fuera siempre la forma, entonces usar window.location pathname funcionaría bien, dándome “t/nombre-tema/id-tema”.

PERO, a veces la URL de la página de visualización del tema añade también el orden de la categoría del tema, por lo que la URL es: nombre-foro/t/nombre-tema/id-tema/indice-categoria

Por lo tanto, usar window.location.pathname es insuficiente, porque no sé programáticamente si el último parámetro será el id-tema o el indice-categoria.

Puede haber una forma de resolver esto usando regex, pero eso requiere una habilidad seria con regex. También puede haber una forma de resolverlo con jQuery, mirando elementos en la página que puedan dar el ID, pero aún no he logrado que funcione.

¿Cuándo y dónde ocurre eso? No pude encontrarlo.

De todos modos, cuando se carga este tema, tiene un elemento link:

<link rel="canonical" href="https://meta.discourse.org/t/get-topic-id-when-the-topic-show-page-loads/155620" />

Quizás puedas obtenerlo de ahí. :slight_smile:

En mi foro, esto en realidad ocurre la mayoría de las veces cuando haces clic en un tema. El último fragmento de la URL será el número del tema dentro de la categoría, si has hecho clic en el tema desde esa categoría. ¿Quizás sea una configuración en Discourse? No parece ocurrir en meta-, pero no creo que esté haciendo nada especial para provocar esto en mi foro.

Sin embargo, no siempre puedo confiar en que esto ocurra, porque si un tema es el primero en la categoría, no se le añade el índice de la categoría. Así que, hasta donde puedo ver, no hay una buena manera ahora mismo para saber si aparecerá o no en el índice de la categoría.

Obtener el ID desde un div está bien, pero, lamentablemente, es bastante más lento que poder obtenerlo directamente de la URL o mediante algún otro medio directo. En caso de que no haya otra solución, ¿sabes cómo usar jQuery para obtener el valor de ese Href?

Prueba

api.onPageChange((url, title) => {
    var res = url.match(/\/t\/(.*?)\/(\w+)/);
    if (res && res[2] > 0) {
        console.log(res[2]);
    }
});

¿Qué estás intentando lograr?

Esto podría funcionar, pero no es muy eficiente, ya que estás realizando una solicitud AJAX adicional por cada visita a la página de un tema para cada usuario, incluidos los anónimos. Esto generará una carga innecesaria en tu servidor.

No exactamente. La URL de un tema se ve así:

tu.sitio.com/t/titulo-tema/id-tema/numero-post-vinculado(opcional)

No hay un orden de categoría en la URL en una instalación predeterminada de Discourse.

Podemos ayudarte si describes el problema que intentas resolver en lugar de describir tus soluciones para ello.

¡Esto funciona! Muchas gracias. Entiendo que con el método match aquí, estás recorriendo la URL para obtener, supongo, la tercera ocurrencia de “/”, ya que el ID siempre aparecerá después de la tercera “/” en la URL, la cual tiene el formato “/t/nombre/id/otracosa”. ¿Podrías darme un poco de información sobre cómo funciona tu expresión regular? Sería muy útil en mi viaje aprendiendo regex.

Gracias por la información. Entonces es el “numero_de_publicacion_vinculada” el que aparece a veces y hace fallar mi llamada a la API. ¿Dices aquí que es “opcional”? ¿Hay alguna forma de asegurarse de que nunca se muestre?

Cuando un usuario visita la página de visualización del tema, quiero:

  1. Saber programáticamente todas las etiquetas asociadas a ese tema. Ten en cuenta que algunas etiquetas están ocultas para la vista del usuario.
  2. Tener un botón en la página del tema que, al hacer clic, añada una etiqueta oculta específica al tema (si aún no está presente), y que la elimine al hacer clic (si la etiqueta oculta ya está presente).

Todo esto es bastante sencillo usando la API de Administración y JavaScript/jQuery (asumiendo que puedo obtener la URL correcta del tema para usar en las llamadas a la API).

Creo que la única otra forma de hacer este tipo de cosas sería crear un plugin donde tendría que adentrarme profundamente en 1. Ember, 2. Rails y 3. la base de código de Discourse. He revisado las publicaciones clave de Discourse y la documentación sobre cómo hacerlo, pero he encontrado que avanza lentamente porque realmente necesitas entender estos tres componentes. Por ahora, me he centrado en el enfoque de la API.

Me gustaría saber si hay otra forma de hacer esto que reduzca la carga del servidor.

Ciertamente, podría haberte ayudado con el código si se tratara de una solución de un solo paso, pero hay varios pasos involucrados. Si necesitas ayuda en forma de consulta para realizar el trabajo o aprender a escribir componentes de tema por ti mismo, por favor publica en el Marketplace y me pondré en contacto contigo.

Gracias, pero es útil recibir orientación en cualquier paso. Por ejemplo, aparte de usar la API, ¿cómo sabría todas las etiquetas asociadas a un tema?

Un objeto de tema completo se carga en el lado del cliente al cargar la página del tema. Ahora, si quieres usarlo, necesitas agregar tu propio código a la plantilla para utilizar esos datos, o reopen clases para aprovechar los datos cargados (es decir, básicamente crear tus propias propiedades computadas y utilizarlas en la plantilla). Tiene la mayoría de los datos que necesitas (probablemente más de los que necesitas) cargados en el lado del cliente sin llamadas adicionales a la API. También necesitas plugin-outlets para insertar tu propio marcado en plantillas existentes.

Ahora, sería útil si revisaras el código base/meta para los términos que usé anteriormente. Estaré encantado de ayudarte aquí si te quedas atascado, dentro de mis posibilidades en términos de tiempo. Saludos.

Gracias. Estoy familiarizado con algunos de los conceptos básicos que mencionas, pero hay un punto que me deja atascado (y apuesto a que esto le pasa a mucha gente):

En la página de visualización del tema, se carga la plantilla /templates/components/topic-category.hbs. Es lo que muestra la categoría y también la etiqueta debajo del título del tema.

En topic-category, se enumeran topic.tags. Ese es el dato clave que necesito para poner esto en marcha.

Aquí es donde me quedo atascado: ¿Cómo puedo obtener esa información de topic.tags en mi JavaScript?

Por ejemplo, si solo quisiera hacer un console.log del contenido de topic.tags, ¿cómo lo haría?


Sé cómo sobrescribir plantillas. Por ejemplo, en un tema, podría crear un archivo en discourse/templates/components/topic-category.hbs, volver a imprimir la plantilla allí y añadir los cambios que quisiera hacer en la vista. (Estoy usando la estructura de archivos separada descrita aquí).

En mi tema, también sé cómo colocar JavaScript en theme/initializers/initializer-file.js.es6.

Y puedo hacer que ambos interactúen con algo de jQuery. Por ejemplo, podría poner los topic.tags en un div en la plantilla y acceder a ellos en mi inicializador con jQuery obteniendo el contenido de ese div.

Pero eso es indirecto. ¿Cómo puedo obtener esa información de topic.tags directamente para poder analizarla y manipularla?

Hacería un console.log de todo el topic y buscaría la clave requerida. Para las interacciones con jQuery, estas se realizan y deben realizarse desde dentro de los componentes. didInsertElement es el hook del componente que resulta útil aquí.

Por lo que se entiende, parece que necesitas una propiedad computada que dependa de topic.tags y que devuelva tu manipulación de la misma en el controlador o componente correspondiente. Es utilizable directamente en la plantilla. Además, no te rindas con esto. Tomará tiempo, pero definitivamente dará frutos de maneras mejores de las que podrías imaginar.

¿Qué quieres decir con “dentro de los componentes”? ¿En qué archivo debo poner el código de jQuery? (en mi tema, puedo usar jQuery en el archivo tema/inicializadores/archivo-inicializador.js.es6, pero eso no parece estar “dentro” del componente)

¿En qué archivo va el código de didInsertElement?

En este punto, deberías consultar las guías de Ember. Un componente es un paquete de funcionalidad que puedes implementar y adjuntar a otros elementos.

Gracias, chicos, toda esta información es muy útil. Estoy revisando las guías y la documentación general. También sería de gran ayuda saber el nombre del archivo donde debo colocar el código de (i) jQuery y (ii) didInsertElement. Contar con este tipo de información concreta será de gran ayuda para orientar la revisión posterior.

Componentes = componentes de Ember.

Puedes reopen (reabrir) todo tipo de clases de Ember e inyectar tu código en ellas. Tendrás que buscar plugins o temas que lo hagan para tener una mejor idea.

@JQ331 Como probablemente sepas, encontré expresiones regulares en Google y las probé aquí. Puedes probar variaciones para obtener los mejores resultados.

Esto parece ser terreno para un plugin.

Si las etiquetas están ocultas para el usuario normal, ¿cómo ayudaría una llamada adicional? El serializador, en cualquier caso, debería estar ocultando esas etiquetas al usuario normal. Si no es así, estás exponiendo una vulnerabilidad de seguridad del contenido.

Si vas a tomar tantas molestias para sortear las limitaciones de los cambios solo en el frontend, te sugiero que te decidas y consideres construir esto como un plugin, donde podrías serializar todo de una sola vez en lugar de tener una configuración desordenada con llamadas adicionales.

Tiene sentido. Me gustaría aprender más sobre el uso del serializador: aunque el serializador es uno de los pasos más importantes en un complemento de Discourse, aún no he encontrado documentación que presente ejemplos básicos de su uso. ¿Conoces esa documentación?

Cuando dices que un serializador debería ocultar esas etiquetas, ¿podrías proporcionar algún pseudocódigo para darme una idea de lo que quieres decir? (No importa si no funciona del todo bien; solo estoy tratando de entender el concepto).

Aquí:

Esto es como la música jazz… las mejores prácticas suelen estar ya disponibles en el paisaje existente de plugins de código abierto, al igual que todos los discos. No esperes una guía perfecta sobre cómo hacer todo; muchas veces tienes que ponerte en el ritmo (ehem) de aprender de obras previas.

Busca un plugin en #plugin que haga algo funcionalmente similar, o un elemento de lo que quieres hacer, e inspecciona el código para ver cómo logra las cosas. Lo mismo se aplica al código fuente de Discourse, que puedes utilizar como fuente de la “mejor práctica” definitiva, especialmente en lo que respecta a Discourse.

Clona un plugin existente localmente e intenta cambiar algunas cosas, experimenta.

Los serializadores simplemente filtran lo que se envía desde los controladores/modelos y también pueden realizar algunas manipulaciones básicas.

Aquí tienes un ejemplo de la fuente: discourse/app/serializers/concerns/topic_tags_mixin.rb at 888e68a1637ca784a7bf51a6bbb524dcf7413b13 · discourse/discourse · GitHub

  def tags
    # Llamada al método `pluck` junto con `includes` que provoca consultas N+1
    tags = topic.tags.map(&:name)

    if scope.is_staff?
      tags
    else
      tags - scope.hidden_tag_names
    end
  end

Como puedes ver, aquí se excluyen las etiquetas ocultas para los usuarios que no son personal.