mirror of
https://github.com/discourse/discourse.git
synced 2025-06-06 11:14:42 +08:00
PERF: Eager load Theme associations in Stylesheet Manager.
Before this change, calling `StyleSheet::Manager.stylesheet_details` for the first time resulted in multiple queries to the database. This is because the code was modelled in a way where each `Theme` was loaded from the database one at a time. This PR restructures the code such that it allows us to load all the theme records in a single query. It also allows us to eager load the required associations upfront. In order to achieve this, I removed the support of loading multiple themes per request. It was initially added to support user selectable theme components but the feature was never completed and abandoned because it wasn't a feature that we thought was worth building.
This commit is contained in:
@ -320,6 +320,7 @@ class ColorScheme < ActiveRecord::Base
|
||||
end
|
||||
if theme_ids.present?
|
||||
Stylesheet::Manager.cache.clear
|
||||
|
||||
Theme.notify_theme_change(
|
||||
theme_ids,
|
||||
with_scheme: true,
|
||||
|
@ -29,6 +29,9 @@ class Theme < ActiveRecord::Base
|
||||
has_many :locale_fields, -> { filter_locale_fields(I18n.fallbacks[I18n.locale]) }, class_name: 'ThemeField'
|
||||
has_many :upload_fields, -> { where(type_id: ThemeField.types[:theme_upload_var]).preload(:upload) }, class_name: 'ThemeField'
|
||||
has_many :extra_scss_fields, -> { where(target_id: Theme.targets[:extra_scss]) }, class_name: 'ThemeField'
|
||||
has_many :yaml_theme_fields, -> { where("name = 'yaml' AND type_id = ?", ThemeField.types[:yaml]) }, class_name: 'ThemeField'
|
||||
has_many :var_theme_fields, -> { where("type_id IN (?)", ThemeField.theme_var_type_ids) }, class_name: 'ThemeField'
|
||||
has_many :builder_theme_fields, -> { where("name IN (?)", ThemeField.scss_fields) }, class_name: 'ThemeField'
|
||||
|
||||
validate :component_validations
|
||||
|
||||
@ -164,6 +167,16 @@ class Theme < ActiveRecord::Base
|
||||
end
|
||||
end
|
||||
|
||||
def self.parent_theme_ids
|
||||
get_set_cache "parent_theme_ids" do
|
||||
Theme.where(component: false).pluck(:id)
|
||||
end
|
||||
end
|
||||
|
||||
def self.is_parent_theme?(id)
|
||||
self.parent_theme_ids.include?(id)
|
||||
end
|
||||
|
||||
def self.user_theme_ids
|
||||
get_set_cache "user_theme_ids" do
|
||||
Theme.user_selectable.pluck(:id)
|
||||
@ -188,25 +201,22 @@ class Theme < ActiveRecord::Base
|
||||
expire_site_cache!
|
||||
end
|
||||
|
||||
def self.transform_ids(ids, extend: true)
|
||||
return [] if ids.nil?
|
||||
get_set_cache "#{extend ? "extended_" : ""}transformed_ids_#{ids.join("_")}" do
|
||||
next [] if ids.blank?
|
||||
def self.transform_ids(id)
|
||||
return [] if id.blank?
|
||||
|
||||
ids = ids.dup
|
||||
ids.uniq!
|
||||
parent = ids.shift
|
||||
|
||||
components = ids
|
||||
components.push(*components_for(parent)) if extend
|
||||
components.sort!.uniq!
|
||||
|
||||
all_ids = [parent, *components]
|
||||
get_set_cache "transformed_ids_#{id}" do
|
||||
all_ids =
|
||||
if self.is_parent_theme?(id)
|
||||
components = components_for(id).tap { |c| c.sort!.uniq! }
|
||||
[id, *components]
|
||||
else
|
||||
[id]
|
||||
end
|
||||
|
||||
disabled_ids = Theme.where(id: all_ids)
|
||||
.includes(:remote_theme)
|
||||
.select { |t| !t.supported? || !t.enabled? }
|
||||
.pluck(:id)
|
||||
.map(&:id)
|
||||
|
||||
all_ids - disabled_ids
|
||||
end
|
||||
@ -272,11 +282,10 @@ class Theme < ActiveRecord::Base
|
||||
end
|
||||
end
|
||||
|
||||
def self.lookup_field(theme_ids, target, field, skip_transformation: false)
|
||||
return if theme_ids.blank?
|
||||
theme_ids = [theme_ids] unless Array === theme_ids
|
||||
def self.lookup_field(theme_id, target, field, skip_transformation: false)
|
||||
return "" if theme_id.blank?
|
||||
|
||||
theme_ids = transform_ids(theme_ids) if !skip_transformation
|
||||
theme_ids = !skip_transformation ? transform_ids(theme_id) : [theme_id]
|
||||
cache_key = "#{theme_ids.join(",")}:#{target}:#{field}:#{Theme.compiler_version}"
|
||||
lookup = @cache[cache_key]
|
||||
return lookup.html_safe if lookup
|
||||
@ -289,8 +298,8 @@ class Theme < ActiveRecord::Base
|
||||
|
||||
def self.lookup_modifier(theme_ids, modifier_name)
|
||||
theme_ids = [theme_ids] unless Array === theme_ids
|
||||
|
||||
theme_ids = transform_ids(theme_ids)
|
||||
|
||||
get_set_cache("#{theme_ids.join(",")}:modifier:#{modifier_name}:#{Theme.compiler_version}") do
|
||||
ThemeModifierSet.resolve_modifier_for_themes(theme_ids, modifier_name)
|
||||
end
|
||||
@ -335,14 +344,18 @@ class Theme < ActiveRecord::Base
|
||||
|
||||
def notify_theme_change(with_scheme: false)
|
||||
DB.after_commit do
|
||||
theme_ids = Theme.transform_ids([id])
|
||||
theme_ids = Theme.transform_ids(id)
|
||||
self.class.notify_theme_change(theme_ids, with_scheme: with_scheme)
|
||||
end
|
||||
end
|
||||
|
||||
def self.refresh_message_for_targets(targets, theme_ids)
|
||||
targets.map do |target|
|
||||
Stylesheet::Manager.stylesheet_data(target.to_sym, theme_ids)
|
||||
theme_ids = [theme_ids] unless theme_ids === Array
|
||||
|
||||
targets.each_with_object([]) do |target, data|
|
||||
theme_ids.each do |theme_id|
|
||||
data << Stylesheet::Manager.new(theme_id: theme_id).stylesheet_data(target.to_sym)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@ -385,7 +398,8 @@ class Theme < ActiveRecord::Base
|
||||
end
|
||||
|
||||
def list_baked_fields(target, name)
|
||||
theme_ids = Theme.transform_ids([id], extend: name == :color_definitions)
|
||||
theme_ids = Theme.transform_ids(id)
|
||||
theme_ids = [theme_ids.first] if name != :color_definitions
|
||||
self.class.list_baked_fields(theme_ids, target, name)
|
||||
end
|
||||
|
||||
@ -435,7 +449,7 @@ class Theme < ActiveRecord::Base
|
||||
|
||||
def all_theme_variables
|
||||
fields = {}
|
||||
ids = Theme.transform_ids([id])
|
||||
ids = Theme.transform_ids(id)
|
||||
ThemeField.find_by_theme_ids(ids).where(type_id: ThemeField.theme_var_type_ids).each do |field|
|
||||
next if fields.key?(field.name)
|
||||
fields[field.name] = field
|
||||
@ -530,7 +544,7 @@ class Theme < ActiveRecord::Base
|
||||
def included_settings
|
||||
hash = {}
|
||||
|
||||
Theme.where(id: Theme.transform_ids([id])).each do |theme|
|
||||
Theme.where(id: Theme.transform_ids(id)).each do |theme|
|
||||
hash.merge!(theme.cached_settings)
|
||||
end
|
||||
|
||||
@ -641,11 +655,6 @@ class Theme < ActiveRecord::Base
|
||||
contents
|
||||
end
|
||||
|
||||
def has_scss(target)
|
||||
name = target == :embedded_theme ? :embedded_scss : :scss
|
||||
list_baked_fields(target, name).count > 0
|
||||
end
|
||||
|
||||
def convert_settings
|
||||
settings.each do |setting|
|
||||
setting_row = ThemeSetting.where(theme_id: self.id, name: setting.name.to_s).first
|
||||
|
Reference in New Issue
Block a user