Usando tag-chooser en un plugin

Estoy trabajando en un plugin que asignará una etiqueta predeterminada a los nuevos temas creados en una categoría.

El siguiente código “funciona” si ingreso nombres de etiquetas separados por “|”, por lo que “tag1|tag2” funciona. (¡Apenas puedo creerlo! Pero me desvío del tema.)

<h3>{{i18n 'topic_default_tag.title'}}</h3>
<section class='field default-tag'>
  <div class="default-tag">
  <label>
    {{input type="list" value=category.custom_fields.default_tag }}
    {{popup-input-tip validation=tagValidation}}
    {{i18n 'topic_default_tag.default_tag'}}
  </label>
  </div>
</section>

Lo que ahora me gustaría es tener un selector de etiquetas adecuado en lugar de una cadena no validada. Parece que lo siguiente debería funcionar:

<h3>{{i18n 'topic_default_tag.title'}}</h3>
<section class='field default-tag'>
  <div class="default-tag">
  <label>
    {{tag-chooser tags=category.custom_fields.default_tag tabindex="4" categoryId=category.id}}
    {{popup-input-tip validation=tagValidation}}
    {{i18n 'topic_default_tag.default_tag'}}
  </label>
  </div>
</section>

Pero no funciona. La base de mi problema es que tengo casi nula idea de cómo funciona la magia de esos Handlebars. Por ejemplo, supongo que la primera sección funciona porque mágicamente obtiene el nombre del campo de default-tag en <section class='field default-tag'>, pero eso fue suerte. :slight_smile:

Cuando uso tag-chooser, las etiquetas se pasan a Rails como un array, que lo descarta antes de que pueda convertirlo en una cadena delimitada por | para insertarla en CategoryCustomField. Con {{input type=list...}} puedo ingresar yo mismo la cadena delimitada por | y funciona perfectamente. ¿Necesito algún tipo de magia de Ember para convertir el array en una cadena en el lado de Ember?

¿Quizás necesito hacer algo como What's the best approach to access category specific settings??

EDITO: Para agregar etiquetas antes de que se llame al webhook, usa after_create en lugar de DiscourseEvent.on(:post_created). Rails ahora tiene más sentido para mí, pero Ember, Javascript y CSS, no tanto.

Puedes verificar si las variables que estás utilizando contienen los valores necesarios usando {{log variable_name}} y revisando la consola. Si los valores correctos no se pasan al componente, este no mostrará la salida adecuada.

Puedes verificarlos haciendo lo mismo en el código principal para confirmar si los valores se pasan correctamente.

Perdona si suena ingenuo para ti.

¡No! Solo soy un cavernícola.

Eso es muy útil, ya que no sabía cómo hacerlo. Resulta que tengo datos en esos campos. Y, los datos del nombre de la etiqueta están en category.custom_fields.default_tag y se están pasando al mini-tag-chooser. category.id tiene el ID de una categoría, pero el selector no ofrece ninguna etiqueta.

No puedo saber si, de ser así, esos datos se inyectarían en el campo.

EDITO: ¡OOOH! Pero usar tag-chooser en lugar de mini-tag-chooser funciona como debería (voy a editar el código anterior en consecuencia). El único problema es que los datos no se guardan cuando hago clic en guardar.

Esta línea me hace sospechar. Creo que tags podría estar recibiendo un array y, por lo que veo, estás pasando un solo valor (necesitas confirmarlo). Si se está pasando como un único valor, simplemente conviértelo en un array e inténtalo de nuevo.

Bueno, en el lado de Rails, es una cadena delimitada por | y veo que, después de enviar, lo que he ingresado se está enviando, por ejemplo: "custom_fields"=>{"de fault_tag"=>["error", "high-availability", "best-practices"]}, y "custom_fields"=>{"de fault_tag"=>["health-checks"]},

Aquí está todo:

