mirror of
https://github.com/discourse/discourse.git
synced 2025-06-25 01:30:17 +08:00
PERF: fixes N+1 for automation plugin (#32810)
- Add a safeguard until we implement pagination for the index, it ensures we won't try to load more than 500 automations ever. - Includes the fields of the automation so we don't have an N+1 and also filter them in ruby land instead of doing two additional queries - Ensures a field object in the field serializer is capable to find the loaded automation associated to it instead of trying to reload it - Includes pending_automations to avoid an N+1
This commit is contained in:
@ -5,7 +5,13 @@ module DiscourseAutomation
|
||||
requires_plugin DiscourseAutomation::PLUGIN_NAME
|
||||
|
||||
def index
|
||||
automations = DiscourseAutomation::Automation.order(:name).all
|
||||
automations =
|
||||
DiscourseAutomation::Automation
|
||||
.strict_loading
|
||||
.includes(:fields, :pending_automations)
|
||||
.order(:name)
|
||||
.limit(500)
|
||||
.all
|
||||
serializer =
|
||||
ActiveModel::ArraySerializer.new(
|
||||
automations,
|
||||
@ -19,7 +25,8 @@ module DiscourseAutomation
|
||||
end
|
||||
|
||||
def show
|
||||
automation = DiscourseAutomation::Automation.find(params[:id])
|
||||
automation =
|
||||
DiscourseAutomation::Automation.includes(:fields, :pending_automations).find(params[:id])
|
||||
render_serialized_automation(automation)
|
||||
end
|
||||
|
||||
@ -43,7 +50,8 @@ module DiscourseAutomation
|
||||
def update
|
||||
params.require(:automation)
|
||||
|
||||
automation = DiscourseAutomation::Automation.find(params[:id])
|
||||
automation =
|
||||
DiscourseAutomation::Automation.includes(:fields, :pending_automations).find(params[:id])
|
||||
if automation.scriptable.forced_triggerable
|
||||
params[:trigger] = automation.scriptable.forced_triggerable[:triggerable].to_s
|
||||
end
|
||||
|
@ -7,7 +7,8 @@ module DiscourseAutomation
|
||||
has_many :fields,
|
||||
class_name: "DiscourseAutomation::Field",
|
||||
dependent: :delete_all,
|
||||
foreign_key: "automation_id"
|
||||
foreign_key: "automation_id",
|
||||
inverse_of: :automation
|
||||
has_many :pending_automations,
|
||||
class_name: "DiscourseAutomation::PendingAutomation",
|
||||
dependent: :delete_all,
|
||||
@ -28,6 +29,16 @@ module DiscourseAutomation
|
||||
|
||||
attr_accessor :running_in_background
|
||||
|
||||
def trigger=(new_trigger)
|
||||
@triggerable = nil
|
||||
super
|
||||
end
|
||||
|
||||
def script=(new_script)
|
||||
@scriptable = nil
|
||||
super
|
||||
end
|
||||
|
||||
def running_in_background!
|
||||
@running_in_background = true
|
||||
end
|
||||
|
@ -4,7 +4,10 @@ module DiscourseAutomation
|
||||
class Field < ActiveRecord::Base
|
||||
self.table_name = "discourse_automation_fields"
|
||||
|
||||
belongs_to :automation, class_name: "DiscourseAutomation::Automation"
|
||||
belongs_to :automation,
|
||||
class_name: "DiscourseAutomation::Automation",
|
||||
foreign_key: :automation_id,
|
||||
inverse_of: :fields
|
||||
|
||||
around_save :on_update_callback
|
||||
|
||||
|
@ -61,7 +61,7 @@ module DiscourseAutomation
|
||||
not_found: scriptable.not_found,
|
||||
templates:
|
||||
process_templates(filter_fields_with_priority(scriptable.fields, object.trigger&.to_sym)),
|
||||
fields: process_fields(object.fields.where(target: "script")),
|
||||
fields: process_fields(script_fields),
|
||||
}
|
||||
end
|
||||
|
||||
@ -80,7 +80,7 @@ module DiscourseAutomation
|
||||
doc: I18n.exists?(doc_key, :en) ? I18n.t(doc_key) : nil,
|
||||
not_found: triggerable&.not_found,
|
||||
templates: process_templates(triggerable&.fields || []),
|
||||
fields: process_fields(object.fields.where(target: "trigger")),
|
||||
fields: process_fields(trigger_fields),
|
||||
settings: triggerable&.settings,
|
||||
}
|
||||
end
|
||||
@ -141,6 +141,14 @@ module DiscourseAutomation
|
||||
).as_json || []
|
||||
end
|
||||
|
||||
def script_fields
|
||||
object.fields.select { |f| f.target == "script" }
|
||||
end
|
||||
|
||||
def trigger_fields
|
||||
object.fields.select { |f| f.target == "trigger" }
|
||||
end
|
||||
|
||||
def scriptable
|
||||
object.scriptable
|
||||
end
|
||||
|
@ -5,7 +5,7 @@ en:
|
||||
models:
|
||||
fields:
|
||||
required_field: Field `%{name}` must be filled on `%{target}:%{target_name}`.
|
||||
invalid_field: Field’s component `%{component}` is not usable on `%{target}:%{target_name}.`
|
||||
invalid_field: Field’s component `%{component}` is not usable on `%{target}:%{target_name}`.
|
||||
invalid_metadata: Data for `%{field}` is invalid or component `%{component}` is unknown.
|
||||
triggerables:
|
||||
errors:
|
||||
|
Reference in New Issue
Block a user