Comment ajouter des champs personnalisés aux modèles

J’ai mis à jour le guide des champs personnalisés de sujet pour Discourse 3.4.0. Je mettrai à jour le guide des catégories la semaine prochaine.

4 « J'aime »

Salut @angus, merci pour le plugin category-custom-fields !

Cependant, les valeurs ne sont pas enregistrées lorsque l’on clique sur Enregistrer la catégorie :

  • La case à cocher de votre exemple non modifié revient immédiatement à non cochée.
  • Le champ personnalisé n’est pas enregistré dans la base de données (je l’ai surveillé).

Je n’obtiens aucune erreur.

Pourriez-vous m’aider à résoudre ce problème ? Je ne trouve aucune cause.

Existe-t-il un moyen de s’assurer côté serveur que les champs personnalisés sont obligatoires ?

Dans un plugin, vous utiliserez généralement le modèle ModelCustomField pour ajouter vos propres données.

Pouvez-vous m’en dire plus sur ce que vous essayez de faire
bsp?

J’ai ajouté les champs personnalisés et je suis capable de les enregistrer dans la base de données dans une table personnalisée. Cependant, je souhaite rendre ces champs personnalisés obligatoires à la fois côté client et côté serveur. Côté client, c’est encore relativement facile. Côté serveur, existe-t-il une manière standard de valider que tous les champs personnalisés sont remplis et de n’autoriser la création du sujet que si c’est le cas ? Actuellement, même si les champs personnalisés sont vides, le sujet est créé sans eux.

Ah. C’est facile, mais je ne suis pas assez bon en rails pour vous dire comment. Mais vous aurez votre code derrière un rappel (Active Record Callbacks — Ruby on Rails Guides) qui est appelé avant la création et il échouera si vos champs ne sont pas là.

Bonjour à tous,

J’ai configuré un plugin basé sur Topic Custom Fields et tout fonctionnait parfaitement jusqu’à ce que je mette à jour Discourse vers la version 3.6.0.beta1-dev.

  • Liste des sujets => OK, les colonnes s’affichent correctement dans la liste
  • Titre du sujet => OK, les colonnes s’affichent correctement sous le titre du sujet
  • Éditeur de sujet => KO, les champs n’apparaissent pas et je ne peux ni rédiger ni valider le message.

Voici le message d’erreur rencontré :

index.js:104 DEBUG: -------------------------------
index.js:104 DEBUG: Ember : 6.6.0
index.js:104 DEBUG: -------------------------------
app.js:271 ℹ️ Discourse v3.6.0.beta1-dev — https://github.com/discourse/discourse/commits/1d5b82ed51 — Ember v6.6.0
dev-tools.js:47 Chargement des outils de développement Discourse...
contentCommunicatorMain.js:1 -- pf - démarrage de la détection du script
dev-tools.js:55 Outils de développement Discourse chargés. Exécutez `disableDevTools()` dans la console pour les désactiver.
index.js:104 DEBUG: Pour un débogage plus avancé, installez l'inspecteur Ember depuis https://chrome.google.com/webstore/detail/ember-inspector/bmdblncegkenkacieihfhpjfppoconhi
index.js:4148 

Une erreur s'est produite :

- Lors du rendu :
  {{outlet}} pour -top-level
    -top-level
      {{outlet}} pour application
        application
          (composant inconnu uniquement basé sur un modèle)
            DiscourseRoot
              ComposerContainer
                ComposerBody
                  ComposerEditor
                    DEditor
                      PluginOutletComponent
                        TopicVersionComposer
                          topic-custom-field-input
                            Input
execute @ index.js:4148
index.js:3391 

