Skip to content

Commit

Permalink
Merge pull request #826 from studentinsights/split-up-school-overview…
Browse files Browse the repository at this point in the history
…-queries

Add an school overview page that merges mutable/precomputed data on c…
  • Loading branch information
alexsoble committed Jan 20, 2017
2 parents b7a1f0b + 135f69b commit 58c1b19
Show file tree
Hide file tree
Showing 5 changed files with 136 additions and 20 deletions.
2 changes: 1 addition & 1 deletion app/assets/javascripts/components/slice_buttons.js
Expand Up @@ -10,7 +10,7 @@
propTypes: {
students: React.PropTypes.arrayOf(React.PropTypes.object).isRequired,
filters: React.PropTypes.arrayOf(React.PropTypes.object).isRequired,
filtersHash: React.PropTypes.object.isRequired,
filtersHash: React.PropTypes.string.isRequired,
clearFilters: React.PropTypes.func.isRequired
},

Expand Down
75 changes: 75 additions & 0 deletions app/assets/javascripts/school_overview/main_fast.js
@@ -0,0 +1,75 @@
//= require ./school_overview_page

$(function() {
if ($('body').hasClass('schools') && $('body').hasClass('show_fast')) {
var MixpanelUtils = window.shared.MixpanelUtils;
var SchoolOverviewPage = window.shared.SchoolOverviewPage;
var Filters = window.shared.Filters;
var createEl = window.shared.ReactHelpers.createEl;

function main() {
var serializedData = $('#serialized-data').data();
MixpanelUtils.registerUser(serializedData.currentEducator);
MixpanelUtils.track('PAGE_VISIT', { page_key: 'SCHOOL_OVERVIEW_DASHBOARD_FAST' });

renderLoading();
requestsPromise(serializedData.schoolId)
.then(mergedPromise)
.then(render.bind(null, serializedData));
}

function requestsPromise(schoolId) {
// make two requests, wait til they both come back
return $.when(
$.ajax('/schools/' + schoolId + '/get_precomputed_hashes_for_school/'),
$.ajax('/schools/' + schoolId + '/get_mutable_fields_for_school/')
);
}

function mergedPromise(precomputedReq, mutableFieldsReq) {
var precomputedStudents = precomputedReq[0];
var mutableFields = mutableFieldsReq[0];

// make indexes by student_id
/*
[
all_event_notes: { 34: [{}, {}], 72: [{}] },
all_services: { 13: [{}], 22: [{}] },
...
]
*/
var indexMap = Object.keys(mutableFields).reduce(function (indexMap, key) {
var index = _.groupBy(mutableFields[key], 'student_id');
indexMap[key] = index;
return indexMap;
}, {});

var merged = precomputedStudents.map(function(student) {
return _.merge(student, {
event_notes: indexMap.all_event_notes[student.id] || [],
active_services: indexMap.all_active_services[student.id] || [],
summer_services: indexMap.all_summer_services[student.id] || [],
interventions: indexMap.all_interventions[student.id] || []
});
});

return $.Deferred().resolve(merged);
}

function render(serializedData, students) {
ReactDOM.render(createEl(SchoolOverviewPage, {
allStudents: students,
serviceTypesIndex: serializedData.constantIndexes.service_types_index,
eventNoteTypesIndex: serializedData.constantIndexes.event_note_types_index,
initialFilters: Filters.parseFiltersHash(window.location.hash)
}), document.getElementById('main'));
}

function renderLoading() {
document.getElementById('main').innerHTML = '<div style="padding: 40px; font-size: 24px;">Loading...</div>';
}


main();
}
});
48 changes: 40 additions & 8 deletions app/controllers/schools_controller.rb
Expand Up @@ -6,19 +6,12 @@ class SchoolsController < ApplicationController
:authorize

def show
if current_educator.districtwide_access?
eager_loads = [:interventions, :student_risk_level, :homeroom, :student_school_years]
authorized_students = @school.students.active.includes(eager_loads)
else
authorized_students = current_educator.students_for_school_overview
end
authorized_students = authorized_students_for_overview(@school)

# TODO(kr) Read from cache, since this only updates daily
student_hashes = log_timing('schools#show student_hashes') do
load_precomputed_student_hashes(Time.now, authorized_students.map(&:id))
end

# Read data stored StudentInsights each time, with no caching
merged_student_hashes = log_timing('schools#show merge_mutable_fields_for_slicing') do
merge_mutable_fields_for_slicing(student_hashes)
end
Expand All @@ -31,6 +24,36 @@ def show
render 'shared/serialized_data'
end

