Я решил создать плагин. Сам компонент формы корректно рендерится через api.renderInOutlet. Однако данные не сохраняются на бэкенде в пользовательской таблице.
Настройка фронтенда:
Я использую api.renderInOutlet("composer-fields", MyOutletConnectorComponent) для отображения компонента GJS (MyOutletConnectorComponent) при создании новой темы в определенной категории.
Этот MyOutletConnectorComponent затем рендерит мой основной компонент формы GJS (MyMarketFormComponent).
Внутри MyMarketFormComponent ввод пользователя обновляет JavaScript-объект, который затем устанавливается как свойство верхнего уровня в composerModel, предоставленном аргументами выхода. Например:
// Действие внутри MyMarketFormComponent
const currentData = this.args.composerModel.get("market_listing_data") || {};
const updatedData = { ...currentData, [fieldKey]: newValue };
this.args.composerModel.set("market_listing_data", updatedData);
В инициализаторе моего плагина (tecenc-market-composer.js) я использую api.serializeOnCreate("market_listing_data", "market_listing_data"), чтобы попытаться передать эти данные на бэкенд. Также я использую api.serializeToDraft("market_listing_data", "market_listing_data").
Проблема на бэкенде:
В моем файле plugin.rb, внутри обработчика DiscourseEvent.on(:topic_created) do |topic, opts, user| ... end:
Я проверяю, находится ли тема в правильной категории (это работает).
Затем я пытаюсь получить доступ к сериализованным данным, используя market_data = opts[:market_listing_data] (или opts["market_listing_data"]).
Проблема в том, что opts[:market_listing_data] постоянно равен nil.
Логирование opts.keys подтверждает, что мой ключ market_listing_data отсутствует на верхнем уровне хэша opts. Сам хэш opts содержит стандартные ключи, такие как :raw, :title, :category, :archetype и т.д.
Фрагмент моего файла plugin.rb для события:
# plugin.rb
# ...
module ::TecencMarket
SERIALIZED_DATA_KEY = "market_listing_data".freeze
end
# ...
after_initialize do
# ...
DiscourseEvent.on(:topic_created) do |topic, opts, user|
# ... (логика проверки категории) ...
# Здесь market_data равен nil
market_data = opts[TecencMarket::SERIALIZED_DATA_KEY.to_sym]
Rails.logger.info "[MyPlugin] Ключи Opts: #{opts.keys.inspect}"
Rails.logger.info "[MyPlugin] market_data из opts: #{market_data.inspect}"
if market_data.present? && market_data.is_a?(Hash)
# ... обработка и сохранение данных в пользовательскую таблицу ...
else
Rails.logger.warn "[MyPlugin] Данные о рынке не найдены в opts, как ожидалось."
end
end
# ...
end
Вопросы:
Какой правильный и наиболее надежный способ гарантировать, что JavaScript-объект, установленный как свойство верхнего уровня в composerModel (например, composerModel.set("my_plugin_data_key", { ... });) с использованием компонентов GJS, будет корректно сериализован через api.serializeOnCreate и станет доступным в хэше opts события :topic_created на бэкенде?
Ожидается ли, что api.serializeOnCreate("my_key", "my_key") будет работать для произвольных ключей верхнего уровня, установленных в composerModel из контекста GJS, или сериализация через custom_fields (например, установка composerModel.custom_fields.my_plugin_key = {...} и использование api.serializeOnCreate("custom_fields.my_plugin_key")) является единственным надежным/рекомендуемым подходом для такой передачи данных при создании новых тем?
Существуют ли какие-либо специфические соображения или распространенные ошибки при использовании api.serializeOnCreate с данными, управляемыми компонентами GJS, которые могут привести к тому, что данные не будут включены в хэш opts?
Я подтвердил, что форма на фронтенде корректно собирает данные и устанавливает их в свойство composerModel.market_listing_data. Проблема, по-видимому, заключается исключительно в том, чтобы эти данные были сериализованы и переданы событию на бэкенде.
Любые рекомендации или примеры рекомендуемого паттерна для этого в современном Discourse будут очень кстати!
В продолжение моего предыдущего вопроса о том, что данные не попадают в хеш opts, я изменил стратегию и начал использовать рекомендуемый путь custom_fields для сериализации данных из формы композера моего плагина.
Текущий подход:
Инициализатор на стороне фронтенда:
Я пытаюсь обеспечить, чтобы composerModel.custom_fields и composerModel.custom_fields["tecenc_market_data"] (ключ данных моего плагина) инициализировались как объекты. Моя последняя попытка включает использование api.modifyClass("model:composer", ...) для добавления логики инициализации в init() и clearState():
Далее я использую api.serializeOnCreate('custom_fields.tecenc_market_data'); и api.serializeToDraft('custom_fields.tecenc_market_data');.
Мой компонент формы GJS обновляет composerModel.custom_fields.tecenc_market_data.my_field = value; (путем установки нового объекта custom_fields для обеспечения реактивности).
Обработчик события :topic_created ожидает чтение данных из topic.custom_fields["tecenc_market_data"].
Новая блокирующая ошибка:
Несмотря на эти попытки инициализировать custom_fields в composerModel, я постоянно сталкиваюсь со следующей ошибкой JavaScript при попытке открыть композер для новой темы (нажав кнопку «Создать тему»):
Uncaught (in promise) Error: Property set failed: object in path "custom_fields" could not be found.
Ember 3
open composer.js:1010
open composer.js:1009
_setModel composer.js:1451
open composer.js:1401
openNewTopic composer.js:1410
createTopic list.js:167
clickCreateTopicButton d-navigation.gjs:224
_triggerAction d-button.gjs:138
Ember 11
_triggerAction d-button.gjs:135
click d-button.gjs:93
source chunk.8d6366d70b85d1b69fdc.d41d8cd9.js:94366
Ember 2
source chunk.8d6366d70b85d1b69fdc.d41d8cd9.js:94040
Ember 26 property_set-BapAkp3X.js:79:10
Эта ошибка указывает на то, что this.model.custom_fields (в composerModel) равен undefined или null, когда ядро Discourse в composer.js:1010 (внутри метода open, вызываемого openNewTopic) пытается установить вложенное свойство. Это происходит до того, как форма моего плагина успеет даже отрендериться.
Вопросы:
Учитывая, что базовая модель Composer должна инициализировать custom_fields: {}, почему composerModel.custom_fields все еще может быть неопределенным в composer.js:1010 во время последовательности openNewTopic в этой версии Discourse?
Является ли подход api.modifyClass("model:composer", ...) в инициализаторе правильным/наиболее эффективным способом гарантировать, что custom_fields (и вложенные ключи плагинов внутри него) инициализируются как объекты достаточно рано, чтобы предотвратить эту базовую ошибку? Если нет, какой паттерн рекомендуется?
Возможно ли, что проблема связана с таймингом, когда шаги инициализации базового композера выполняются и ожидают custom_fields до того, как инициализаторы плагинов, использующие api.modifyClass, полностью применятся к прототипу или экземплярам модели Composer?
Любые insights по поводу ошибки «Property set failed» в ядре композера и лучших практик для безопасного взаимодействия плагинов с composerModel.custom_fields во время инициализации были бы крайне полезны.
Я сохраняю данные в пользовательской таблице базы данных.
addToSerializer предназначен для передачи данных с сервера на клиент, верно?
Моя проблема заключается в передаче данных с клиента на сервер, чтобы я мог их сохранить. Поэтому я использую serializeOnCreate. Но проблема в том, что данные не попадают в хэш opts. Таким образом, на данный момент ответ: нет, пользовательские данные не попадают в хэш opts, как ожидалось. Они не поступают в Rails.
Я изучил этот обучающий плагин, но не смог заставить его работать для 6 пользовательских полей.