Une erreur s'est produite :
execute @ index.js:3391
index.js:85 Erreur non capturée (dans la promesse) : Tentative de résolution d'un helper dans un modèle en mode strict, mais cette valeur n'était pas dans le scope : action
    at lookupBuiltInHelper (index.js:85:30)
    at index.js:253:60
    at encodeOp (index.js:266:8)
    at pushOp (index.js:1210:5)
    at index.js:636:33
    at Compilers.compile (index.js:448:14)
    at expr (index.js:461:43)
    at CompilePositional (index.js:614:47)
    at SimpleArgs (index.js:595:15)
    at index.js:1064:12
    at index.js:214:11
    at encodeOp (index.js:240:7)
    at pushOp (index.js:1210:5)
    at index.js:1063:35
    at Compilers.compile (index.js:448:14)
    at compileStatements (index.js:1212:49)
    at index.js:1191:18
    at CompilableTemplateImpl.compile (index.js:1193:6)
    at VM.compile (index.js:3771:31)
    at Object.evaluate (index.js:506:25)
    at Object.evaluate (index.js:103:106)
    at LowLevelVM.evaluateSyscall (index.js:2873:20)
    at LowLevelVM.evaluateInner (index.js:2852:64)
    at LowLevelVM.evaluateOuter (index.js:2849:10)
    at VM.next (index.js:4167:45)
    at VM._execute (index.js:4157:21)
    at VM.execute (index.js:4137:26)
    at TryOpcode.handleException (index.js:3450:19)
    at UpdatingVMFrame.handleException (index.js:3592:52)
    at UpdatingVM.throw (index.js:3414:16)
    at Assert.evaluate (index.js:565:42)
    at UpdatingVM._execute (index.js:3401:34)
    at index.js:3384:51
    at push.../../../../../../../node_modules/.pnpm/ember-source@6.6.0_patch_hash=tyhbf7f4uxnr3gt4x2tdcudbva_@glimmer+component@2.0.0_rsvp@4.8.5/node_modules/ember-source/dist/packages/@glimmer/validator/index.js.debug.runInTrackingTransaction (index.js:44:19)
    at UpdatingVM.execute (index.js:3384:15)
    at RenderResultImpl.rerender (index.js:3610:8)
    at index-BCp6wOJU.js:4639:55
    at RootState.render (index-BCp6wOJU.js:4600:9)
    at index-BCp6wOJU.js:4934:16
    at inTransaction (index.js:2414:7)
    at Renderer._renderRoots (index-BCp6wOJU.js:4914:20)
    at Renderer._renderRootsTransaction (index-BCp6wOJU.js:4962:12)
    at Renderer._revalidate (index-BCp6wOJU.js:4995:10)
    at invoke (index.js:262:14)
    at Queue.flush (index.js:180:11)
    at DeferredActionQueues.flush (index.js:334:19)
    at Backburner._end (index.js:762:32)
    at Backburner._boundAutorunEnd (index.js:499:12)
index-BCp6wOJU.js:4608 Tentative de rerendu, mais l'application Ember a rencontré une erreur irrécupérable pendant le rendu. Vous devez recharger l'application après avoir corrigé la cause de l'erreur.
fn @ index-BCp6wOJU.js:4608
index-BCp6wOJU.js:4608 Tentative de rerendu, mais l'application Ember a rencontré une erreur irrécupérable pendant le rendu. Vous devez recharger l'application après avoir corrigé la cause de l'erreur.
fn @ index-BCp6wOJU.js:4608
index-BCp6wOJU.js:4608 Tentative de rerendu, mais l'application Ember a rencontré une erreur irrécupérable pendant le rendu. Vous devez recharger l'application après avoir corrigé la cause de l'erreur.
fn @ index-BCp6wOJU.js:4608
index-BCp6wOJU.js:4608 Tentative de rerendu, mais l'application Ember a rencontré une erreur irrécupérable pendant le rendu. Vous devez recharger l'application après avoir corrigé la cause de l'erreur.
fn @ index-BCp6wOJU.js:4608
index-BCp6wOJU.js:4608 Tentative de rerendu, mais l'application Ember a rencontré une erreur irrécupérable pendant le rendu. Vous devez recharger l'application après avoir corrigé la cause de l'erreur.
fn @ index-BCp6wOJU.js:4608
index-BCp6wOJU.js:4608 Tentative de rerendu, mais l'application Ember a rencontré une erreur irrécupérable pendant le rendu. Vous devez recharger l'application après avoir corrigé la cause de l'erreur.
fn @ index-BCp6wOJU.js:4608
  • Vue d’édition du sujet => KO, les champs n’apparaissent pas et je ne peux pas valider la modification du titre.

Voici le message d’erreur rencontré - très similaire au précédent - :

index.js:4148 

Une erreur s'est produite :

- Lors du rendu :
  {{outlet}} pour -top-level
    -top-level
      {{outlet}} pour application
        application
          (composant inconnu uniquement basé sur un modèle)
            DiscourseRoot
              {{outlet}} pour topic
                topic
                  (composant inconnu uniquement basé sur un modèle)
                    DiscourseTopic
                      TopicTitle
                        PluginOutletComponent
                          TopicVersionEditTopic
                            topic-custom-field-input
                              Input