def show_fast
@serialized_data = {
school_id: @school.id,
current_educator: current_educator,
constant_indexes: constant_indexes
}

render 'shared/serialized_data'
end

def get_precomputed_hashes_for_school
authorized_students = authorized_students_for_overview(@school)

student_hashes = log_timing('schools#get_precomputed_hashes_for_school') do
load_precomputed_student_hashes(Time.now, authorized_students.map(&:id))
end

render json: student_hashes
end

def get_mutable_fields_for_school
authorized_students = authorized_students_for_overview(@school)

mutable_fields = log_timing('schools#get_mutable_hashes_for_school') do
mutable_fields_for_slicing(authorized_students.map(&:id))
end

render json: mutable_fields
end

def star_math
serialized_data_for_star {|student| student.star_math_results }
render 'shared/serialized_data'
Expand All @@ -52,6 +75,7 @@ def csv
end

private

# This should always find a record, but if it doesn't we fall back to the
# raw query.
# Results an array of student_hashes.
Expand Down Expand Up @@ -122,4 +146,12 @@ def educator_authorized_for_school
current_educator.districtwide_access?
end

def authorized_students_for_overview(school)
if current_educator.districtwide_access?
eager_loads = [:interventions, :student_risk_level, :homeroom, :student_school_years]
school.students.active.includes(eager_loads)
else
current_educator.students_for_school_overview
end
end
end
28 changes: 17 additions & 11 deletions app/helpers/students_query_helper.rb
Expand Up @@ -15,20 +15,14 @@ def student_hash_for_slicing(student)
# into the list of student hashes.
def merge_mutable_fields_for_slicing(student_hashes)
student_ids = student_hashes.map {|student_hash| student_hash[:id] }
summer_service_type_ids = ServiceType.where(summer_program: true).pluck(:id)
all_event_notes = EventNote.where(student_id: student_ids)
all_active_services = Service.where(student_id: student_ids).active
all_interventions = Intervention.where(student_id: student_ids)
all_summer_services = Service.where(student_id: student_ids)
.where(service_type_id: summer_service_type_ids)
.where("date_started > ?", 1.year.ago)
mutable_fields = mutable_fields_for_slicing(student_ids)

student_hashes.map do |student_hash|
for_student = {
event_notes: all_event_notes.select {|event_note| event_note.student_id == student_hash[:id] },
active_services: all_active_services.select {|service| service.student_id == student_hash[:id] },
summer_services: all_summer_services.select {|service| service.student_id == student_hash[:id] },
interventions: all_interventions.select {|intervention| intervention.student_id == student_hash[:id] }
event_notes: mutable_fields[:all_event_notes].select {|event_note| event_note.student_id == student_hash[:id] },
active_services: mutable_fields[:all_active_services].select {|service| service.student_id == student_hash[:id] },
summer_services: mutable_fields[:all_summer_services].select {|service| service.student_id == student_hash[:id] },
interventions: mutable_fields[:all_interventions].select {|intervention| intervention.student_id == student_hash[:id] }
}
student_hash.merge({
event_notes: for_student[:event_notes].map {|x| serialize_event_note_without_attachments(x) },
Expand All @@ -39,6 +33,18 @@ def merge_mutable_fields_for_slicing(student_hashes)
end
end

def mutable_fields_for_slicing(student_ids)
summer_service_type_ids = ServiceType.where(summer_program: true).pluck(:id)
{
all_event_notes: EventNote.where(student_id: student_ids),
all_active_services: Service.where(student_id: student_ids).active,
all_interventions: Intervention.where(student_id: student_ids),
all_summer_services: Service.where(student_id: student_ids)
.where(service_type_id: summer_service_type_ids)
.where("date_started > ?", 1.year.ago)
}
end

# Used to compute key for reading and writing precomputed student_hashes documents
def precomputed_student_hashes_key(time_now, authorized_student_ids)
timestamp = time_now.beginning_of_day.to_i
Expand Down
3 changes: 3 additions & 0 deletions config/routes.rb
Expand Up @@ -42,5 +42,8 @@
get :star_reading, on: :member
get :star_math, on: :member
get :csv, on: :member
get :show_fast, on: :member
get :get_precomputed_hashes_for_school, on: :member
get :get_mutable_fields_for_school, on: :member
end
end

0 comments on commit 58c1b19

Please sign in to comment.