Usando tag-chooser em um plugin

Estou trabalhando em um plugin que atribuirá uma tag padrão a novos tópicos criados em uma categoria.

O código abaixo “funciona” se eu inserir nomes de tags separados por “|”, então “tag1|tag2” funciona. (Mal posso acreditar! Mas estou divagando.)

<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>

O que eu gostaria agora é ter um seletor de tags adequado, em vez de uma string não validada. Parece que o código abaixo deveria 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>

Mas não funciona. A base do meu problema é que tenho quase nenhuma ideia de como a mágica do Handlebars funciona. Tipo, eu acho que a primeira seção funciona porque está magicamente pegando o nome do campo de default-tag em <section class='field default-tag'>, mas isso foi sorte. :slight_smile:

Quando uso o tag-chooser, as tags são passadas para o Rails como um array, que ele descarta antes que eu possa convertê-las em uma string delimitada por | para inserir no CategoryCustomField. Com o {{input type=list...}}, posso inserir a string delimitada por | manualmente e funciona perfeitamente. Preciso de alguma mágica do Ember para converter o array em uma string no lado do Ember?

Talvez eu precise fazer algo como What's the best approach to access category specific settings??

EDIT: Para adicionar tags antes que o webhook seja chamado, use after_create em vez de DiscourseEvent.on(:post_created). O Rails faz sentido para mim agora, mas Ember, Javascript e CSS, não tanto.

Você pode verificar se as variáveis que está usando contêm os valores necessários usando {{log nome_da_variavel}} e verificando o console. Se os valores corretos não forem passados para o componente, ele não exibirá a saída correta.

Você pode verificá-los fazendo o mesmo no código principal para confirmar se os valores estão sendo passados corretamente.

Peço desculpas se isso soar ingênuo para você.

Não! Eu sou apenas um homem das cavernas.

Isso é muito útil, pois eu não sabia como fazer isso. Acontece que eu tenho dados nesses campos. E, os dados do nome da tag estão em category.custom_fields.default_tag e estão sendo passados para o mini-tag-chooser. category.id possui o ID de uma categoria, mas o seletor não está oferecendo nenhuma tag.

Não consigo dizer se, com esses dados, eles seriam inseridos no campo.

EDIT: OOOOH! Mas usar tag-chooser em vez de mini-tag-chooser está funcionando como deveria (vou editar o código acima de acordo). O único problema é que os dados não estão sendo salvos quando clico em salvar.

Essa linha me deixa desconfiado. Acho que o tags pode estar recebendo um array e, pelo que vejo, você está passando um único valor (precisa confirmar isso). Se estiver sendo passado como um único valor, basta transformá-lo em um array e tentar.

Bem, no lado do Rails, é uma string delimitada por | e vejo que, após enviar, o que digitei está sendo submetido, por exemplo, "custom_fields"=>{"de fault_tag"=>["error", "high-availability", "best-practices"]}, e "custom_fields"=>{"de fault_tag"=>["health-checks"]},

Aqui está tudo:

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"}

Então parece que a coisa certa está acontecendo no lado misterioso, mas o Rails não está atualizando o campo personalizado da Categoria. Vou voltar a comparar o que tenho com outro plugin que lida com CategoryCustomFields.

Muito obrigado, @fzngagan!

EDIT: Hmm. Acho que o problema é:

Parâmetro não permitido: :default_tag

Você vai adorar encontrar a resposta para isso. Ainda assim, se precisar de ajuda, ficarei mais do que feliz em ajudar. :slight_smile:

Sim, é isso. O Rails ainda não sabe o que fazer com esse novo campo. Você precisa adicionar ao serializer o novo campo. Você pode ver exemplos disso em plugins que adicionam campos personalizados.

Bem, plugin.rb inclui:

  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"] }

O código está em GitHub - pfaffman/discourse-topic-default-tag: Allow topics to include default tags · GitHub, caso queira dar uma olhada.

Estou confuso porque o uso de

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

funcionou, mas

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