Started PUT "/categories/2" for 127.0.0.1 at 2019-08-01 13:56:13 -0700
Processing by CategoriesController#update as */*
  Parameters: {"name"=>"Lounge", "slug"=>"lounge", "color"=>"EEEEEE", "text_color"=>"652D90", "permissions"=>{"trus
t_level_3"=>"1"}, "auto_close_hours"=>"", "auto_close_based_on_last_post"=>"false", "position"=>"3", "email_in"=>""
, "email_in_allow_strangers"=>"false", "mailinglist_mirror"=>"false", "allow_badges"=>"true", "custom_fields"=>{"de
fault_tag"=>["error", "high-availability", "best-practices"]}, "topic_template"=>"", "suppress_from_latest"=>"false
", "all_topics_wiki"=>"false", "allow_global_tags"=>"false", "sort_order"=>"", "sort_ascending"=>"", "topic_feature
d_link_allowed"=>"true", "show_subcategory_list"=>"false", "num_featured_topics"=>"3", "default_view"=>"", "subcate
gory_list_style"=>"rows_with_featured_topics", "default_top_period"=>"all", "minimum_required_tags"=>"0", "navigate
_to_first_post_after_read"=>"false", "search_priority"=>"0", "id"=>"2"}

Parece que lo correcto está ocurriendo en el lado misterioso, pero Rails no está actualizando el campo personalizado de la categoría. Volveré a comparar lo que tengo con otro plugin que trabaja con CategoryCustomFields.

¡Muchas gracias, @fzngagan!

EDIT: Hmm. Creo que el problema es:

Unpermitted parameter: :default_tag

Te encantará encontrar la respuesta a eso. Aun así, si necesitas ayuda, estaré más que encantado de brindártela. :slight_smile:

Sí, lo es. Rails no sabe todavía qué hacer con este nuevo campo. Necesitas add_to_serializer el nuevo campo. Puedes ver ejemplos de esto en plugins que agregan campos personalizados.

Bueno, plugin.rb incluye:

  Category.register_custom_field_type('default_tag', :list)
  Site.preloaded_category_custom_fields << 'default_tag' if Site.respond_to? :preloaded_category_custom_fields
  add_to_serializer(:basic_category, :default_tag) { object.custom_fields["default_tag"] }

Está disponible en GitHub - pfaffman/discourse-topic-default-tag: Allow topics to include default tags · GitHub si quieres echar un vistazo.

Estoy confundido porque esto:

   {{input type="list" value=category.custom_fields.default_tag }}

funcionaba, pero esto:

{{tag-chooser tags=category.custom_fields.default_tag tabindex="4" categoryId=category.id}}

no funciona.

EDITO: Parece que al usar tag-chooser, mi campo personalizado se envía a Rails como un array y luego se descarta antes de ser procesado. Sin embargo, al usar un campo de texto donde creo una cadena delimitada por |, funciona perfectamente. (Pensé que tal vez podría solucionarlo con un before_validation en el lado de Rails, pero no hubo suerte.)

Así que supongo que necesito algún truco en el lado de Ember para convertir el array en una cadena antes de enviarlo de nuevo.

Yo también usé tag-chooser sin parámetros y obtuvo todas las etiquetas disponibles.

Además, creo que encontré la razón por la que esas no se guardan (ni siquiera llegan) :wink: en el lado de Rails al usar tag-chooser. Cuando usas input type list y agregas un campo value, eso se convierte automáticamente en parte del formulario.

Pero el marcado generado por el selector de etiquetas es un div. Por eso no se agrega al envío del formulario.

Estoy tratando de armar una solución alternativa para ello. Enviaré un PR en cuanto logre que funcione.

Hablé con @j.jaffeux ayer y está trabajando en realizar un cambio.

Eso es exactamente en lo que estoy trabajando.

Eso es genial. Como principiante, estoy tratando de aprender cada vez más y esto ayuda mucho :slight_smile:

Hola @pfaffman.

Logré armar una solución. No pude hacerlo desde el lado de Ember, ya que tag-chooser parecía demasiado útil para descartarlo, pero lo logré desde el lado de Rails.

Escribí una función sencilla en CategoriesController y la llamé :before_action. En ella, convertí el array default_tag en una cadena delimitada por |.

En segundo lugar, cambié before_update por before_commit, ya que los custom_fields parecen estar establecidos en ese punto de la ejecución.

Hmm. Pensé que ya lo había probado, pero lo revisaré cuando llegue a la oficina. ¡Gracias!

¡Ajá! Eso es lo que no sé cómo hacer. ¿Lo colocas en plugin.rb?

Sí. Esto funcionó para mí.

class ::ApplicationController
    def convert_default_tag
      return unless :topic_default_tag_enabled
      puts 'request'
     #Solo verifica si el campo existe para evitar errores
      request.params["custom_fields"]["default_tag"] = request.params["custom_fields"]["default_tag"].join('|')
      p request.params["custom_fields"]["default_tag"]
    end
  end
  require 'categories_controller'
  class ::CategoriesController
     before_action :convert_default_tag , only: [:create]
  end

Creo que es posible definir el método default_tag directamente en el controlador, pero no pude hacerlo funcionar de esa manera. Como ApplicationController es del que hereda cada controlador de Discourse, el método se carga al extender la clase desde ApplicationController, lo cual hace el trabajo.

@merefield
¿Es posible definir un método llamado :before_action directamente en el controlador?

Debes poner tres comillas invertidas antes y después del bloque de código.

```
 El código va aquí
  ```

¡No puedo esperar a probarlo mañana! Muchas gracias.

Gracias. Pensé que era una comilla invertida simple, pero estaba atascado. Así que usé las etiquetas HTML clásicas <pre></pre> para que funcionara.

Sí, creo que sí

Eso es una gran ayuda. Ahora tengo esto:

  class ::CategoriesController
    before_action :default_tag_to_string, only: [:create, :update]

    def default_tag_to_string
      puts "CDT: #{params}"

      return unless :topic_default_tag_enabled
      #Solo verificamos si el campo existe para evitar errores
      request.params["custom_fields"]["default_tag"] = request.params["custom_fields"]["default_tag"].join('|')
      p request.params["custom_fields"]["default_tag"]
    end

  end

Ahora, las etiquetas seleccionadas se convierten en una cadena antes de que Rails intente actualizar el registro, y funciona como se esperaba.

AHORA el problema es que necesito averiguar dónde convertir la cadena en el sitio de Rails en el array que necesitamos en el lado de Javascript/Ember. @j.jaffeux, no recuerdo (o, más probablemente, no entendí) si el problema que intentabas resolver era reescribir este valor en el lado de javascript-a-rails (¡resuelto!) o en el lado de rails-a-javascript (todavía confundido).

Lo que me funcionó fue cambiar :before_update por :before_commit en tu código al asignar etiquetas al tema.

En segundo lugar, cuando abres la página de edición de categoría, el campo de configuración de etiquetas predeterminado requiere un array en su parámetro de etiquetas para mostrar las etiquetas seleccionadas.