execute @ index.js:4148
handleException @ index.js:3450
handleException @ index.js:3592
throw @ index.js:3414
evaluate @ index.js:565
_execute @ index.js:3401
(anonymous) @ index.js:3384
push.../../../../../../../node_modules/.pnpm/ember-source@6.6.0_patch_hash=tyhbf7f4uxnr3gt4x2tdcudbva_@glimmer+component@2.0.0_rsvp@4.8.5/node_modules/ember-source/dist/packages/@glimmer/validator/index.js.debug.runInTrackingTransaction @ index.js:44
execute @ index.js:3384
rerender @ index.js:3610
(anonymous) @ index-BCp6wOJU.js:4639
(anonymous) @ index-BCp6wOJU.js:4600
(anonymous) @ index-BCp6wOJU.js:4934
inTransaction @ index.js:2414
_renderRoots @ index-BCp6wOJU.js:4914
_renderRootsTransaction @ index-BCp6wOJU.js:4962
_revalidate @ index-BCp6wOJU.js:4995
invoke @ index.js:262
flush @ index.js:180
flush @ index.js:334
_end @ index.js:762
Backburner._boundAutorunEnd @ index.js:499
Promise.then
iterations @ index.js:18
flush @ index.js:29
_scheduleAutorun @ index.js:928
_end @ index.js:768
Backburner._boundAutorunEnd @ index.js:499
Promise.then
iterations @ index.js:18
flush @ index.js:29
_scheduleAutorun @ index.js:928
_end @ index.js:768
Backburner._boundAutorunEnd @ index.js:499
Promise.then
iterations @ index.js:18
flush @ index.js:29
_scheduleAutorun @ index.js:928
_ensureInstance @ index.js:919
ensureInstance @ index.js:731
scheduleRevalidate @ index-BCp6wOJU.js:3609
dirtyTag @ index.js:229
dirtyTagFor @ index.js:287
markObjectAsDirty @ cache-fCezwMOy.js:49
notifyPropertyChange @ cache-fCezwMOy.js:745
_setProp @ property_set-2JtwI-ab.js:66
set @ property_set-2JtwI-ab.js:42
set @ observable.js:27
editTopic @ topic.js:376
index.js:3391 

Une erreur s'est produite :

