From 2a75656ff24ba750b19838e27e559828a3aaf719 Mon Sep 17 00:00:00 2001 From: Angus McLeod Date: Thu, 26 Oct 2023 21:34:23 +0800 Subject: [PATCH] DEV: Add category custom field preloading to CategoryList (#23969) This commit also introduced a plugin API for preloading category custom fields. --- app/models/category_list.rb | 7 ++++ lib/plugin/instance.rb | 7 ++++ spec/models/category_list_spec.rb | 17 +++++++++ spec/requests/categories_controller_spec.rb | 38 +++++++++++++++++++++ 4 files changed, 69 insertions(+) diff --git a/app/models/category_list.rb b/app/models/category_list.rb index b6e8e7d9e13..ed7fa6673d0 100644 --- a/app/models/category_list.rb +++ b/app/models/category_list.rb @@ -6,6 +6,9 @@ class CategoryList cattr_accessor :preloaded_topic_custom_fields self.preloaded_topic_custom_fields = Set.new + cattr_accessor :preloaded_category_custom_fields + self.preloaded_category_custom_fields = Set.new + attr_accessor :categories, :uncategorized def self.register_included_association(association) @@ -139,6 +142,10 @@ class CategoryList @categories = query.to_a + if preloaded_category_custom_fields.any? + Category.preload_custom_fields(@categories, preloaded_category_custom_fields) + end + include_subcategories = @options[:include_subcategories] == true notification_levels = CategoryUser.notification_levels_for(@guardian.user) diff --git a/lib/plugin/instance.rb b/lib/plugin/instance.rb index e912cc31109..83e18d3a0ec 100644 --- a/lib/plugin/instance.rb +++ b/lib/plugin/instance.rb @@ -290,6 +290,13 @@ class Plugin::Instance Upload.add_in_use_callback(&block) end + # Registers a category custom field to be loaded when rendering a category list + # Example usage: + # register_category_list_preloaded_category_custom_fields("custom_field") + def register_category_list_preloaded_category_custom_fields(field) + CategoryList.preloaded_category_custom_fields << field + end + def custom_avatar_column(column) reloadable_patch do |plugin| UserLookup.lookup_columns << column diff --git a/spec/models/category_list_spec.rb b/spec/models/category_list_spec.rb index bb341cc2f58..255fb859b85 100644 --- a/spec/models/category_list_spec.rb +++ b/spec/models/category_list_spec.rb @@ -357,4 +357,21 @@ RSpec.describe CategoryList do DiscoursePluginRegistry.clear_modifiers! end end + + describe "with custom fields" do + fab!(:category) { Fabricate(:category, user: admin) } + + before { category.upsert_custom_fields("bob" => "marley") } + after { CategoryList.preloaded_category_custom_fields = Set.new } + + it "can preloads custom fields" do + CategoryList.preloaded_category_custom_fields << "bob" + + expect(category_list.categories[-1].custom_field_preloaded?("bob")).to eq(true) + end + + it "does not preload fields that were not set for preloading" do + expect(category_list.categories[-1].custom_field_preloaded?("bob")).to be_falsey + end + end end diff --git a/spec/requests/categories_controller_spec.rb b/spec/requests/categories_controller_spec.rb index 286ca7e585f..a1248e3fe7a 100644 --- a/spec/requests/categories_controller_spec.rb +++ b/spec/requests/categories_controller_spec.rb @@ -372,6 +372,44 @@ RSpec.describe CategoriesController do response.parsed_body["category_list"]["categories"].map { |x| x["id"] }, ).not_to include(uncategorized.id) end + + describe "with serialized category custom fields" do + class CategoryPlugin < Plugin::Instance + end + + let!(:plugin) do + plugin = CategoryPlugin.new + plugin.add_to_serializer(:basic_category, :bob) { object.custom_fields["bob"] } + plugin + end + + before { category.upsert_custom_fields("bob" => "marley") } + after { CategoryList.preloaded_category_custom_fields = Set.new } + + context "when custom fields are not preloaded" do + it "increases the query count" do + queries = track_sql_queries { get "/categories.json" } + + expect(response.status).to eq(200) + category = response.parsed_body["category_list"]["categories"][-1] + expect(category["bob"]).to eq("marley") + expect(queries.count).to eq(7) + end + end + + context "when custom fields are preloaded" do + before { CategoryList.preloaded_category_custom_fields << "bob" } + + it "does not increase the query count" do + queries = track_sql_queries { get "/categories.json" } + + expect(response.status).to eq(200) + category = response.parsed_body["category_list"]["categories"][-1] + expect(category["bob"]).to eq("marley") + expect(queries.count).to eq(6) + end + end + end end describe "extensibility event" do