fix existing out of sync outcome alignments

fixes CNVS-7620

test plan:
- NOTE: before apply this patchset
  * create some rubrics with and without outcomes attached to assignments
  * remove some of them
- after applying this patchset, the active ones should still be active, and
  the deleted ones should still be deleted.
- if you had old alignments that should have been deleted, but where not, they
  should now be deleted (it's difficult to get them to test, at this point)

Change-Id: I813e083357a99a38eb22611b5b5848fbf9525156
Reviewed-on: https://gerrit.instructure.com/23475
Tested-by: Jenkins <jenkins@instructure.com>
QA-Review: Amber Taniuchi <amber@instructure.com>
Reviewed-by: Cameron Matheson <cameron@instructure.com>
Product-Review: Simon Williams <simon@instructure.com>
This commit is contained in:
Simon Williams 2013-08-19 14:11:24 -06:00
parent 99ab5a08d1
commit 26214e33a4
5 changed files with 173 additions and 1 deletions

View File

@ -117,12 +117,16 @@ class Rubric < ActiveRecord::Base
if data_changed? || workflow_state_changed?
outcome_ids = []
unless deleted?
outcome_ids = (data || []).map{|c| c[:learning_outcome_id] }.compact.map(&:to_i).uniq
outcome_ids = data_outcome_ids
end
LearningOutcome.update_alignments(self, context, outcome_ids)
end
true
end
def data_outcome_ids
(data || []).map{|c| c[:learning_outcome_id] }.compact.map(&:to_i).uniq
end
def criteria_object
OpenObject.process(self.data)

View File

@ -0,0 +1,11 @@
class FixOutOfSyncOutcomeAlignments < ActiveRecord::Migration
tag :postdeploy
def self.up
DataFixup::FixOutOfSyncOutcomeAlignments.send_later_if_production_enqueue_args(:run,
:priority => Delayed::LOW_PRIORITY, :max_attempts => 1)
end
def self.down
end
end

View File

@ -0,0 +1,71 @@
module DataFixup::FixOutOfSyncOutcomeAlignments
def self.run
# Active alignments to deleted rubrics
ContentTag.joins("
INNER JOIN rubrics r
ON content_tags.content_id = r.id
AND content_tags.content_type = 'Rubric'
").where("
content_tags.tag_type = 'learning_outcome'
AND content_tags.workflow_state = 'active'
AND r.workflow_state = 'deleted'
").find_each do |ct|
ct.destroy
end
# Active alignments to rubrics that should no longer be aligned
ContentTag.joins("
INNER JOIN rubrics r
ON content_tags.content_id = r.id
AND content_tags.content_type = 'Rubric'
").where("
content_tags.tag_type = 'learning_outcome'
AND content_tags.workflow_state = 'active'
AND r.workflow_state = 'active'
AND NOT r.data LIKE '%:learning_outcome_id: ' || content_tags.learning_outcome_id || '%'
").find_each do |ct|
ct.destroy
end
# Active alignments to assignments without rubrics
ContentTag.joins("
INNER JOIN assignments a
ON content_tags.content_id = a.id
AND content_tags.content_type = 'Assignment'
LEFT OUTER JOIN rubric_associations ra
ON ra.association_id = a.id
AND ra.association_type = 'Assignment'
").where("
content_tags.tag_type = 'learning_outcome'
AND content_tags.workflow_state = 'active'
AND ra.id IS NULL
").find_each do |ct|
ct.destroy
end
# Active alignments to assignments with rubrics
# that don't have a matching alignment
ContentTag.joins("
INNER JOIN assignments a
ON content_tags.content_id = a.id
AND content_tags.content_type = 'Assignment'
INNER JOIN rubric_associations ra
ON ra.association_id = a.id
AND ra.association_type = 'Assignment'
INNER JOIN rubrics r
ON ra.rubric_id = r.id
LEFT OUTER JOIN content_tags ct2
ON ct2.content_id = r.id
AND ct2.content_type = 'Rubric'
AND ct2.tag_type = 'learning_outcome'
AND ct2.workflow_state = 'active'
AND ct2.learning_outcome_id = content_tags.learning_outcome_id
").where("
content_tags.tag_type = 'learning_outcome'
AND content_tags.workflow_state = 'active'
AND ct2.id IS NULL
").find_each do |ct|
ct.destroy
end
end
end

View File

@ -0,0 +1,84 @@
#
# Copyright (C) 2012 Instructure, Inc.
#
# This file is part of Canvas.
#
# Canvas is free software: you can redistribute it and/or modify it under
# the terms of the GNU Affero General Public License as published by the Free
# Software Foundation, version 3 of the License.
#
# Canvas is distributed in the hope that it will be useful, but WITHOUT ANY
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
# A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
# details.
#
# You should have received a copy of the GNU Affero General Public License along
# with this program. If not, see <http://www.gnu.org/licenses/>.
#
require File.expand_path(File.dirname(__FILE__) + '/../spec_helper.rb')
describe DataFixup::FixOutOfSyncOutcomeAlignments do
before do
course_with_teacher_logged_in(:active_all => true)
outcome_with_rubric
@rubric_association_object = @course.assignments.create!(:title => 'blah')
@rubric_association = @rubric.rubric_associations.create!({
:association => @rubric_association_object,
:context => @course,
:purpose => 'grading'
})
end
it "should not delete active alignments" do
align1 = @rubric_association_object.learning_outcome_alignments.first
align2 = @rubric.learning_outcome_alignments.first
align1.reload.should_not be_deleted
align2.reload.should_not be_deleted
DataFixup::FixOutOfSyncOutcomeAlignments.run
align1.reload.should_not be_deleted
align2.reload.should_not be_deleted
end
it "should delete alignments to deleted rubrics" do
align = @rubric.learning_outcome_alignments.first
Rubric.where(:id => @rubric.id).update_all(:workflow_state => 'deleted')
align.reload.should_not be_deleted
DataFixup::FixOutOfSyncOutcomeAlignments.run
align.reload.should be_deleted
end
it "should delete alignments to rubrics that no longer should be aligned" do
align = @rubric.learning_outcome_alignments.first
data = @rubric.data
data.first.delete(:learning_outcome_id)
Rubric.where(:id => @rubric.id).update_all(:data => data.to_yaml)
align.reload.should_not be_deleted
DataFixup::FixOutOfSyncOutcomeAlignments.run
align.reload.should be_deleted
end
it "should delete alignments to assignments without rubrics" do
align = @rubric_association_object.learning_outcome_alignments.first
RubricAssociation.where(:rubric_id => @rubric.id).delete_all
align.reload.should_not be_deleted
DataFixup::FixOutOfSyncOutcomeAlignments.run
align.reload.should be_deleted
end
it "should delete alignments to assignments with rubrics without matching alignments" do
align = @rubric_association_object.learning_outcome_alignments.first
@rubric.learning_outcome_alignments.update_all(:learning_outcome_id => 0)
align.reload.should_not be_deleted
DataFixup::FixOutOfSyncOutcomeAlignments.run
align.reload.should be_deleted
end
end

View File

@ -303,7 +303,9 @@ def should_edit_an_outcome_group
outcome_group_model
get outcome_url
wait_for_ajaximations
fj('.outcomes-sidebar .outcome-level:first li.outcome-group').click
wait_for_ajaximations
keep_trying_until do
fj('.edit_button').click