From 2a26555a7a758ec870c8bbdf12d75758a3bea680 Mon Sep 17 00:00:00 2001 From: Natalie Tay Date: Tue, 1 Apr 2025 16:50:16 +0800 Subject: [PATCH] DEV: Allow specifying a condition when preloading topics for topic list (#32101) Currently when using `register_topic_preloader_associations`, we are not able to specify a condition that is evaluated at runtime. This commit allows specifying a condition and also keeps backward compatibility. ``` register_topic_preloader_associations(:linked_topic) { true } register_topic_preloader_associations({ first_post: [uploads] }) ``` --- app/models/topic_list.rb | 10 +++++++++- lib/plugin/instance.rb | 22 ++++++++++++++++++---- spec/lib/topic_query_spec.rb | 15 ++++++++++----- 3 files changed, 37 insertions(+), 10 deletions(-) diff --git a/app/models/topic_list.rb b/app/models/topic_list.rb index 9578eb11310..83b97925734 100644 --- a/app/models/topic_list.rb +++ b/app/models/topic_list.rb @@ -138,7 +138,15 @@ class TopicList { category: :parent_category }, ] - topic_preloader_associations.concat(DiscoursePluginRegistry.topic_preloader_associations.to_a) + DiscoursePluginRegistry.topic_preloader_associations.each do |a| + fields = a[:fields] + condition = a[:condition] + if condition.present? + topic_preloader_associations << fields if condition.present? && condition.call + else + topic_preloader_associations << fields + end + end ActiveRecord::Associations::Preloader.new( records: @topics, diff --git a/lib/plugin/instance.rb b/lib/plugin/instance.rb index d1f292afb66..000f54d7c19 100644 --- a/lib/plugin/instance.rb +++ b/lib/plugin/instance.rb @@ -1347,6 +1347,24 @@ class Plugin::Instance end end + # This method allows plugins to preload topic associations when loading topics + # that make use of topic_list. + # + # @param fields [Symbol, Array, Hash] The topic associations to preload. + # + # @example + # register_topic_preloader_associations(:first_post) + # register_topic_preloader_associations([:first_post, :topic_embeds]) + # register_topic_preloader_associations({ first_post: :uploads }) + # register_topic_preloader_associations({ first_post: :uploads }) do + # SiteSetting.some_setting_enabled? + # end + # + # @return [void] + def register_topic_preloader_associations(fields, &condition) + DiscoursePluginRegistry.register_topic_preloader_association({ fields:, condition: }, self) + end + protected def self.js_path @@ -1441,10 +1459,6 @@ class Plugin::Instance reloadable_patch { NewPostManager.add_plugin_payload_attribute(attribute_name) } end - def register_topic_preloader_associations(fields) - DiscoursePluginRegistry.register_topic_preloader_association(fields, self) - end - ## # Allows plugins to preload topic associations when loading categories with topics. # diff --git a/spec/lib/topic_query_spec.rb b/spec/lib/topic_query_spec.rb index 6ac2fed86cb..1fd8053b01e 100644 --- a/spec/lib/topic_query_spec.rb +++ b/spec/lib/topic_query_spec.rb @@ -1305,17 +1305,22 @@ RSpec.describe TopicQuery do context "when preloading associations" do it "preloads associations" do - DiscoursePluginRegistry.register_topic_preloader_association( - :first_post, - Plugin::Instance.new, - ) + plugin = Plugin::Instance.new + plugin.register_topic_preloader_associations(:topic_embed) + plugin.register_topic_preloader_associations({ first_post: [:uploads] }) + plugin.register_topic_preloader_associations(:user_warning) { true } + plugin.register_topic_preloader_associations(:linked_topic) { false } topic = Fabricate(:topic) Fabricate(:post, topic: topic) new_topic = topic_query.list_new.topics.first expect(new_topic.association(:image_upload).loaded?).to eq(true) # Preloaded by default - expect(new_topic.association(:first_post).loaded?).to eq(true) # Testing a user-defined preloaded association + expect(new_topic.association(:topic_embed).loaded?).to eq(true) # Testing a user-defined preloaded association + expect(new_topic.association(:first_post).loaded?).to eq(true) # Nested preloaded association + expect(new_topic.first_post.association(:uploads).loaded?).to eq(true) # Nested preloaded association + expect(new_topic.association(:user_warning).loaded?).to eq(true) # Conditionally loaded + expect(new_topic.association(:linked_topic).loaded?).to eq(false) # Failed condition expect(new_topic.association(:user).loaded?).to eq(false) # Testing the negative DiscoursePluginRegistry.reset_register!(:topic_preloader_associations)