# 来自 GJS Composer 表单的自定义数据未包含在 \`opts\` 中的 \`:topic\_created\` 事件

**URL:** <https://meta.discourse.org/t/custom-data-from-gjs-composer-form-not-in-opts-for-topic-created-event/366809>\
**Category:** Development\
**Created:** [2025年五月20日 06:17 UTC](https://meta.discourse.org/t/custom-data-from-gjs-composer-form-not-in-opts-for-topic-created-event/366809 "2025-05-20T06:17:38Z")\
**Posts on this page:** 1\
**Showing post:** 1

<div class="post-metadata">

**Author:** ![SubStrider](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/substrider/32/512604_2.png) [@SubStrider](https://meta.discourse.org/u/SubStrider)\
**Post date:** [2025年五月20日 06:17 UTC](https://meta.discourse.org/t/custom-data-from-gjs-composer-form-not-in-opts-for-topic-created-event/366809/1 "2025-05-20T06:17:38Z")

</div>

这是对此的延续 - [Custom topic fields per category or custom topic entry form per category?](https://meta.discourse.org/t/custom-topic-fields-per-category-or-custom-topic-entry-form-per-category/355260)

我决定创建这个插件。表单组件本身通过 `api.renderInOutlet` 正确渲染。但是数据没有在后端保存到自定义表中。

**前端设置：**

1. 我使用 `api.renderInOutlet("composer-fields", MyOutletConnectorComponent)` 在指定类别中创建新主题时渲染 GJS 组件 (`MyOutletConnectorComponent`)。

2. 此 `MyOutletConnectorComponent` 然后渲染我的主 GJS 表单组件 (`MyMarketFormComponenent`)。

3. 在 `MyMarketFormComponenent` 中，用户输入会更新一个 JavaScript 对象，然后该对象被设置为 Outlet 参数提供的 `composerModel` 的顶层属性。例如：

4. 在我的插件初始化程序 (`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` 代码片段用于事件：**

```ruby
# 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 keys: #{opts.keys.inspect}"
    Rails.logger.info "[MyPlugin] market_data from opts: #{market_data.inspect}"

    if market_data.present? && market_data.is_a?(Hash)
      # ... 处理并将数据保存到自定义表 ...
    else
      Rails.logger.warn "[MyPlugin] Market data not found in opts as expected."
    end
  end
  # ...
end

```

**问题：**

1. 确保通过 GJS 组件设置为 `composerModel` 的顶层属性（例如 `composerModel.set("my_plugin_data_key", { ... });`）被 `api.serializeOnCreate` 正确序列化并可在后端 `:topic_created` 事件的 `opts` 哈希中访问的正确且最可靠的方法是什么？
2. `api.serializeOnCreate("my_key", "my_key")` 是否适用于从 GJS 上下文设置在 `composerModel` 上的任意顶层键，还是通过 `custom_fields` 进行序列化（例如，设置 `composerModel.custom_fields.my_plugin_key = {...}` 并使用 `api.serializeOnCreate("custom_fields.my_plugin_key")`）是这种类型的数据传输到新主题的唯一健壮/推荐方法？
3. 在使用由 GJS 组件管理的数据时，使用 `api.serializeOnCreate` 是否有任何特定的注意事项或常见陷阱可能导致数据未包含在 `opts` 哈希中？

我已经确认前端表单正在正确收集数据并将其设置在 `composerModel.market_listing_data` 属性上。问题似乎纯粹在于如何将此数据序列化并传递到后端事件。

任何关于现代 Discourse 中推荐模式的指导或示例都将不胜感激！

谢谢！

---

_[View the full topic](https://meta.discourse.org/t/custom-data-from-gjs-composer-form-not-in-opts-for-topic-created-event/366809)._
