Verwendung von tag-chooser in einem Plugin

Ich arbeite an einem Plugin, das neuen Themen in einer Kategorie automatisch einen Standard-Tag zuweist.

Der folgende Code „funktioniert“, wenn ich Tag-Namen durch ein „|“ trenne, also funktioniert „tag1|tag2“. (Ich kann es kaum glauben! Aber ich schweife ab.)

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

Was ich jetzt möchte, ist ein echter Tag-Auswähler statt eines nicht validierten Strings. Es scheint, als ob folgendes funktionieren sollte:

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

Aber das funktioniert nicht. Das Grundproblem ist, dass ich fast keine Ahnung habe, wie die Magie dieser Handlebars-Templates funktioniert. Ich vermute zwar, dass der erste Abschnitt funktioniert, weil er magisch den Feldnamen aus default-tag in <section class='field default-tag'> bezieht, aber das war eher Glück. :slight_smile:

Wenn ich den tag-chooser verwende, werden die Tags als Array an Rails übergeben, das sie verwirft, bevor ich sie in einen durch | getrennten String umwandeln kann, um sie in CategoryCustomField einzufügen. Mit {{input type=list...}} kann ich den durch | getrennten String selbst eingeben, und das funktioniert einwandfrei. Brauche ich irgendeine Art von Ember-Magie, um das Array auf der Ember-Seite in einen String umzuwandeln?

Vielleicht muss ich etwas wie hier tun: What's the best approach to access category specific settings??

EDIT: Um Tags hinzuzufügen, bevor der Webhook aufgerufen wird, verwende after_create statt DiscourseEvent.on(:post_created). Rails ergibt jetzt größtenteils Sinn für mich, aber Ember, JavaScript und CSS weniger.

Du kannst prüfen, ob die von dir verwendeten Variablen die benötigten Werte enthalten, indem du {{log variable_name}} verwendest und die Konsole überprüfst. Wenn die korrekten Werte nicht an die Komponente übergeben werden, wird sie die richtige Ausgabe nicht anzeigen.

Du kannst sie verifizieren, indem du dasselbe im Core-Code durchführst, um zu bestätigen, ob die Werte korrekt übergeben werden.

Entschuldige bitte, falls es dir naiv vorkommt.

Nein! Ich bin nur ein Höhlenmensch.

Das ist sehr hilfreich, denn ich wusste nicht, wie man das macht. Wie sich herausstellt, habe ich doch Daten in diesen Feldern. UND die Tag-Namensdaten befinden sich in category.custom_fields.default_tag und werden an den mini-tag-chooser übergeben. category.id enthält zwar die ID einer Kategorie, aber der Auswahldialog bietet keine Tags an.

Ich kann nicht sagen, ob die Daten in das Feld übernommen würden, wenn es so wäre.

EDIT: OOOOH! Aber die Verwendung von tag-chooser anstelle von mini-tag-chooser funktioniert wie erwartet (ich werde den Code oben entsprechend anpassen). Das einzige Problem ist, dass die Daten beim Klicken auf Speichern nicht gespeichert werden.

Diese Zeile macht mich stutzig. Ich vermute, dass tags ein Array erwartet, und wie es aussieht, übergibst du einen einzelnen Wert (das müsstest du bestätigen). Falls tatsächlich ein einzelner Wert übergeben wird, mach einfach ein Array daraus und versuch es erneut.

Nun, auf der Rails-Seite ist es ein durch | getrennter String, und ich sehe nach dem Absenden, dass die von mir eingegebenen Daten übermittelt werden, z. B. "custom_fields"=>{"de fault_tag"=>["error", "high-availability", "best-practices"]}, und "custom_fields"=>{"de fault_tag"=>["health-checks"]},

Hier ist das Ganze:

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

Es sieht also so aus, als würde auf der mysteriösen Seite das Richtige passieren, aber Rails aktualisiert das benutzerdefinierte Feld der Kategorie nicht. Ich werde wieder vergleichen, was ich habe, mit einem anderen Plugin, das sich mit CategoryCustomFields befasst.

Vielen Dank, @fzngagan!

EDIT: Hmm. Ich denke, das Problem ist:

Unpermitted parameter: :default_tag

Du wirst die Antwort darauf wirklich genießen. Trotzdem, falls du Hilfe brauchst, würde ich das sehr gerne tun. :slight_smile:

Ja, das ist er. Rails weiß noch nicht, was mit diesem neuen Feld zu tun ist. Du musst das neue Feld mit add_to_serializer hinzufügen. Beispiele hierfür findest du in Plugins, die benutzerdefinierte Felder hinzufügen.

Nun, plugin.rb enthält:

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

Du kannst es unter GitHub - pfaffman/discourse-topic-default-tag: Allow topics to include default tags · GitHub einsehen, falls du möchtest.

Ich bin verwirrt, denn

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

funktioniert, aber

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

nicht.

