Как добавить пользовательские поля к моделям

Я обновил руководство по пользовательскому полю темы для Discourse версии 3.4.0. На следующей неделе я обновлю руководство по категориям.

4 лайка

Привет @angus, спасибо за плагин category-custom-fields!

Однако значения не сохраняются при нажатии на Save Category:

  • Флажок из вашего неизмененного примера сразу же возвращается в состояние не отмечено.
  • Пользовательское поле не сохраняется в базе данных (я это отслеживал).

Ошибок я не получаю.

Не могли бы вы помочь мне разобраться в этом? Я не могу найти никаких причин.

Есть ли способ гарантировать обязательность пользовательских полей на стороне сервера?

В плагине вы обычно используете модель ModelCustomField для добавления собственных данных.

Можете рассказать подробнее о том, что вы пытаетесь сделать?

Я добавил пользовательские поля и успешно сохраняю их в базе данных в специальной таблице. Однако я хочу сделать эти поля обязательными как на стороне клиента, так и на стороне сервера. На стороне клиента это относительно просто. На стороне сервера есть ли стандартный способ проверить, что все пользовательские поля заполнены, и только после этого разрешить создание темы? В данный момент, даже если пользовательские поля пусты, тема всё равно создаётся без них.

Ах. Это просто, но я недостаточно хорошо знаю Rails, чтобы подсказать, как именно. Однако ваш код будет находиться внутри обратного вызова (Active Record Callbacks — Ruby on Rails Guides), который срабатывает перед созданием записи, и он завершится ошибкой, если необходимые поля отсутствуют.

Всем привет,

Я настроил плагин на основе Topic Custom Fields, и всё работало отлично, пока я не обновил Discourse до версии 3.6.0.beta1-dev.

  • Список тем => OK, столбцы корректно отображаются в списке
  • Заголовок темы => OK, столбцы корректно отображаются под заголовком темы
  • Редактор создания темы (composer) => KO, поля не отображаются, и я не могу создать и отправить сообщение.

Вот сообщение об ошибке, которое я получил:

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 Загрузка инструментов разработки Discourse...
contentCommunicatorMain.js:1 -- pf - запуск обнаружения скриптов
dev-tools.js:55 Инструменты разработки Discourse загружены. Выполните `disableDevTools()` в консоли, чтобы отключить их.
index.js:104 DEBUG: Для более продвинутой отладки установите Ember Inspector из https://chrome.google.com/webstore/detail/ember-inspector/bmdblncegkenkacieihfhpjfppoconhi
index.js:4148 

Произошла ошибка:

- Во время рендеринга:
  {{outlet}} для -top-level
    -top-level
      {{outlet}} для application
        application
          (неизвестный компонент, использующий только шаблон)
            DiscourseRoot
              ComposerContainer
                ComposerBody
                  ComposerEditor
                    DEditor
                      PluginOutletComponent
                        TopicVersionComposer
                          topic-custom-field-input
                            Input
execute @ index.js:4148
index.js:3391 

Произошла ошибка:
execute @ index.js:3391
index.js:85 Uncaught (in promise) Error: Попытка разрешения помощника (helper) в шаблоне строгого режима, но это значение не было в области видимости: 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 Попытка перерисовки, но в приложении Ember произошла неисправимая ошибка во время рендеринга. Вам следует перезагрузить приложение после устранения причины ошибки.
fn @ index-BCp6wOJU.js:4608
index-BCp6wOJU.js:4608 Попытка перерисовки, но в приложении Ember произошла неисправимая ошибка во время рендеринга. Вам следует перезагрузить приложение после устранения причины ошибки.
fn @ index-BCp6wOJU.js:4608
index-BCp6wOJU.js:4608 Попытка перерисовки, но в приложении Ember произошла неисправимая ошибка во время рендеринга. Вам следует перезагрузить приложение после устранения причины ошибки.
fn @ index-BCp6wOJU.js:4608
index-BCp6wOJU.js:4608 Попытка перерисовки, но в приложении Ember произошла неисправимая ошибка во время рендеринга. Вам следует перезагрузить приложение после устранения причины ошибки.
fn @ index-BCp6wOJU.js:4608
index-BCp6wOJU.js:4608 Попытка перерисовки, но в приложении Ember произошла неисправимая ошибка во время рендеринга. Вам следует перезагрузить приложение после устранения причины ошибки.
fn @ index-BCp6wOJU.js:4608
index-BCp6wOJU.js:4608 Попытка перерисовки, но в приложении Ember произошла неисправимая ошибка во время рендеринга. Вам следует перезагрузить приложение после устранения причины ошибки.
fn @ index-BCp6wOJU.js:4608
  • Редактирование темы => KO, поля не отображаются, и я не могу подтвердить изменение заголовка.

Вот сообщение об ошибке — оно практически такое же, как и предыдущее:

index.js:4148 

Произошла ошибка:

- Во время рендеринга:
  {{outlet}} для -top-level
    -top-level
      {{outlet}} для application
        application
          (неизвестный компонент, использующий только шаблон)
            DiscourseRoot
              {{outlet}} для topic
                topic
                  (неизвестный компонент, использующий только шаблон)
                    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 

Произошла ошибка:

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 Обработка автофокуса была заблокирована, так как в документе уже есть сфокусированный элемент.
index.js:85 Uncaught (in promise) Error: Попытка разрешения помощника (helper) в шаблоне строгого режима, но это значение не было в области видимости: 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

У кого-нибудь из вас возникает та же проблема?

1 лайк

Привет @cdervout,

Проблема
Компонент поля ввода пользовательского поля темы использовал устаревший синтаксис:

{{on "change" (action @onChangeField value="target.value")}}
  • Синтаксис (action …) не поддерживается в современных компонентах Glimmer.
  • В результате поле вообще не отображалось в редакторе.

Исправление
Заменен старый синтаксис на современное действие Glimmer:

{{on "input" this.handleInputChange}}

И добавлен соответствующий метод JS:

@action
handleInputChange(event) {
  this.args.onChangeField(event.target.value);
}
  • Это обеспечивает правильное отображение поля в редакторе.

Рефакторинг кода компонента

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

РЕДАКТИРОВАНИЕ: Я создал PR по этому поводу

4 лайка

Спасибо, всё работает отлично!

Я адаптировал код для случая, когда поле является чекбоксом. Чтобы получить значение, мне пришлось использовать event.target.checked вместо event.target.value.

2 лайка