improve caching invalidation for groups in messageable user

test plan:
* create a course with a teacher and a student
* create a group set in the course with no groups

* as the teacher, view the inbox,
 open the dialog to compose a message for the course
 and search for recipients in it (priming the cache)
* create a new group in the group set and add
 a student to it
* refresh the inbox page, open the compose dialog again
 and try to search for people in the new group
* should find the student right away

closes #COMMS-2475

Change-Id: I1d310e90ecb7bc8ec1a50f85f55fa268cdc810ad
Reviewed-on: https://gerrit.instructure.com/c/canvas-lms/+/213406
Tested-by: Jenkins
Reviewed-by: Jeremy Stanley <jeremy@instructure.com>
QA-Review: Steven Burnett <sburnett@instructure.com>
Product-Review: James Williams <jamesw@instructure.com>
This commit is contained in:
James Williams 2019-10-16 14:07:25 -06:00
parent 2970bd7ff4
commit d80f253b25
5 changed files with 39 additions and 7 deletions

View File

@ -72,6 +72,7 @@ class Group < ActiveRecord::Base
before_save :update_max_membership_from_group_category
after_create :refresh_group_discussion_topics
after_save :touch_context, :if => :saved_change_to_workflow_state?
after_update :clear_cached_short_name, :if => :saved_change_to_name?

View File

@ -1809,6 +1809,12 @@ class User < ActiveRecord::Base
end
end
def participating_current_and_concluded_course_ids
cached_course_ids('current_and_concluded') do |enrollments|
enrollments.current_and_concluded.not_inactive_by_date_ignoring_access
end
end
def participating_student_current_and_concluded_course_ids
cached_course_ids('student_current_and_concluded') do |enrollments|
enrollments.current_and_concluded.not_inactive_by_date_ignoring_access.where(type: %w{StudentEnrollment StudentViewEnrollment})

View File

@ -265,7 +265,9 @@ class ActiveRecord::Base
def touch_context
return if (@@skip_touch_context ||= false || @skip_touch_context ||= false)
if self.respond_to?(:context_type) && self.respond_to?(:context_id) && self.context_type && self.context_id
self.context_type.constantize.where(id: self.context_id).update_all(updated_at: Time.now.utc)
self.class.connection.after_transaction_commit do
self.context_type.constantize.where(id: self.context_id).update_all(updated_at: Time.now.utc)
end
end
rescue
Canvas::Errors.capture_exception(:touch_context, $ERROR_INFO)

View File

@ -840,9 +840,7 @@ class MessageableUser
end
def all_courses_by_shard
@all_courses_by_shard ||=
@user.courses_with_primary_enrollment(:current_and_concluded_courses, nil, :include_completed_courses => true).
group_by(&:shard)
@all_courses_by_shard ||= Course.where(:id => @user.participating_current_and_concluded_course_ids).to_a.group_by(&:shard)
end
def visible_section_ids_by_shard
@ -972,9 +970,8 @@ class MessageableUser
end
def student_courses
@student_courses_by_shard ||= {}
@student_courses_by_shard[Shard.current] ||= all_courses.
select{ |course| course.primary_enrollment_type == 'StudentEnrollment' }
@student_courses_by_shard ||= Course.where(:id => @user.participating_student_current_and_concluded_course_ids).to_a.group_by(&:shard)
@student_courses_by_shard[Shard.current]
end
def visible_section_ids_in_courses(courses)

View File

@ -506,6 +506,32 @@ describe SearchController, type: :request do
end
end
context "caching" do
specs_require_cache(:redis_cache_store)
it "should show new groups in existing categories" do
json = api_call(:get, "/api/v1/search/recipients.json?context=course_#{@course.id}_groups&synthetic_contexts=1",
{:controller => 'search', :action => 'recipients', :format => 'json', :context => "course_#{@course.id}_groups", :synthetic_contexts => "1"})
expect(json.map{|r| r["id"]}).to eq ["group_#{@group.id}"]
Timecop.freeze(1.minute.from_now) do
group2 = @course.groups.create(:name => "whee new group", :group_category => @group.group_category)
json2 = api_call(:get, "/api/v1/search/recipients.json?context=course_#{@course.id}_groups&synthetic_contexts=1",
{:controller => 'search', :action => 'recipients', :format => 'json', :context => "course_#{@course.id}_groups", :synthetic_contexts => "1"})
expect(json2.map{|r| r["id"]}).to match_array ["group_#{@group.id}", "group_#{group2.id}"]
new_student = User.create!
@course.enroll_student(new_student, :enrollment_state => "active")
group2.add_user(new_student)
# show group members too
json3 = api_call(:get, "/api/v1/search/recipients.json?context=group_#{group2.id}",
{:controller => 'search', :action => 'recipients', :format => 'json', :context => "group_#{group2.id}"})
expect(json3.map{|r| r["id"]}).to eq [new_student.id]
end
end
end
context "sharding" do
specs_require_sharding