EDIT: Es scheint, dass beim Verwenden von tag-chooser mein benutzerdefiniertes Feld als Array an Rails gesendet und dort verworfen wird, bevor es verarbeitet wird. Bei Verwendung eines Text-Felds, in dem ich einen mit | getrennten String erstelle, funktioniert es jedoch einwandfrei. (Ich dachte, ich könnte es mit einem before_validation auf der Rails-Seite beheben, aber das brachte nichts.)

Also muss ich wohl auf der Ember-Seite etwas Magisches anwenden, um das Array vor dem Zurücksenden in einen String umzuwandeln?

Ich habe auch tag-chooser ohne Parameter verwendet, und er hat alle verfügbaren Tags abgerufen.

Außerdem habe ich herausgefunden, warum diese beim Einsatz von tag-chooser auf der Rails-Seite nicht gespeichert werden (oder gar nicht erst ankommen) :wink: Wenn du input type=list verwendest und ein value-Feld hinzufügst, wird dieses automatisch Teil des Formulars.

Das von tag-chooser generierte Markup ist jedoch ein div. Deshalb wird es nicht an die Formularübermittlung angehängt.

Ich versuche gerade, eine Workaround-Lösung dafür zu finden. Sobald es funktioniert, werde ich einen PR einreichen.

Ich habe gestern mit @j.jaffeux gesprochen, und er arbeitet an einer Änderung.

Das ist genau das, woran ich arbeite.

Das ist großartig. Als Neuling versuche ich, immer mehr zu lernen, und das hilft mir sehr :slight_smile:

Hallo @pfaffman.

Ich habe es geschafft, eine Lösung zu finden. Es war mir nicht möglich, dies auf Ember-Seite zu lösen, da tag-chooser zu cool war, um darauf zu verzichten, aber ich habe es auf Rails-Seite geschafft.

Ich habe eine einfache Funktion im CategoriesController geschrieben und sie als :before_action aufgerufen. Dabei habe ich das default_tag-Array in einen durch | getrennten String umgewandelt.

Zweitens habe ich before_update in before_commit geändert, da die custom_fields zu diesem Zeitpunkt der Ausführung gesetzt zu sein scheinen.

Hmm. Ich dachte, ich hätte das schon ausprobiert, aber ich werde mir das im Büro ansehen. Danke!

Aha! Genau das weiß ich nicht, wie man macht. Packst du das in plugin.rb?

Ja, das hat bei mir funktioniert.

class ::ApplicationController
    def convert_default_tag
      return unless :topic_default_tag_enabled
      puts 'request'
     # Einfach prüfen, ob das Feld existiert, um Fehler zu vermeiden
      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

Ich denke, es wäre möglich, die Methode default_tag direkt im Controller zu definieren, aber ich habe es auf diese Weise nicht zum Laufen bekommen. Da jede Discourse-Controller-Klasse von ApplicationController erbt, wird die Methode beim Erweitern der Klasse von ApplicationController geladen, was den gewünschten Effekt erzielt.

@merefield
Ist es möglich, eine Methode zu definieren, die als :before_action im Controller selbst aufgerufen wird?

Du solltest drei Backticks vor und nach dem Code-Block setzen.

```
 Code goes here
  ```

Ich kann es kaum erwarten, es morgen auszuprobieren! Vielen Dank.

Danke. Ich dachte, es sei ein einzelnes Backtick, aber ich steckte fest. Also habe ich die einfachen alten HTML-Tags

 verwendet, damit es funktioniert.

Ja, ich glaube schon

Das ist eine große Hilfe. Jetzt habe ich Folgendes:

  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
      # Prüfen, ob das Feld existiert, um Fehler zu vermeiden
      request.params["custom_fields"]["default_tag"] = request.params["custom_fields"]["default_tag"].join('|')
      p request.params["custom_fields"]["default_tag"]
    end

  end

Jetzt werden die ausgewählten Tags in einen String umgewandelt, bevor Rails versucht, den Datensatz zu aktualisieren, und es funktioniert wie erwartet.

JETZT ist das Problem, dass ich herausfinden muss, wo der String auf der Rails-Seite in das Array umgewandelt werden muss, das wir auf der JavaScript/Ember-Seite benötigen. @j.jaffeux, ich kann mich nicht erinnern (oder habe es wahrscheinlich nicht verstanden), ob das Problem, das du zu lösen versuchtest, das Überschreiben dieses Werts auf der JavaScript-zu-Rails-Seite war (gelöst!) oder auf der Rails-zu-JavaScript-Seite (immer noch verwirrt).

Was bei mir funktioniert hat: Ich habe in deinem Code beim Zuweisen von Tags zum Thema :before_update zu :before_commit geändert.

Zweitens: Wenn du die Seite „Kategorie bearbeiten“ öffnest, erwartet das Standard-Feld für die Tag-Einstellung in seinen Tag-Parametern ein Array, um die ausgewählten Tags anzuzeigen.