não funcionou.

EDIT: Parece que ao usar tag-chooser, meu campo personalizado é enviado ao Rails como um array e descartado antes de ser processado. Já ao usar um campo de texto, onde crio uma string delimitada por |, tudo funciona perfeitamente. (Pensei que talvez pudesse corrigir isso com um before_validation no lado do Rails, mas não funcionou.)

Então, imagino que precise de alguma mágica no lado do Ember para converter o array em uma string antes de enviá-lo de volta?

Eu também usei tag-chooser sem parâmetros e ele buscou todas as tags disponíveis.

Além disso, acho que descobri o motivo pelo qual elas não estão sendo salvas (ou nem mesmo chegando) :wink: no lado do Rails ao usar o tag-chooser. Quando você usa input type list e adiciona um campo value, isso automaticamente se torna parte do formulário.

Mas o markup gerado pelo tag-chooser é um div. É por isso que ele não é incluído na submissão do formulário.

Estou tentando montar uma solução alternativa para isso. Enviarei um PR assim que conseguir fazê-lo funcionar.

Falei com @j.jaffeux ontem e ele está trabalhando para fazer uma alteração.

É exatamente nisso que estou trabalhando.

Isso é ótimo. Como iniciante, estou tentando aprender cada vez mais e isso ajuda muito :slight_smile:

Olá @pfaffman.

Consegui montar uma correção. Não consegui fazer isso do lado do Ember, pois o tag-chooser parecia muito bom para ser descartado, mas consegui fazer do lado do Rails.

Escrevi uma função simples no CategoriesController e a chamei de :before_action. Nessa função, converti o array default_tag em uma string delimitada por |.

Em segundo lugar, mudei before_update para before_commit, pois os custom_fields parecem ser definidos nesse ponto da execução.

Hmm. Achei que já tivesse tentado isso, mas vou dar uma olhada quando chegar ao escritório. Obrigado!

Aha! É isso que eu não sei fazer. Você coloca isso no plugin.rb?

Sim. Isso funcionou para mim.

class ::ApplicationController
    def convert_default_tag
      return unless :topic_default_tag_enabled
      puts 'request'
     # Basta verificar se o campo existe para evitar erros
      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

Acho que é possível ter o método default_tag no próprio controlador, mas não consegui fazê-lo funcionar dessa maneira. Como o ApplicationController é a classe da qual todo controlador do Discourse herda, o método é carregado no momento da extensão da classe a partir do ApplicationController, o que resolve o problema.

@merefield
É possível definir um método chamado :before_action no próprio controlador?

Você deve colocar três crases antes e depois do bloco de código.

```
 O código vai aqui
  ```

Mal posso esperar para experimentar amanhã! Muito obrigado.

Obrigado. Achei que fosse usar apenas crase, mas fiquei travado. Então usei as tags HTML antigas <pre></pre> para fazer funcionar.

Sim, acho que sim

Isso é uma grande ajuda. Agora eu tenho isso:

  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
      # Basta verificar se o campo existe para evitar erros
      request.params["custom_fields"]["default_tag"] = request.params["custom_fields"]["default_tag"].join('|')
      p request.params["custom_fields"]["default_tag"]
    end

  end

E agora as tags selecionadas são convertidas em uma string antes que o Rails tente atualizar o registro, e funciona conforme o esperado.

AGORA o problema é que preciso descobrir onde converter a string no site Rails de volta para o array que precisamos no lado do Javascript/Ember. @j.jaffeux, não me lembro (ou, mais provavelmente, não entendi) se o problema que você estava tentando resolver era reescrever esse valor no lado javascript-to-rails (resolvido!) ou no lado rails-to-Javascript (ainda confuso).

O que funcionou para mim foi alterar o :before_update para :before_commit no seu código ao atribuir tags ao tópico.

Em segundo lugar, quando você abre a página de edição da categoria, o campo de configuração padrão de tags exigirá um array em seu parâmetro de tags, a fim de exibir as tags selecionadas.