Reduce SQL queries for score runs

Fixes CODEOCEAN-JR
This commit is contained in:
Sebastian Serth
2023-03-14 00:47:02 +01:00
parent 4a28d4c5a3
commit 939b31967f
4 changed files with 14 additions and 6 deletions

View File

@ -3,13 +3,20 @@
module FileParameters module FileParameters
def reject_illegal_file_attributes(exercise, params) def reject_illegal_file_attributes(exercise, params)
if exercise && params if exercise && params
# We only want to load the files once, to avoid multiple database queries.
# Further, we use `unscope` to avoid that the `order` scope is applied
files = CodeOcean::File.unscope(:order).where(id: params.values.pluck(:file_id))
params.reject do |_, file_attributes| params.reject do |_, file_attributes|
file = CodeOcean::File.find_by(id: file_attributes[:file_id]) # This mechanism seems cumbersome, but we cannot use an index here.
# The ordering of the files is not guaranteed to be the same as the ordering of the file attributes.
file = files.find {|f| f.id == file_attributes[:file_id].to_i }
next true if file.nil? || file.hidden || file.read_only next true if file.nil? || file.hidden || file.read_only
# avoid that public files from other contexts can be created # avoid that public files from other contexts can be created
# `next` is similar to an early return and will proceed with the next iteration of the loop # `next` is similar to an early return and will proceed with the next iteration of the loop
next true if file.context_type == 'Exercise' && file.context != exercise next true if file.context_type == 'Exercise' && file.context_id != exercise.id
next true if file.context_type == 'Submission' && file.context.user != current_user next true if file.context_type == 'Submission' && (file.context.user_id != current_user.id || file.context.user_type != current_user.class.name)
next true if file.context_type == 'CommunitySolution' && controller_name != 'community_solutions' next true if file.context_type == 'CommunitySolution' && controller_name != 'community_solutions'
false false

View File

@ -12,8 +12,9 @@ module SubmissionParameters
end end
submission_params = merge_user(submission_params) submission_params = merge_user(submission_params)
files_attributes = submission_params[:files_attributes] files_attributes = submission_params[:files_attributes]
exercise = Exercise.find_by(id: submission_params[:exercise_id]) exercise = @exercise || Exercise.find_by(id: submission_params[:exercise_id])
submission_params[:files_attributes] = reject_illegal_file_attributes(exercise, files_attributes) submission_params[:files_attributes] = reject_illegal_file_attributes(exercise, files_attributes)
submission_params[:exercise] = exercise
submission_params submission_params
end end
private :submission_params private :submission_params

View File

@ -517,7 +517,7 @@ class Exercise < ApplicationRecord
0 0
end end
else else
files.teacher_defined_assessments.sum(:weight) @maximum_score ||= files.teacher_defined_assessments.sum(:weight)
end end
end end

View File

@ -12,7 +12,7 @@ describe FileParameters do
describe '#reject_illegal_file_attributes!' do describe '#reject_illegal_file_attributes!' do
def file_accepted?(file) def file_accepted?(file)
files = [[0, attributes_for(:file, context: hello_world, file_id: file.id)]] files = {'0': attributes_for(:file, context: hello_world, file_id: file.id)}
filtered_files = controller.send(:reject_illegal_file_attributes, hello_world, files) filtered_files = controller.send(:reject_illegal_file_attributes, hello_world, files)
files.eql?(filtered_files) files.eql?(filtered_files)
end end