execute @ index.js:3391
rerender @ index.js:3610
(anonymous) @ index-BCp6wOJU.js:4639
(anonymous) @ index-BCp6wOJU.js:4600
(anonymous) @ index-BCp6wOJU.js:4934
inTransaction @ index.js:2414
_renderRoots @ index-BCp6wOJU.js:4914
_renderRootsTransaction @ index-BCp6wOJU.js:4962
_revalidate @ index-BCp6wOJU.js:4995
invoke @ index.js:262
flush @ index.js:180
flush @ index.js:334
_end @ index.js:762
Backburner._boundAutorunEnd @ index.js:499
Promise.then
iterations @ index.js:18
flush @ index.js:29
_scheduleAutorun @ index.js:928
_end @ index.js:768
Backburner._boundAutorunEnd @ index.js:499
Promise.then
iterations @ index.js:18
flush @ index.js:29
_scheduleAutorun @ index.js:928
_end @ index.js:768
Backburner._boundAutorunEnd @ index.js:499
Promise.then
iterations @ index.js:18
flush @ index.js:29
_scheduleAutorun @ index.js:928
_ensureInstance @ index.js:919
ensureInstance @ index.js:731
scheduleRevalidate @ index-BCp6wOJU.js:3609
dirtyTag @ index.js:229
dirtyTagFor @ index.js:287
markObjectAsDirty @ cache-fCezwMOy.js:49
notifyPropertyChange @ cache-fCezwMOy.js:745
_setProp @ property_set-2JtwI-ab.js:66
set @ property_set-2JtwI-ab.js:42
set @ observable.js:27
editTopic @ topic.js:376
5:1 Le traitement de l'autofocus a été bloqué car un document contient déjà un élément focalisé.
index.js:85 Erreur non capturée (dans la promesse) : Tentative de résolution d'un helper dans un modèle en mode strict, mais cette valeur n'était pas dans le scope : action
    at lookupBuiltInHelper (index.js:85:30)
    at index.js:253:60
    at encodeOp (index.js:266:8)
    at pushOp (index.js:1210:5)
    at index.js:636:33
    at Compilers.compile (index.js:448:14)
    at expr (index.js:461:43)
    at CompilePositional (index.js:614:47)
    at SimpleArgs (index.js:595:15)
    at index.js:1064:12
    at index.js:214:11
    at encodeOp (index.js:240:7)
    at pushOp (index.js:1210:5)
    at index.js:1063:35
    at Compilers.compile (index.js:448:14)
    at compileStatements (index.js:1212:49)
    at index.js:1191:18
    at CompilableTemplateImpl.compile (index.js:1193:6)
    at VM.compile (index.js:3771:31)
    at Object.evaluate (index.js:506:25)
    at Object.evaluate (index.js:103:106)
    at LowLevelVM.evaluateSyscall (index.js:2873:20)
    at LowLevelVM.evaluateInner (index.js:2852:64)
    at LowLevelVM.evaluateOuter (index.js:2849:10)
    at VM.next (index.js:4167:45)
    at VM._execute (index.js:4157:21)
    at VM.execute (index.js:4137:26)
    at TryOpcode.handleException (index.js:3450:19)
    at UpdatingVMFrame.handleException (index.js:3592:52)
    at UpdatingVM.throw (index.js:3414:16)
    at Assert.evaluate (index.js:565:42)
    at UpdatingVM._execute (index.js:3401:34)
    at index.js:3384:51
    at push.../../../../../../../node_modules/.pnpm/ember-source@6.6.0_patch_hash=tyhbf7f4uxnr3gt4x2tdcudbva_@glimmer+component@2.0.0_rsvp@4.8.5/node_modules/ember-source/dist/packages/@glimmer/validator/index.js.debug.runInTrackingTransaction (index.js:44:19)
    at UpdatingVM.execute (index.js:3384:15)
    at RenderResultImpl.rerender (index.js:3610:8)
    at index-BCp6wOJU.js:4639:55
    at RootState.render (index-BCp6wOJU.js:4600:9)
    at index-BCp6wOJU.js:4934:16
    at inTransaction (index.js:2414:7)
    at Renderer._renderRoots (index-BCp6wOJU.js:4914:20)
    at Renderer._renderRootsTransaction (index-BCp6wOJU.js:4962:12)
    at Renderer._revalidate (index-BCp6wOJU.js:4995:10)
    at invoke (index.js:262:14)
    at Queue.flush (index.js:180:11)
    at DeferredActionQueues.flush (index.js:334:19)
    at Backburner._end (index.js:762:32)
    at Backburner._boundAutorunEnd (index.js:499:12)
lookupBuiltInHelper @ index.js:85
(anonymous) @ index.js:253
encodeOp @ index.js:266
pushOp @ index.js:1210
(anonymous) @ index.js:636
compile @ index.js:448
expr @ index.js:461
CompilePositional @ index.js:614
SimpleArgs @ index.js:595
(anonymous) @ index.js:1064
(anonymous) @ index.js:214
encodeOp @ index.js:240
pushOp @ index.js:1210
(anonymous) @ index.js:1063
compile @ index.js:448
compileStatements @ index.js:1212
(anonymous) @ index.js:1191
compile @ index.js:1193
compile @ index.js:3771
(anonymous) @ index.js:506
evaluate @ index.js:103
evaluateSyscall @ index.js:2873
evaluateInner @ index.js:2852
evaluateOuter @ index.js:2849
next @ index.js:4167
_execute @ index.js:4157
execute @ index.js:4137
handleException @ index.js:3450
handleException @ index.js:3592
throw @ index.js:3414
evaluate @ index.js:565
_execute @ index.js:3401
(anonymous) @ index.js:3384
push.../../../../../../../node_modules/.pnpm/ember-source@6.6.0_patch_hash=tyhbf7f4uxnr3gt4x2tdcudbva_@glimmer+component@2.0.0_rsvp@4.8.5/node_modules/ember-source/dist/packages/@glimmer/validator/index.js.debug.runInTrackingTransaction @ index.js:44
execute @ index.js:3384
rerender @ index.js:3610
(anonymous) @ index-BCp6wOJU.js:4639
(anonymous) @ index-BCp6wOJU.js:4600
(anonymous) @ index-BCp6wOJU.js:4934
inTransaction @ index.js:2414
_renderRoots @ index-BCp6wOJU.js:4914
_renderRootsTransaction @ index-BCp6wOJU.js:4962
_revalidate @ index-BCp6wOJU.js:4995
invoke @ index.js:262
flush @ index.js:180
flush @ index.js:334
_end @ index.js:762
Backburner._boundAutorunEnd @ index.js:499
Promise.then
iterations @ index.js:18
flush @ index.js:29
_scheduleAutorun @ index.js:928
_end @ index.js:768
Backburner._boundAutorunEnd @ index.js:499
Promise.then
iterations @ index.js:18
flush @ index.js:29
_scheduleAutorun @ index.js:928
_end @ index.js:768
Backburner._boundAutorunEnd @ index.js:499
Promise.then
iterations @ index.js:18
flush @ index.js:29
_scheduleAutorun @ index.js:928
_ensureInstance @ index.js:919
ensureInstance @ index.js:731
scheduleRevalidate @ index-BCp6wOJU.js:3609
dirtyTag @ index.js:229
dirtyTagFor @ index.js:287
markObjectAsDirty @ cache-fCezwMOy.js:49
notifyPropertyChange @ cache-fCezwMOy.js:745
_setProp @ property_set-2JtwI-ab.js:66
set @ property_set-2JtwI-ab.js:42
set @ observable.js:27
editTopic @ topic.js:376

