remove active_polymorph
fixes CNVS-25580 Change-Id: Id1a001e8b85f87d1c0e9678500ed13d435872b55 Reviewed-on: https://gerrit.instructure.com/68292 Tested-by: Jenkins Reviewed-by: Rob Orton <rob@instructure.com> Product-Review: Cody Cutrer <cody@instructure.com> QA-Review: Cody Cutrer <cody@instructure.com>
This commit is contained in:
parent
0ea92efcae
commit
440290c08f
|
@ -101,7 +101,6 @@ gem 'sentry-raven', '0.13.2', require: false
|
||||||
gem 'canvas_statsd', '1.0.3'
|
gem 'canvas_statsd', '1.0.3'
|
||||||
gem 'diplomat', '0.14.0', require: false
|
gem 'diplomat', '0.14.0', require: false
|
||||||
|
|
||||||
gem 'active_polymorph', path: 'gems/active_polymorph'
|
|
||||||
gem 'activesupport-suspend_callbacks', path: 'gems/activesupport-suspend_callbacks'
|
gem 'activesupport-suspend_callbacks', path: 'gems/activesupport-suspend_callbacks'
|
||||||
gem 'acts_as_list', path: 'gems/acts_as_list'
|
gem 'acts_as_list', path: 'gems/acts_as_list'
|
||||||
gem 'adheres_to_policy', path: 'gems/adheres_to_policy'
|
gem 'adheres_to_policy', path: 'gems/adheres_to_policy'
|
||||||
|
|
|
@ -54,10 +54,6 @@ class Quizzes::Quiz < ActiveRecord::Base
|
||||||
belongs_to :assignment
|
belongs_to :assignment
|
||||||
belongs_to :assignment_group
|
belongs_to :assignment_group
|
||||||
|
|
||||||
def self.polymorphic_names
|
|
||||||
[self.base_class.name, "Quiz"]
|
|
||||||
end
|
|
||||||
|
|
||||||
EXPORTABLE_ATTRIBUTES = [
|
EXPORTABLE_ATTRIBUTES = [
|
||||||
:id, :title, :description, :quiz_data, :points_possible, :context_id,
|
:id, :title, :description, :quiz_data, :points_possible, :context_id,
|
||||||
:context_type, :assignment_id, :workflow_state, :shuffle_answers,
|
:context_type, :assignment_id, :workflow_state, :shuffle_answers,
|
||||||
|
|
|
@ -21,10 +21,6 @@ require 'sanitize'
|
||||||
class Quizzes::QuizSubmission < ActiveRecord::Base
|
class Quizzes::QuizSubmission < ActiveRecord::Base
|
||||||
self.table_name = 'quiz_submissions'
|
self.table_name = 'quiz_submissions'
|
||||||
|
|
||||||
def self.polymorphic_names
|
|
||||||
[self.name, "QuizSubmission"]
|
|
||||||
end
|
|
||||||
|
|
||||||
include Workflow
|
include Workflow
|
||||||
|
|
||||||
attr_accessible :quiz, :user, :temporary_user_code, :submission_data, :score_before_regrade, :has_seen_results
|
attr_accessible :quiz, :user, :temporary_user_code, :submission_data, :score_before_regrade, :has_seen_results
|
||||||
|
|
|
@ -640,6 +640,92 @@ if CANVAS_RAILS3
|
||||||
super
|
super
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# copy/paste from Rails 3, with addition of applying the scope_chain (copy/paste from Rails 4)
|
||||||
|
def add_constraints(scope)
|
||||||
|
tables = construct_tables
|
||||||
|
|
||||||
|
chain.each_with_index do |reflection, i|
|
||||||
|
table, foreign_table = tables.shift, tables.first
|
||||||
|
|
||||||
|
if reflection.source_macro == :has_and_belongs_to_many
|
||||||
|
join_table = tables.shift
|
||||||
|
|
||||||
|
scope = scope.joins(join(
|
||||||
|
join_table,
|
||||||
|
table[reflection.association_primary_key].
|
||||||
|
eq(join_table[reflection.association_foreign_key])
|
||||||
|
))
|
||||||
|
|
||||||
|
table, foreign_table = join_table, tables.first
|
||||||
|
end
|
||||||
|
|
||||||
|
if reflection.source_macro == :belongs_to
|
||||||
|
if reflection.options[:polymorphic]
|
||||||
|
key = reflection.association_primary_key(klass)
|
||||||
|
else
|
||||||
|
key = reflection.association_primary_key
|
||||||
|
end
|
||||||
|
|
||||||
|
foreign_key = reflection.foreign_key
|
||||||
|
else
|
||||||
|
key = reflection.foreign_key
|
||||||
|
foreign_key = reflection.active_record_primary_key
|
||||||
|
end
|
||||||
|
|
||||||
|
conditions = self.conditions[i]
|
||||||
|
|
||||||
|
if reflection == chain.last
|
||||||
|
scope = scope.where(table[key].eq(owner[foreign_key]))
|
||||||
|
|
||||||
|
if reflection.type
|
||||||
|
scope = scope.where(table[reflection.type].eq(owner.class.base_class.name))
|
||||||
|
end
|
||||||
|
|
||||||
|
conditions.each do |condition|
|
||||||
|
if options[:through] && condition.is_a?(Hash)
|
||||||
|
condition = disambiguate_condition(table, condition)
|
||||||
|
end
|
||||||
|
|
||||||
|
scope = scope.where(interpolate(condition))
|
||||||
|
end
|
||||||
|
else
|
||||||
|
constraint = table[key].eq(foreign_table[foreign_key])
|
||||||
|
|
||||||
|
if reflection.type
|
||||||
|
type = chain[i + 1].klass.base_class.name
|
||||||
|
constraint = constraint.and(table[reflection.type].eq(type))
|
||||||
|
end
|
||||||
|
|
||||||
|
scope = scope.joins(join(foreign_table, constraint))
|
||||||
|
|
||||||
|
unless conditions.empty?
|
||||||
|
scope = scope.where(sanitize(conditions, table))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# rails 4 part
|
||||||
|
is_first_chain = i == 0
|
||||||
|
klass = is_first_chain ? self.klass : reflection.klass
|
||||||
|
|
||||||
|
self.reflection.scope_chain[i].each do |scope_chain_item|
|
||||||
|
item = klass.unscoped.instance_exec(&scope_chain_item)
|
||||||
|
|
||||||
|
if scope_chain_item == self.reflection.scope
|
||||||
|
scope = scope.merge(item.except(:where, :includes))
|
||||||
|
end
|
||||||
|
|
||||||
|
if is_first_chain
|
||||||
|
scope = scope.includes(*item.includes_values)
|
||||||
|
end
|
||||||
|
|
||||||
|
scope.where_values += item.where_values
|
||||||
|
scope.order_values |= item.order_values
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
scope
|
||||||
|
end
|
||||||
end
|
end
|
||||||
ActiveRecord::Associations::AssociationScope.prepend(RelationForAssociationScope)
|
ActiveRecord::Associations::AssociationScope.prepend(RelationForAssociationScope)
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,20 @@
|
||||||
|
class FixDeprecatedPolymorphicNames < ActiveRecord::Migration
|
||||||
|
tag :predeploy
|
||||||
|
disable_ddl_transaction!
|
||||||
|
|
||||||
|
def up
|
||||||
|
reflections = [Quizzes::Quiz, Quizzes::QuizSubmission].map do |klass|
|
||||||
|
klass.reflections.values.select { |r| r.macro == :has_many && r.options[:as] }
|
||||||
|
end
|
||||||
|
reflections.flatten!
|
||||||
|
reflections.group_by(&:klass).each do |(klass, klass_reflections)|
|
||||||
|
klass.find_ids_in_ranges(batch_size: 10000) do |min_id, max_id|
|
||||||
|
klass_reflections.each do |reflection|
|
||||||
|
klass.where(id: min_id..max_id,
|
||||||
|
reflection.type => reflection.active_record.name.sub("Quizzes::", "")).
|
||||||
|
update_all(reflection.type => reflection.active_record.name)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -1,10 +0,0 @@
|
||||||
source 'https://rubygems.org'
|
|
||||||
gemspec
|
|
||||||
|
|
||||||
require File.expand_path("../../../config/canvas_rails4", __FILE__)
|
|
||||||
|
|
||||||
if CANVAS_RAILS3
|
|
||||||
gem 'activerecord', '~> 3.2.0'
|
|
||||||
else
|
|
||||||
gem 'activerecord', '~> 4.0.0'
|
|
||||||
end
|
|
|
@ -1,2 +0,0 @@
|
||||||
require "bundler/gem_tasks"
|
|
||||||
|
|
|
@ -1,26 +0,0 @@
|
||||||
# coding: utf-8
|
|
||||||
lib = File.expand_path('../lib', __FILE__)
|
|
||||||
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
|
||||||
|
|
||||||
Gem::Specification.new do |spec|
|
|
||||||
spec.name = "active_polymorph"
|
|
||||||
spec.version = "0.0.1"
|
|
||||||
spec.authors = ["Anthus Williams"]
|
|
||||||
spec.email = ["aj@instructure.com"]
|
|
||||||
spec.summary = %q{Support for polymorphic names in ActiveRecord has_many associations}
|
|
||||||
spec.homepage = "https://github.com/instructure/canvas-lms"
|
|
||||||
spec.license = "AGPL"
|
|
||||||
|
|
||||||
spec.files = Dir.glob("{lib,spec}/**/*") + %w(Rakefile test.sh)
|
|
||||||
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
|
||||||
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
|
||||||
spec.require_paths = ["lib"]
|
|
||||||
|
|
||||||
spec.add_dependency "activerecord", ">= 3.2", "< 4.1"
|
|
||||||
|
|
||||||
spec.add_development_dependency "bundler", "~> 1.5"
|
|
||||||
spec.add_development_dependency "rake"
|
|
||||||
spec.add_development_dependency "rspec", "2.99.0"
|
|
||||||
spec.add_development_dependency "sqlite3"
|
|
||||||
end
|
|
||||||
|
|
|
@ -1,145 +0,0 @@
|
||||||
require 'active_record'
|
|
||||||
|
|
||||||
class ActiveRecord::Base
|
|
||||||
def self.polymorphic_names
|
|
||||||
[self.base_class.name]
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
module ActiveRecord
|
|
||||||
class Relation
|
|
||||||
# this method prevents ActiveRecord from attempting to constantize the polymorphic_names array as part of the build_associations process
|
|
||||||
def scope_for_create_with_polymorphic_names
|
|
||||||
scope = scope_for_create_without_polymorphic_names
|
|
||||||
if default_scoped?
|
|
||||||
reflect_on_polymorphic_associations.each do |assoc|
|
|
||||||
# since all class names in are returned in select queries (via self.polymorphic_names) it is ok to just take the first element of the array (rather than trying to constantize the array itself)
|
|
||||||
# still, in future it would be better to devise some way of declaring a canonical form for the create scope
|
|
||||||
# (e.g. select queries should retrieve all instances of PreRefactoredClassName and PostRefactoredClassName, but insert queries should always prefer the latter)
|
|
||||||
scope[assoc.foreign_type] = scope[assoc.foreign_type].first if scope[assoc.foreign_type].is_a?(Array)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
scope
|
|
||||||
end
|
|
||||||
alias_method_chain :scope_for_create, :polymorphic_names
|
|
||||||
|
|
||||||
def reflect_on_polymorphic_associations
|
|
||||||
reflect_on_all_associations.select{ |assoc| assoc.options[:polymorphic] }
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
class Associations::AssociationScope
|
|
||||||
def add_constraints(scope)
|
|
||||||
tables = construct_tables
|
|
||||||
|
|
||||||
chain.each_with_index do |reflection, i|
|
|
||||||
table, foreign_table = tables.shift, tables.first
|
|
||||||
|
|
||||||
if reflection.source_macro == :has_and_belongs_to_many
|
|
||||||
join_table = tables.shift
|
|
||||||
|
|
||||||
scope = scope.joins(join(
|
|
||||||
join_table,
|
|
||||||
table[reflection.association_primary_key].
|
|
||||||
eq(join_table[reflection.association_foreign_key])
|
|
||||||
))
|
|
||||||
|
|
||||||
table, foreign_table = join_table, tables.first
|
|
||||||
end
|
|
||||||
|
|
||||||
if reflection.source_macro == :belongs_to
|
|
||||||
if reflection.options[:polymorphic]
|
|
||||||
key = reflection.association_primary_key(klass)
|
|
||||||
else
|
|
||||||
key = reflection.association_primary_key
|
|
||||||
end
|
|
||||||
|
|
||||||
foreign_key = reflection.foreign_key
|
|
||||||
else
|
|
||||||
key = reflection.foreign_key
|
|
||||||
foreign_key = reflection.active_record_primary_key
|
|
||||||
end
|
|
||||||
|
|
||||||
conditions = CANVAS_RAILS3 ? self.conditions[i] : []
|
|
||||||
|
|
||||||
if reflection == chain.last
|
|
||||||
bind_val = CANVAS_RAILS3 ? owner[foreign_key] :
|
|
||||||
bind(scope, table.table_name, key.to_s, owner[foreign_key])
|
|
||||||
scope = scope.where(table[key].eq(bind_val))
|
|
||||||
|
|
||||||
if reflection.type
|
|
||||||
types = owner.class.polymorphic_names
|
|
||||||
types = types.first if types.length == 1
|
|
||||||
scope = scope.where(table.name => {table[reflection.type].name => types})
|
|
||||||
end
|
|
||||||
|
|
||||||
conditions.each do |condition|
|
|
||||||
if options[:through] && condition.is_a?(Hash)
|
|
||||||
condition = disambiguate_condition(table, condition)
|
|
||||||
end
|
|
||||||
|
|
||||||
scope = scope.where(interpolate(condition))
|
|
||||||
end
|
|
||||||
|
|
||||||
else
|
|
||||||
constraint = table[key].eq(foreign_table[foreign_key])
|
|
||||||
|
|
||||||
if reflection.type
|
|
||||||
types = chain[i + 1].klass.polymorphic_names
|
|
||||||
types = types.first if types.length == 1
|
|
||||||
constraint = constraint.and(table.name => {table[reflection.type].name => types})
|
|
||||||
end
|
|
||||||
|
|
||||||
scope = scope.joins(join(foreign_table, constraint))
|
|
||||||
|
|
||||||
unless conditions.empty?
|
|
||||||
scope = scope.where(sanitize(conditions, table))
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
if !CANVAS_RAILS3
|
|
||||||
is_first_chain = i == 0
|
|
||||||
klass = is_first_chain ? self.klass : reflection.klass
|
|
||||||
|
|
||||||
# Exclude the scope of the association itself, because that
|
|
||||||
# was already merged in the #scope method.
|
|
||||||
self.reflection.scope_chain[i].each do |scope_chain_item|
|
|
||||||
item = eval_scope(klass, scope_chain_item)
|
|
||||||
|
|
||||||
if scope_chain_item == self.reflection.scope
|
|
||||||
scope.merge! item.except(:where, :includes)
|
|
||||||
end
|
|
||||||
|
|
||||||
if is_first_chain
|
|
||||||
scope.includes! item.includes_values
|
|
||||||
end
|
|
||||||
|
|
||||||
scope.where_values += item.where_values
|
|
||||||
scope.order_values |= item.order_values
|
|
||||||
end
|
|
||||||
elsif self.reflection.respond_to?(:scope_chain)
|
|
||||||
# rails 3 supporting rails 4 style scope on associations
|
|
||||||
is_first_chain = i == 0
|
|
||||||
klass = is_first_chain ? self.klass : reflection.klass
|
|
||||||
|
|
||||||
self.reflection.scope_chain[i].each do |scope_chain_item|
|
|
||||||
item = klass.unscoped.instance_exec(&scope_chain_item)
|
|
||||||
|
|
||||||
if scope_chain_item == self.reflection.scope
|
|
||||||
scope = scope.merge(item.except(:where, :includes))
|
|
||||||
end
|
|
||||||
|
|
||||||
if is_first_chain
|
|
||||||
scope = scope.includes(*item.includes_values)
|
|
||||||
end
|
|
||||||
|
|
||||||
scope.where_values += item.where_values
|
|
||||||
scope.order_values |= item.order_values
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
scope
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
|
@ -1,152 +0,0 @@
|
||||||
#
|
|
||||||
# Copyright (C) 2014 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 "active_polymorph"
|
|
||||||
|
|
||||||
describe ActiveRecord do
|
|
||||||
|
|
||||||
describe ActiveRecord::Base do
|
|
||||||
it "should respond to polymorphic_names" do
|
|
||||||
ActiveRecord::Base.respond_to?(:polymorphic_names).should be_true
|
|
||||||
end
|
|
||||||
|
|
||||||
it "should by default return its own class" do
|
|
||||||
class SomeClass < ActiveRecord::Base; end
|
|
||||||
SomeClass.polymorphic_names.should == ["SomeClass"]
|
|
||||||
end
|
|
||||||
|
|
||||||
it "should return defined polymorphic names" do
|
|
||||||
class SomeClass < ActiveRecord::Base
|
|
||||||
def self.polymorphic_names
|
|
||||||
[self.base_class.name, "SomeOtherClass"]
|
|
||||||
end
|
|
||||||
end
|
|
||||||
SomeClass.polymorphic_names.sort.should == ["SomeClass", "SomeOtherClass"]
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
describe ActiveRecord::Associations do
|
|
||||||
before(:all) do
|
|
||||||
ActiveRecord::Base.establish_connection(
|
|
||||||
:adapter => 'sqlite3',
|
|
||||||
:database => ':memory:'
|
|
||||||
)
|
|
||||||
|
|
||||||
ActiveRecord::Schema.define do
|
|
||||||
create_table :things, :force => true do |t|
|
|
||||||
t.integer :context_id
|
|
||||||
t.string :context_type
|
|
||||||
end
|
|
||||||
|
|
||||||
create_table :normal_contexts, :force => true do |t|
|
|
||||||
t.string :something_meaningful
|
|
||||||
end
|
|
||||||
|
|
||||||
end
|
|
||||||
|
|
||||||
class Thing < ActiveRecord::Base
|
|
||||||
belongs_to :context, :polymorphic => true
|
|
||||||
end
|
|
||||||
|
|
||||||
class NormalContext < ActiveRecord::Base
|
|
||||||
has_many :things, :as => :context
|
|
||||||
|
|
||||||
def self.polymorphic_names
|
|
||||||
[self.base_class.name, "Namespaced::ParaNormalContext"]
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
module Namespaced
|
|
||||||
class ParaNormalContext < ::ActiveRecord::Base
|
|
||||||
self.table_name = "normal_contexts"
|
|
||||||
has_many :things, :as => :context
|
|
||||||
|
|
||||||
def self.polymorphic_names
|
|
||||||
[self.base_class.name, "NormalContext"]
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
describe "HasManyAssociation" do
|
|
||||||
before(:each) do
|
|
||||||
@normal_context = NormalContext.create!(something_meaningful: "This is a holy scripture for a small tribe in Paraguay")
|
|
||||||
@namespaced_context = Namespaced::ParaNormalContext.find(@normal_context.id)
|
|
||||||
@thing_a = @normal_context.things.create!
|
|
||||||
@thing_b = @namespaced_context.things.create!
|
|
||||||
end
|
|
||||||
|
|
||||||
it "should find records bearing polymorphic names" do
|
|
||||||
@normal_context.reload.things.should == [@thing_a,@thing_b]
|
|
||||||
@namespaced_context.reload.things.should == [@thing_a,@thing_b]
|
|
||||||
end
|
|
||||||
|
|
||||||
it "should not find records not bearing polymorphic names" do
|
|
||||||
ActiveRecord::Base.connection.execute("UPDATE things SET context_type = 'NotReallyAThing' WHERE id = #{@thing_a.id}")
|
|
||||||
@normal_context.reload.things.should == [@thing_b]
|
|
||||||
@namespaced_context.reload.things.should == [@thing_b]
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
it "should use polymorphic names in count queries" do
|
|
||||||
@normal_context.reload.things.count.should == 2
|
|
||||||
ActiveRecord::Base.connection.execute("UPDATE things SET context_type = 'NotReallyAThing' WHERE id = #{@thing_a.id}")
|
|
||||||
@normal_context.reload.things.count.should == 1
|
|
||||||
end
|
|
||||||
|
|
||||||
it "should prefer custom finder_sql if provided" do
|
|
||||||
NormalContext.class_eval do
|
|
||||||
has_many :things, :as => :context, :finder_sql =>
|
|
||||||
proc{ "SELECT * FROM things WHERE context_id = #{id} AND context_type = '#{self.class.base_class.name}'" }
|
|
||||||
end
|
|
||||||
|
|
||||||
@namespaced_context.reload.things.should == [@thing_a, @thing_b]
|
|
||||||
@normal_context.reload.things.should == [@thing_a]
|
|
||||||
end
|
|
||||||
|
|
||||||
it "should prefer custom counter_sql if provided" do
|
|
||||||
NormalContext.class_eval do
|
|
||||||
has_many :things, :as => :context, :counter_sql =>
|
|
||||||
proc{ "SELECT COUNT(*) FROM things WHERE context_id = #{id} AND context_type = '#{self.class.base_class.name}'" }
|
|
||||||
end
|
|
||||||
|
|
||||||
@namespaced_context.reload.things.count.should == 2
|
|
||||||
@normal_context.reload.things.count.should == 1
|
|
||||||
end
|
|
||||||
|
|
||||||
it "should count/find correctly with additional where/find scopes" do
|
|
||||||
@normal_context.things.find(@thing_a.id).should == @thing_a
|
|
||||||
@normal_context.things.where(context_type: "Namespaced::ParaNormalContext").first.should == @thing_b
|
|
||||||
scope = @normal_context.things.where(context_type: "Namespaced::ParaNormalContext")
|
|
||||||
scope.count.should == 1
|
|
||||||
scope.should == [@thing_b]
|
|
||||||
end
|
|
||||||
|
|
||||||
it "should work with pluck" do
|
|
||||||
@normal_context.things.pluck(:id).should == [@thing_a.id, @thing_b.id]
|
|
||||||
end
|
|
||||||
|
|
||||||
it "should work with build_associations" do
|
|
||||||
thing_c = @normal_context.things.build
|
|
||||||
thing_c.save!
|
|
||||||
@normal_context.reload.things.should == [@thing_a, @thing_b, thing_c]
|
|
||||||
end
|
|
||||||
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
|
@ -1,15 +0,0 @@
|
||||||
#!/bin/bash
|
|
||||||
result=0
|
|
||||||
|
|
||||||
echo "################ active_polymorph ################"
|
|
||||||
bundle check || bundle install
|
|
||||||
bundle exec rspec spec
|
|
||||||
let result=$result+$?
|
|
||||||
|
|
||||||
if [ $result -eq 0 ]; then
|
|
||||||
echo "SUCCESS"
|
|
||||||
else
|
|
||||||
echo "FAILURE"
|
|
||||||
fi
|
|
||||||
|
|
||||||
exit $result
|
|
|
@ -518,7 +518,6 @@ describe UserMerge do
|
||||||
qs1 = @quiz_submission
|
qs1 = @quiz_submission
|
||||||
quiz_with_graded_submission([], user: user2)
|
quiz_with_graded_submission([], user: user2)
|
||||||
qs2 = @quiz_submission
|
qs2 = @quiz_submission
|
||||||
Version.where(:versionable_type => "Quizzes::QuizSubmission", :versionable_id => qs2).update_all(:versionable_type => "QuizSubmission")
|
|
||||||
|
|
||||||
expect(qs1.versions).to be_present
|
expect(qs1.versions).to be_present
|
||||||
qs1.versions.each{ |v| expect(v.model.user_id).to eql(user2.id) }
|
qs1.versions.each{ |v| expect(v.model.user_id).to eql(user2.id) }
|
||||||
|
|
|
@ -1701,39 +1701,6 @@ describe Quizzes::Quiz do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'with versioning' do
|
|
||||||
let_once(:quiz) { @course.quizzes.create! title: 'Test Quiz' }
|
|
||||||
describe "#versions" do
|
|
||||||
it "finds the versions of both namespaced and non-namespaced quizzes" do
|
|
||||||
quiz.title = "Renamed Test Quiz"
|
|
||||||
quiz.save
|
|
||||||
expect(quiz.versions.count).to eq 2
|
|
||||||
|
|
||||||
Version.where(versionable_id: quiz, versionable_type: 'Quizzes::Quiz').update_all("versionable_type='Quiz'")
|
|
||||||
|
|
||||||
expect(Quizzes::Quiz.find(quiz).versions.count).to eq 2
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
describe '#context_module_tags' do
|
|
||||||
it "finds both namespaced and non-namespaced content tags" do
|
|
||||||
quiz = @course.quizzes.create! title: 'Test Quiz'
|
|
||||||
mod = @course.context_modules.create! name: 'Test Module'
|
|
||||||
tag1 = mod.add_item id: quiz.id, type: 'quiz'
|
|
||||||
tag2 = mod.add_item id: quiz.id, type: 'quiz'
|
|
||||||
tag3 = mod.add_item id: quiz.id, type: 'quiz'
|
|
||||||
ContentTag.where(id: tag2).update_all(content_type: 'Quiz')
|
|
||||||
tag3.destroy
|
|
||||||
expect(quiz.context_module_tags.pluck(:id).sort).to eql [tag1.id, tag2.id].sort
|
|
||||||
end
|
|
||||||
|
|
||||||
it "should act like an association" do
|
|
||||||
quiz = @course.quizzes.create! title: 'Test Quiz'
|
|
||||||
expect { quiz.context_module_tags.loaded? }.not_to raise_error
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
describe 'differentiated assignments' do
|
describe 'differentiated assignments' do
|
||||||
context 'visible_to_user?' do
|
context 'visible_to_user?' do
|
||||||
before :once do
|
before :once do
|
||||||
|
|
|
@ -1490,51 +1490,6 @@ describe Quizzes::QuizSubmission do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
context "with versioning" do
|
|
||||||
before(:each) do
|
|
||||||
student_in_course
|
|
||||||
assignment_quiz([])
|
|
||||||
qd = multiple_choice_question_data
|
|
||||||
@quiz.quiz_data = [qd]
|
|
||||||
@quiz.points_possible = qd[:points_possible]
|
|
||||||
@quiz.save!
|
|
||||||
end
|
|
||||||
|
|
||||||
describe "#versions" do
|
|
||||||
it "finds the versions with both namespaced and non-namespaced quizzes" do
|
|
||||||
qs = @quiz.generate_submission(@student)
|
|
||||||
qs.submission_data = { "question_1" => "2405" }
|
|
||||||
Quizzes::SubmissionGrader.new(qs).grade_submission
|
|
||||||
|
|
||||||
qs = @quiz.generate_submission(@student)
|
|
||||||
qs.submission_data = { "question_1" => "8544" }
|
|
||||||
Quizzes::SubmissionGrader.new(qs).grade_submission
|
|
||||||
|
|
||||||
expect(qs.versions.count).to eq 2
|
|
||||||
Version.update_all("versionable_type='QuizSubmission'","versionable_id=#{qs.id} AND versionable_type='Quizzes::QuizSubmission'")
|
|
||||||
expect(Quizzes::QuizSubmission.find(qs).versions.count).to eq 2
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
context "with attachments" do
|
|
||||||
before(:each) do
|
|
||||||
course_with_student_logged_in :active_all => true
|
|
||||||
course_quiz !!:active
|
|
||||||
@qs = @quiz.generate_submission @user
|
|
||||||
create_attachment_for_file_upload_submission!(@qs)
|
|
||||||
end
|
|
||||||
|
|
||||||
describe "#attachments" do
|
|
||||||
it "finds the attachment with both namespaced and non-namespaced quizzes" do
|
|
||||||
expect(Quizzes::QuizSubmission.find(@qs).attachments.count).to eq 1
|
|
||||||
|
|
||||||
Attachment.update_all("context_type='QuizSubmission'","context_id=#{@qs.id} AND context_type='Quizzes::QuizSubmission'")
|
|
||||||
expect(Quizzes::QuizSubmission.find(@qs).attachments.count).to eq 1
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
describe '#points_possible_at_submission_time' do
|
describe '#points_possible_at_submission_time' do
|
||||||
it 'should work' do
|
it 'should work' do
|
||||||
quiz_with_graded_submission([
|
quiz_with_graded_submission([
|
||||||
|
|
Loading…
Reference in New Issue