在使用URL查询参数(例如 ...?market_item_statuses=Available)构建具有自定义主题列表过滤器(如按价格、位置)的插件时,URL正确更新,但参数没有显示在服务器端的 topic_query.options 中。
设置:
-
客户端参数注册(tecenc-discovery-params.js):
// tecenc-discovery-params.js
import { apiInitializer } from "discourse/lib/api";
export default apiInitializer("1.37.3", (api) => {
const MARKET_PARAMS_KEYS = [
"market_price_min", "market_price_max", "market_location",
"market_conditions", "market_warranty", "market_item_statuses"
];
MARKET_PARAMS_KEYS.forEach(paramKey => {
api.addDiscoveryQueryParam(paramKey, { replace: true, refreshModel: true });
});
});
-
服务器端白名单尝试(plugin.rb):
# plugin.rb
module ::Tecenc
MARKET_PARAMS_KEYS = [
:market_price_min, :market_price_max, :market_location,
:market_conditions, :market_warranty, :market_item_statuses
].freeze
end
# after_initialize do
if SiteSetting.tecenc_enabled?
if defined?(::TopicQuery.add_custom_param_handler)
::Tecenc::MARKET_PARAMS_KEYS.each do |param_key|
::TopicQuery.add_custom_param_handler(param_key) { |value| value } # 简化示例
end
Rails.logger.info "[Tecenc] 已注册 with add_custom_param_handler."
elsif defined?(::TopicQuery) && ::TopicQuery.methods.include?(:extra_options_whitelist)
current_whitelist = ::TopicQuery.extra_options_whitelist || []
new_whitelist = (current_whitelist + ::Tecenc::MARKET_PARAMS_KEYS).uniq
::TopicQuery.extra_options_whitelist(*new_whitelist)
Rails.logger.info "[Tecenc] 扩展了 extra_options_whitelist."
else
Rails.logger.warn "[Tecenc] 警告: 未找到允许参数白名单的方法。"
end
-
服务器端过滤逻辑(plugin.rb):
# plugin.rb (在 after_initialize / 启用后)
::TopicQuery.add_custom_filter(:"tecenc_filters") do |topics, topic_query|
opts = topic_query.options
Rails.logger.info "[Tecenc_TopicQuery] 选项: #{opts.inspect}" # 关键日志
# market_params_present = ::Tecenc::MARKET_PARAMS_KEYS.any? { |p| opts[p].present? }
# if market_params_present
# # ... 使用 opts[key] 进行过滤逻辑 ...
# end
topics # 或过滤后的话题
end
问题(日志):
-
参数白名单失败:
[Tecenc] PLUGIN_WARN: 找不到适合的方法(add_custom_param_handler 或者 extra_options_whitelist)为 TopicQuery 白名单自定义参数。
-
在 TopicQuery.add_custom_filter 中,opts 缺少我们的自定义参数:
当URL为 ...?market_item_statuses=Available时,日志显示:
[Tecenc_TopicQuery] 选项: {:category=>5, :filter=>"default", :topic_ids=>nil, :category_id=>5}
我们的 market_item_statuses(以及其他自定义参数)不存在。
我们的环境:
问题:
- 在最新的 Discourse 版本中,确保自定义 URL 查询参数到达
topic_query.options 的目前最佳实践是什么?
- 为什么我们尝试使用
add_custom_param_handler 或 extra_options_whitelist 时会出现 “Could not find a suitable method” 的警告,操作失败?
- 是否有其他的参数注册方法可以用于
TopicQuery,我们应该考虑使用?
任何帮助将不胜感激!
刚刚注意到 add_custom_param_handler 甚至不是 TopicQuery 的方法。在较新版本的 discourse 中,是否有其他方法可以为主题构建自定义筛选器?
TopicQuery 单例方法:[:add_custom_filter, :apply_custom_filters, :new_filter, :public_valid_options, :remove_custom_filter, :remove_muted_tags, :results_filter_callbacks, :results_filter_callbacks=, :tracked_filter, :unread_filter, :valid_options, :validate?, :validators, :yaml_tag]
{“progress_report”: “到目前为止的进展:\n\n1. 确认在我的 Discourse 版本中,像 add_custom_param_handler 或 extra_options_whitelist 这样的静态 TopicQuery 白名单方法不可用,因此放弃了这些方法。\n\n2. 对 ListController#build_topic_list_options 进行了补丁,以在调用 TopicQuery.new 之前,将我自定义的 URL 参数(例如 market_item_statuses,market_price_min)注入到 opts 哈希中。\n\n3. 这部分现在工作正常! 当我发出像 /c/market/5/l/latest.json?filter=defaultmarket_item_statuses=Available 这样的请求时,我的服务器日志确认了注入:\n\n \n [TecencMarket_ListControllerExt_BuildOptsV3] 注入到 opts 中:market_item_statuses = Available\n \n 所以,TopicQuery.new(user, opts) 现在接收到的 opts 包含我自定义的参数。\n\n当前遇到的问题: 500 错误 & 过滤器块未执行\n\n虽然参数现在被正确传递到 TopicQuery 的初始化器,但我仍然在请求包含这些自定义市场参数时遇到 500 内部服务器错误。\n\n为排查问题,我简化我的 TopicQuery.add_custom_filter(:"tecenc_market_filters") 块到最基本的形式。\n\nruby\n# plugin.rb - 当前简化的自定义过滤器块\nif ::TopicQuery.respond_to?(:add_custom_filter)\n ::TopicQuery.add_custom_filter(:"tecenc_market_filters") do |topics, topic_query| original_topics_relation = topics \n opts = topic_query.options\n log_prefix_query = "[TecencMarket_SimplifiedFilter_V1.1_Test]" # 我的调试前缀\n\n Rails.logger.info "#{log_prefix_query} 通过 TopicQuery 接收的 Opts:#{opts.inspect}"\n\n if opts[:market_item_statuses].present?\n Rails.logger.info "#{log_prefix_query} 'market_item_statuses' 存在于 opts 中:#{opts[:market_item_statuses]}"\n else\n Rails.logger.info "#{log_prefix_query} 'market_item_statuses' 不存在于 opts 中。"\n end\n \n Rails.logger.info "#{log_prefix_query} 返回原始话题关系。"\n original_topics_relation # 隐式返回\n end\n Rails.logger.info "[TecencMarket] 应用了简化的自定义过滤器 (V1.1_Test)。"\nend\n\n\n使用此简化过滤器的观察:\n\n* 没有我自定义过滤器参数的请求(例如,仅 /c/market/5/l/latest.json?filter=default):\n\n * 简化的过滤块日志正确:\n\n \n [TecencMarket_SimplifiedFilter_V1.1_Test] 通过 TopicQuery 接收的 Opts: {:category=>5, :filter=>"default", ...} \n [TecencMarket_SimplifiedFilter_V1.1_Test] 'market_item_statuses' 不存在于 opts。\n [TecencMarket_SimplifiedFilter_V1.1_Test] 返回原始话题关系。\n \n\n * 页面加载正常,返回 200 OK。\n\n* 带有我自定义过滤器参数的请求(例如 /c/market/5/l/latest.json?filter=defaultmarket_item_statuses=Available):\n\n * 观察到 ListController 补丁日志:[TecencMarket_ListControllerExt_BuildOptsV3] 注入到 opts:market_item_statuses = Available\n”}{“content”: "* 在 … 毫秒内立即发生的 Completed 500 Internal Server Error
- 至关重要的是,没有任何来自简化过滤器块内部的日志(没有
[TecencMarket_SimplifiedFilter_V1.1_Test]... 的行)出现在此失败请求的日志中。
这表明 500 错误发生在 TopicQuery 使用 opts 哈希(现在包含我自定义参数)初始化之后,但在或刚刚当 Discourse 核心的 TopicQuery#apply_custom_filters 机制试图执行我注册的(现在非常简单的)过滤器块时。
我在尝试从 development.log 中孤立导致请求失败的 Ruby 异常和完整的回溯信息方面遇到困难(我收集到的日志片段显示了 500 的行本身,但没有显示前面详细的错误信息)。
后续问题:
鉴于:
-
现已成功将自定义参数注入到 TopicQuery.options,这是通过 ListController 更新实现的。
-
当这些自定义参数存在于 opts 中时,发生了 500 错误。
-
这个 500 错误发生在甚至执行极其简化的自定义过滤器块(只记录日志并返回原始关系)之前。
-
这是在 Discourse 3.5.0.beta3-dev 版本上。
什么可能导致 TopicQuery 本身,或其 apply_custom_filters 方法,在调用注册的自定义过滤器块之前,因 options 哈希中包含这些插件特定的键而出错?我们之前怀疑的 LocalJumpError 仍然在处理过滤器块迭代或调用的底层有关联,即使我简化的块只是隐式返回?
关于在 TopicQuery 行为中检查这些类型的自定义选项的下一步建议,或关于如何更稳健地获取导致 500 错误的完整回溯信息的指导,将非常有帮助。" }