Quelqu’un d’autre rencontre-t-il le même problème ?

1 « J'aime »

Salut @cdervout ,

Problème
Le composant d’entrée de champ personnalisé de sujet utilisait la syntaxe héritée :

{{on "change" (action @onChangeField value="target.value")}}
  • Cette syntaxe (action …) n’est pas prise en charge dans les composants Glimmer modernes.
  • Par conséquent, le champ ne s’affichait pas du tout dans le compositeur.

Correction
Remplacement de l’ancienne syntaxe par une action Glimmer moderne :

{{on "input" this.handleInputChange}}

Et ajout de la méthode JS correspondante :

@action
handleInputChange(event) {
  this.args.onChangeField(event.target.value);
}
  • Cela garantit que le champ s’affiche correctement dans le compositeur.

Code du composant refactorisé

import Component from "@glimmer/component";
import { Input, Textarea } from "@ember/component";
import { on } from "@ember/modifier";
import { readOnly } from "@ember/object/computed";
import { service } from "@ember/service";
import { eq } from "truth-helpers";
import i18n from "discourse-common/helpers/i18n";
import { action } from "@ember/object";

export default class TopicCustomFieldInput extends Component {
  @service siteSettings;
  @readOnly("siteSettings.topic_custom_field_name") fieldName;
  @readOnly("siteSettings.topic_custom_field_type") fieldType;

  @action
  handleInputChange(event) {
    this.args.onChangeField(event.target.value);
  }

  <template>
    {{#if (eq this.fieldType "boolean")}}
      <Input
        @type="checkbox"
        @checked={{@fieldValue}}
        {{on "input" this.handleInputChange}}
      />
      <span>{{this.fieldName}}</span>
    {{/if}}

    {{#if (eq this.fieldType "integer")}}
      <Input
        @type="number"
        @value={{@fieldValue}}
        placeholder={{i18n
          "topic_custom_field.placeholder"
          field=this.fieldName
        }}
        class="topic-custom-field-input small"
        {{on "input" this.handleInputChange}}
      />
    {{/if}}

    {{#if (eq this.fieldType "string")}}
      <Input
        @type="text"
        @value={{@fieldValue}}
        placeholder={{i18n
          "topic_custom_field.placeholder"
          field=this.fieldName
        }}
        class="topic-custom-field-input large"
        {{on "input" this.handleInputChange}}
      />
    {{/if}}

    {{#if (eq this.fieldType "json")}}
      <Textarea
        @value={{@fieldValue}}
        {{on "input" this.handleInputChange}}
        placeholder={{i18n
          "topic_custom_field.placeholder"
          field=this.fieldName
        }}
        class="topic-custom-field-textarea"
      />
    {{/if}}
  </template>
}

EDIT : J’ai ouvert une PR pour cela

4 « J'aime »

Merci, tout fonctionne bien !

J’ai adapté le code dans le cas où le champ est une case à cocher. Pour récupérer la valeur, j’ai dû faire event.target.checked au lieu de event.target.value

2 « J'aime »