rails 5.2

closes #CORE-1301 #CORE-1302

Change-Id: I687132b066d12cf35e3c7a593dff9b2a91337f33
Reviewed-on: https://gerrit.instructure.com/147220
Reviewed-by: Cody Cutrer <cody@instructure.com>
Tested-by: Jenkins
Product-Review: James Williams  <jamesw@instructure.com>
QA-Review: James Williams  <jamesw@instructure.com>
This commit is contained in:
James Williams 2018-04-17 09:07:21 -06:00
parent 667c7dee19
commit 7423e4fb94
58 changed files with 218 additions and 115 deletions

View File

@ -18,7 +18,7 @@
if CANVAS_RAILS5_1
gem 'rails', '5.1.5'
else
gem 'rails', '5.2.0.rc2'
gem 'rails', '5.2.0'
end
gem 'rack', '2.0.4'
@ -32,13 +32,13 @@ gem 'rails-observers', '0.1.5'
gem 'builder', '3.2.3'
gem 'tzinfo', '1.2.5'
gem 'encrypted_cookie_store-instructure', '1.2.7', require: 'encrypted_cookie_store'
gem 'encrypted_cookie_store-instructure', '1.2.8', require: 'encrypted_cookie_store'
gem 'active_model_serializers', '0.9.0alpha1',
github: 'rails-api/active_model_serializers', ref: '61882e1e4127facfe92e49057aec71edbe981829'
gem 'authlogic', '3.6.1'
gem 'authlogic', '4.0.1'
gem 'scrypt', '3.0.5'
gem 'active_model-better_errors', '1.6.7', require: 'active_model/better_errors'
gem 'switchman', '1.11.7'
gem 'switchman', '1.12.2'
gem 'open4', '1.3.4', require: false
gem 'folio-pagination', '0.0.12', require: 'folio/rails'
# for folio, see the folio README
@ -110,7 +110,7 @@ gem 'rubycas-client', '2.3.9', require: false
gem 'rubyzip', '1.2.1', require: 'zip'
gem 'safe_yaml', '1.0.4', require: false
gem 'sanitize', '2.1.0', require: false
gem 'shackles', '1.4.0'
gem 'shackles', '1.4.1'
gem 'useragent', '0.16.10', require: false
@ -118,7 +118,7 @@ gem 'crocodoc-ruby', '0.0.1', require: false
gem 'sentry-raven', '2.7.2', require: false
gem 'canvas_statsd', '2.0.4'
gem 'statsd-ruby', '1.4.0', require: false
gem 'aroi', '0.0.5', require: false
gem 'aroi', '0.0.6', require: false
gem 'gepub', '0.7.0beta4'
gem 'imperium', '0.3.0', require: false
gem 'academic_benchmarks', '0.0.10', require: false

View File

@ -155,7 +155,7 @@ class AccountsController < ApplicationController
if @current_user
account_ids = Rails.cache.fetch(['admin_enrollment_course_account_ids', @current_user].cache_key) do
Account.joins(:courses => :enrollments).merge(
@current_user.enrollments.admin.shard(@current_user).except(:select)
@current_user.enrollments.admin.shard(@current_user).except(:select, :joins)
).select("accounts.id").distinct.pluck(:id).map{|id| Shard.global_id_for(id)}
end
course_accounts = BookmarkedCollection.wrap(Account::Bookmarker, Account.where(:id => account_ids))

View File

@ -801,7 +801,7 @@ class ApplicationController < ActionController::Base
courses = Course.
shard(opts[:cross_shard] ? @context.in_region_associated_shards : Shard.current).
joins(enrollments: :enrollment_state).
merge(enrollment_scope).
merge(enrollment_scope.except(:joins)).
where(id: course_ids)
end
if include_groups
@ -812,7 +812,7 @@ class ApplicationController < ActionController::Base
courses = Course.
shard(opts[:cross_shard] ? @context.in_region_associated_shards : Shard.current).
joins(enrollments: :enrollment_state).
merge(enrollment_scope)
merge(enrollment_scope.except(:joins))
end
groups = []
@ -1096,7 +1096,7 @@ class ApplicationController < ActionController::Base
def set_no_cache_headers
response.headers["Pragma"] = "no-cache"
response.headers["Cache-Control"] = "no-cache, no-store, max-age=0, must-revalidate"
response.headers["Cache-Control"] = "no-cache, no-store"
end
def clear_cached_contexts

View File

@ -487,7 +487,7 @@ class Account < ActiveRecord::Base
end
def fast_course_base(opts = {})
opts[:order] ||= "#{Course.best_unicode_collation_key("courses.name")} ASC"
opts[:order] ||= Course.best_unicode_collation_key("courses.name").asc
columns = "courses.id, courses.name, courses.workflow_state, courses.course_code, courses.sis_source_id, courses.enrollment_term_id"
associated_courses = self.associated_courses(
:include_crosslisted_courses => opts[:include_crosslisted_courses]

View File

@ -368,7 +368,7 @@ class CommunicationChannel < ActiveRecord::Base
# Add twitter and yo (in that order) if the user's account is setup for them.
rank_order << TYPE_TWITTER if twitter_service
self.unretired.where('communication_channels.path_type IN (?)', rank_order).
order("#{self.rank_sql(rank_order, 'communication_channels.path_type')} ASC, communication_channels.position asc").to_a
order(Arel.sql("#{self.rank_sql(rank_order, 'communication_channels.path_type')} ASC, communication_channels.position asc")).to_a
end
scope :include_policies, -> { preload(:notification_policies) }

View File

@ -554,7 +554,7 @@ class ContextExternalTool < ActiveRecord::Base
scope = ContextExternalTool.shard(context.shard).polymorphic_where(context: contexts).active
scope = scope.placements(*placements)
scope = scope.selectable if Canvas::Plugin.value_to_boolean(options[:selectable])
scope.order("#{ContextExternalTool.best_unicode_collation_key('context_external_tools.name')}, context_external_tools.id")
scope.order(ContextExternalTool.best_unicode_collation_key('context_external_tools.name') + Arel.sql(", context_external_tools.id"))
end
end

View File

@ -1873,7 +1873,7 @@ class Course < ActiveRecord::Base
# order by course_section_id<>section.id so that if there *is* an existing enrollment for this section, we get it (false orders before true)
e = self.all_enrollments.
where(user_id: user, type: type, role_id: role.id, associated_user_id: associated_user_id).
order("course_section_id<>#{section.id}").
order(Arel.sql("course_section_id<>#{section.id}")).
first
end
if e && (!e.active? || opts[:force_update])

View File

@ -109,10 +109,10 @@ class LearningOutcomeResult < ActiveRecord::Base
scope :for_user, lambda { |user| where(:user_id => user) }
scope :custom_ordering, lambda { |param|
orders = {
'recent' => "assessed_at DESC",
'highest' => "score DESC",
'oldest' => "score ASC",
'default' => "assessed_at DESC"
'recent' => {:assessed_at => :desc},
'highest' => {:score => :desc},
'oldest' => {:score => :asc},
'default' => {:assessed_at => :desc}
}
order_clause = orders[param] || orders['default']
order(order_clause)

View File

@ -447,7 +447,7 @@ class PageView < ActiveRecord::Base
# this could run into problems if one account gets more than
# batch_size page views created in the second on this boundary
finder_sql = PageView.where("account_id = ? AND created_at >= ?", account_id, last_created_at).
order("created_at asc").limit(batch_size).to_sql
order(:created_at => :asc).limit(batch_size).to_sql
# query just the raw attributes, don't instantiate AR objects
rows = PageView.connection.select_all(finder_sql).to_a

View File

@ -115,7 +115,7 @@ class SisPseudonym
relation.where.not(sis_user_id: nil)
else
# false sorts before true
relation.order("sis_user_id IS NULL")
relation.order(Arel.sql("sis_user_id IS NULL"))
end
relation.primary_shard.activate do
relation = relation.order(Pseudonym.best_unicode_collation_key(:unique_id))

View File

@ -1608,7 +1608,7 @@ class User < ActiveRecord::Base
end
scope.select("courses.*, enrollments.id AS primary_enrollment_id, enrollments.type AS primary_enrollment_type, enrollments.role_id AS primary_enrollment_role_id, #{Enrollment.type_rank_sql} AS primary_enrollment_rank, enrollments.workflow_state AS primary_enrollment_state, enrollments.created_at AS primary_enrollment_date").
order("courses.id, #{Enrollment.type_rank_sql}, #{Enrollment.state_rank_sql}").
order(Arel.sql("courses.id, #{Enrollment.type_rank_sql}, #{Enrollment.state_rank_sql}")).
distinct_on(:id).shard(shards).to_a
end
result.dup

View File

@ -160,12 +160,22 @@ module CanvasRails
end
module TypeMapInitializerExtensions
def query_conditions_for_initial_load(type_map)
known_type_names = type_map.keys.map { |n| "'#{n}'" } + type_map.keys.map { |n| "'_#{n}'" }
<<-SQL % [known_type_names.join(", "),]
WHERE
t.typname IN (%s)
SQL
if CANVAS_RAILS5_1
def query_conditions_for_initial_load(type_map)
known_type_names = type_map.keys.map { |n| "'#{n}'" } + type_map.keys.map { |n| "'_#{n}'" }
<<-SQL % [known_type_names.join(", "),]
WHERE
t.typname IN (%s)
SQL
end
else
def query_conditions_for_initial_load
known_type_names = @store.keys.map { |n| "'#{n}'" } + @store.keys.map { |n| "'_#{n}'" }
<<-SQL % [known_type_names.join(", "),]
WHERE
t.typname IN (%s)
SQL
end
end
end

View File

@ -407,7 +407,7 @@ class ActiveRecord::Base
end
def self.best_unicode_collation_key(col)
if ActiveRecord::Base.configurations[Rails.env]['adapter'] == 'postgresql'
val = if ActiveRecord::Base.configurations[Rails.env]['adapter'] == 'postgresql'
# For PostgreSQL, we can't trust a simple LOWER(column), with any collation, since
# Postgres just defers to the C library which is different for each platform. The best
# choice is the collkey function from pg_collkey which uses ICU to get a full unicode sort.
@ -431,6 +431,7 @@ class ActiveRecord::Base
else
col
end
Arel.sql(val)
end
def self.count_by_date(options = {})
@ -459,9 +460,10 @@ class ActiveRecord::Base
end
def self.rank_sql(ary, col)
ary.each_with_index.inject('CASE '){ |string, (values, i)|
sql = ary.each_with_index.inject('CASE '){ |string, (values, i)|
string << "WHEN #{col} IN (" << Array(values).map{ |value| connection.quote(value) }.join(', ') << ") THEN #{i} "
} << "ELSE #{ary.size} END"
Arel.sql(sql)
end
def self.rank_hash(ary)
@ -512,8 +514,7 @@ class ActiveRecord::Base
# set up class-specific getters/setters for a polymorphic association, e.g.
# belongs_to :context, polymorphic: [:course, :account]
def self.belongs_to(name, scope = nil, options={})
options = scope if scope.is_a?(Hash)
def self.belongs_to(name, scope = nil, **options)
if options[:polymorphic] == true
raise "Please pass an array of valid types for polymorphic associations. Use exhaustive: false if you really don't want to validate them"
end
@ -994,7 +995,7 @@ ActiveRecord::Relation.class_eval do
def find_ids_in_batches(options = {})
batch_size = options[:batch_size] || 1000
key = "#{quoted_table_name}.#{primary_key}"
scope = except(:select).select(key).reorder(key).limit(batch_size)
scope = except(:select).select(key).reorder(Arel.sql(key)).limit(batch_size)
ids = connection.select_values(scope.to_sql)
ids = ids.map(&:to_i) unless options[:no_integer_cast]
while ids.present?
@ -1064,14 +1065,23 @@ module UpdateAndDeleteWithJoins
sql = stmt.to_sql
binds = bound_attributes.map(&:value_for_database)
binds.map! { |value| connection.quote(value) }
collector = Arel::Collectors::Bind.new
arel.join_sources.each do |node|
connection.visitor.accept(node, collector)
if CANVAS_RAILS5_1
binds = bound_attributes.map(&:value_for_database)
binds.map! { |value| connection.quote(value) }
collector = Arel::Collectors::Bind.new
arel.join_sources.each do |node|
connection.visitor.accept(node, collector)
end
binds_in_join = collector.value.count { |x| x.is_a?(Arel::Nodes::BindParam) }
join_sql = collector.substitute_binds(binds).join
else
collector = connection.send(:collector)
arel.join_sources.each do |node|
connection.visitor.accept(node, collector)
end
join_sql = collector.value
end
binds_in_join = collector.value.count { |x| x.is_a?(Arel::Nodes::BindParam) }
join_sql = collector.substitute_binds(binds).join
tables, join_conditions = deconstruct_joins(join_sql)
unless tables.empty?
@ -1084,15 +1094,23 @@ module UpdateAndDeleteWithJoins
join_conditions.each { |join| scope = scope.where(join) }
# skip any binds that are used in the join
binds = scope.bound_attributes[binds_in_join..-1]
binds = binds.map(&:value_for_database)
binds.map! { |value| connection.quote(value) }
sql_string = Arel::Collectors::Bind.new
scope.arel.constraints.each do |node|
connection.visitor.accept(node, sql_string)
if CANVAS_RAILS5_1
binds = scope.bound_attributes[binds_in_join..-1]
binds = binds.map(&:value_for_database)
binds.map! { |value| connection.quote(value) }
sql_string = Arel::Collectors::Bind.new
scope.arel.constraints.each do |node|
connection.visitor.accept(node, sql_string)
end
where_sql = sql_string.substitute_binds(binds).join
else
collector = connection.send(:collector)
scope.arel.constraints.each do |node|
connection.visitor.accept(node, collector)
end
where_sql = collector.value
end
sql.concat('WHERE ' + sql_string.substitute_binds(binds).join)
sql.concat('WHERE ' + where_sql)
connection.update(sql, "#{name} Update")
end
@ -1111,16 +1129,25 @@ module UpdateAndDeleteWithJoins
scope = self
join_conditions.each { |join| scope = scope.where(join) }
binds = scope.bound_attributes
binds = binds.map(&:value_for_database)
binds.map! { |value| connection.quote(value) }
sql_string = Arel::Collectors::Bind.new
scope.arel.constraints.each do |node|
connection.visitor.accept(node, sql_string)
if CANVAS_RAILS5_1
binds = scope.bound_attributes
binds = binds.map(&:value_for_database)
binds.map! { |value| connection.quote(value) }
sql_string = Arel::Collectors::Bind.new
scope.arel.constraints.each do |node|
connection.visitor.accept(node, sql_string)
end
where_sql = sql_string.substitute_binds(binds).join
else
collector = connection.send(:collector)
scope.arel.constraints.each do |node|
connection.visitor.accept(node, collector)
end
where_sql = collector.value
end
sql.concat('WHERE ' + sql_string.substitute_binds(binds).join)
sql.concat('WHERE ' + where_sql)
connection.delete(sql, "SQL", scope.bind_values)
connection.delete(sql, "SQL", CANVAS_RAILS5_1 ? scope.bind_values : [])
end
end
ActiveRecord::Relation.prepend(UpdateAndDeleteWithJoins)
@ -1398,7 +1425,9 @@ end
module UnscopeCallbacks
def run_callbacks(*args)
scope = self.class.all.klass.unscoped
# workaround for a rails 5.2.0 problem where .all sometimes tries to merge in a current_scope with a `skip_query_cache_value` and explodes
# TODO: can undo it when this is fixed https://github.com/rails/rails/issues/32640
scope = (self.class.current_scope || self.class.all).klass.unscoped
scope.scoping { super }
end
end
@ -1491,7 +1520,11 @@ module DupArraysInMutationTracker
change
end
end
ActiveRecord::AttributeMutationTracker.prepend(DupArraysInMutationTracker)
if CANVAS_RAILS5_1
ActiveRecord::AttributeMutationTracker.prepend(DupArraysInMutationTracker)
else
ActiveModel::AttributeMutationTracker.prepend(DupArraysInMutationTracker)
end
module IgnoreOutOfSequenceMigrationDates
def current_migration_number(dirname)

View File

@ -39,8 +39,27 @@ module ActiveSupport::Cache
end
end
Store.prepend(RailsCacheShim)
unless CANVAS_RAILS5_1
module AllowMocksInStore
def should_compress?(*args)
if @value && Rails.env.test?
begin
marshaled_value
true
rescue TypeError => e
false
end
else
super
end
end
end
Entry.prepend(AllowMocksInStore)
end
end
module IgnoreMonkeyPatchesInDeprecations
def extract_callstack(callstack)
return _extract_callstack(callstack) if callstack.first.is_a?(String)

View File

@ -155,17 +155,21 @@ ActiveRecord::Base::DROPPED_COLUMNS = {
}.freeze
module DroppedColumns
def columns
@columns_with_dropped ||= super.reject { |c|
(ActiveRecord::Base::DROPPED_COLUMNS[self.table_name] || []).include?(c.name)
def columns_hash
@columns_hash_with_dropped ||= super.reject { |k, c|
(ActiveRecord::Base::DROPPED_COLUMNS[self.table_name] || []).include?(k)
}
end
def reset_column_information
@columns_with_dropped = nil
@columns_hash_with_dropped = nil
super
end
def define_attribute(name, *args)
super unless (ActiveRecord::Base::DROPPED_COLUMNS[self.table_name] || []).include?(name)
end
def instantiate(attributes, *args)
(ActiveRecord::Base::DROPPED_COLUMNS[self.table_name] || []).each do |attr|
attributes.delete(attr)

View File

@ -156,7 +156,11 @@ module PostgreSQLAdapterExtensions
desc_order_columns = inddef.scan(/(\w+) DESC/).flatten
orders = desc_order_columns.any? ? Hash[desc_order_columns.map {|order_column| [order_column, :desc]}] : {}
ActiveRecord::ConnectionAdapters::IndexDefinition.new(table_name, index_name, unique, column_names, [], orders)
if CANVAS_RAILS5_1
ActiveRecord::ConnectionAdapters::IndexDefinition.new(table_name, index_name, unique, column_names, [], orders)
else
ActiveRecord::ConnectionAdapters::IndexDefinition.new(table_name, index_name, unique, column_names, orders: orders)
end
end
end

View File

@ -144,7 +144,7 @@ Rails.application.config.after_initialize do
scope :in_current_region, -> do
@current_region_scope ||=
if !default.is_a?(self)
if !default.is_a?(Switchman::Shard)
# sharding isn't set up? maybe we're in tests, or a somehow degraded environment
# either way there's only one shard, and we always want to see it
[default]

View File

@ -14,7 +14,7 @@ Gem::Specification.new do |spec|
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
spec.require_paths = ["lib"]
spec.add_dependency "activesupport", ">= 3.2", "< 5.2"
spec.add_dependency "activesupport", ">= 3.2"
spec.add_development_dependency "bundler", "~>1.5"
spec.add_development_dependency "rake"

View File

@ -16,7 +16,7 @@ Gem::Specification.new do |spec|
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
spec.require_paths = ["lib"]
spec.add_dependency 'rails', ">= 3.2", "< 5.2"
spec.add_dependency 'rails', ">= 3.2"
spec.add_development_dependency "bundler", "~> 1.5"
spec.add_development_dependency "sqlite3"

View File

@ -14,7 +14,7 @@ Gem::Specification.new do |spec|
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
spec.require_paths = ["lib"]
spec.add_dependency 'rails', ">= 3.2", "< 5.2"
spec.add_dependency 'rails', ">= 3.2"
spec.add_dependency 'canvas_statsd', "~> 2.0"
spec.add_development_dependency "bundler", "~> 1.5"

View File

@ -15,5 +15,5 @@ Gem::Specification.new do |s|
s.files = Dir["{app,config,db,lib}/**/*"]
s.test_files = Dir["spec_canvas/**/*"]
s.add_dependency "rails", ">= 3.2", "< 5.2"
s.add_dependency "rails", ">= 3.2"
end

View File

@ -18,5 +18,5 @@ Gem::Specification.new do |spec|
spec.add_development_dependency "byebug"
spec.add_development_dependency "minitest"
spec.add_development_dependency "rake"
spec.add_development_dependency "activesupport", "< 5.2"
spec.add_development_dependency "activesupport"
end

View File

@ -16,7 +16,7 @@ Gem::Specification.new do |spec|
spec.add_dependency "folio-pagination", "~> 0.0.12"
spec.add_dependency "will_paginate", "~> 3.0"
spec.add_dependency "rails", ">= 3.2", "< 5.2"
spec.add_dependency "rails", ">= 3.2"
spec.add_dependency "paginated_collection"
spec.add_dependency "json_token"

View File

@ -81,7 +81,7 @@ module BookmarkedCollection
end
def order_by
@order_by ||= @columns.map { |col| column_order(col) }.join(', ')
@order_by ||= Arel.sql(@columns.map { |col| column_order(col) }.join(', '))
end
def column_order(col_name)

View File

@ -61,7 +61,9 @@ module BroadcastPolicy
other_attributes.write_from_database(key, value.value)
end
end
@mutations_before_last_save = ActiveRecord::AttributeMutationTracker.new(other_attributes)
@mutations_before_last_save = CANVAS_RAILS5_1 ?
ActiveRecord::AttributeMutationTracker.new(other_attributes) :
ActiveModel::AttributeMutationTracker.new(other_attributes)
end
yield
ensure

View File

@ -15,7 +15,7 @@ Gem::Specification.new do |spec|
spec.require_paths = ["lib"]
spec.add_dependency "tzinfo"
spec.add_dependency "activesupport", ">= 3.2", "< 5.2"
spec.add_dependency "activesupport", ">= 3.2"
spec.add_development_dependency "bundler", "~> 1.5"
spec.add_development_dependency "rake"

View File

@ -13,7 +13,7 @@ Gem::Specification.new do |spec|
spec.require_paths = ['lib']
spec.license = 'AGPL'
spec.add_dependency 'activerecord', '>= 3.2', '< 5.2'
spec.add_dependency 'activerecord', '>= 3.2'
spec.add_dependency 'pg', '>= 0.17', '< 2.0'
spec.add_development_dependency 'bundler', '~> 1.5'

View File

@ -110,6 +110,23 @@ module CanvasPartman::Concerns
end
end
def _insert_record(values)
if ::ActiveRecord.version >= Gem::Version.new("5.2")
begin
prev_table = @arel_table
prev_builder = @predicate_builder
@arel_table = arel_table_from_key_values(values)
@predicate_builder = nil
super
ensure
@arel_table = prev_table
@predicate_builder = prev_builder
end
else
super
end
end
# :nodoc:
def arel_table_from_key_values(attributes)
partition_table_name = infer_partition_table_name(attributes)
@ -136,7 +153,7 @@ module CanvasPartman::Concerns
# @return [String]
# The table name for the partition.
def infer_partition_table_name(attributes)
attr = attributes.detect { |(k, _v)| k.name == partitioning_field }
attr = attributes.detect { |(k, _v)| (k.is_a?(String) ? k : k.name) == partitioning_field }
if attr.nil? || attr[1].nil?
raise ArgumentError.new <<-ERROR

View File

@ -14,7 +14,7 @@ Gem::Specification.new do |spec|
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
spec.require_paths = ["lib"]
spec.add_dependency 'rails', ">= 3.2", "< 5.2"
spec.add_dependency 'rails', ">= 3.2"
spec.add_development_dependency "activerecord"
spec.add_development_dependency "bundler", "~> 1.5"

View File

@ -16,7 +16,7 @@ Gem::Specification.new do |spec|
spec.add_dependency "tzinfo"
spec.add_dependency "activesupport", ">= 3.2", "< 5.2"
spec.add_dependency "activesupport", ">= 3.2"
spec.add_development_dependency "bundler", "~> 1.5"
spec.add_development_dependency "rake"

View File

@ -20,7 +20,7 @@ Gem::Specification.new do |spec|
spec.add_dependency 'json_token'
spec.add_dependency 'paginated_collection'
spec.add_dependency 'rails', ">= 4.2", "< 5.2"
spec.add_dependency 'rails', ">= 4.2"
spec.add_development_dependency 'bundler', '~> 1.5'
spec.add_development_dependency 'rspec', "~> 3.5.0"

View File

@ -14,7 +14,7 @@ Gem::Specification.new do |spec|
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
spec.require_paths = ["lib"]
spec.add_dependency "rails", ">= 3.2", "< 5.2"
spec.add_dependency "rails", ">= 3.2"
spec.add_runtime_dependency "google-api-client", "0.8.2"
spec.add_development_dependency "bundler", "~> 1.7"

View File

@ -19,7 +19,7 @@ Gem::Specification.new do |spec|
spec.add_dependency 'canvas_text_helper'
spec.add_dependency 'iconv', '~> 1.0'
spec.add_dependency 'activesupport', ">= 3.2", "< 5.2"
spec.add_dependency 'activesupport', ">= 3.2"
spec.add_development_dependency "bundler", "~> 1.5"
spec.add_development_dependency "rspec", "~> 3.5.0"

View File

@ -16,7 +16,7 @@ Gem::Specification.new do |spec|
spec.add_dependency "sexp_processor", "~> 4.2"
spec.add_dependency "ruby_parser", "~> 3.7"
spec.add_dependency "activesupport", ">= 3.2", "< 5.2"
spec.add_dependency "activesupport", ">= 3.2"
spec.add_dependency "i18nliner", "~> 0.1"
spec.add_development_dependency "bundler", "~> 1.5"

View File

@ -22,6 +22,7 @@ class I18nliner::Scope
def normalize_key(key, inferred_key, explicit_scope_option)
key = key.to_s
key = key.dup if key.frozen?
return key if key.sub!(ABSOLUTE_KEY, '') || !scope || inferred_key || explicit_scope_option
scope + key
end

View File

@ -14,7 +14,7 @@ Gem::Specification.new do |spec|
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
spec.require_paths = ["lib"]
spec.add_dependency "activesupport", ">= 3.2", "< 5.2"
spec.add_dependency "activesupport", ">= 3.2"
spec.add_dependency "i18n", ">= 0.7", "< 2"
spec.add_dependency "ruby_parser", "~> 3.7"

View File

@ -14,7 +14,7 @@ Gem::Specification.new do |spec|
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
spec.require_paths = ["lib"]
spec.add_dependency "activesupport", ">= 3.2", "< 5.2"
spec.add_dependency "activesupport", ">= 3.2"
spec.add_dependency "mail", "~> 2.7.0"
spec.add_dependency "html_text_helper"

View File

@ -16,7 +16,7 @@ Gem::Specification.new do |spec|
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
spec.require_paths = ['lib']
spec.add_dependency 'i18n', '~> 0'
spec.add_dependency 'i18n'
spec.add_dependency 'oauth'
spec.add_development_dependency 'bundler', '~> 1.5'

View File

@ -13,6 +13,6 @@ Gem::Specification.new do |spec|
spec.files = Dir["{app,config,db,lib}/**/*"]
spec.test_files = Dir["spec_canvas/**/*"]
spec.add_dependency "rails", ">= 3.2", "< 5.2"
spec.add_dependency "rails", ">= 3.2"
spec.add_dependency "academic_benchmarks", "~> 0.0"
end

View File

@ -13,5 +13,5 @@ Gem::Specification.new do |spec|
spec.files = Dir["{app,config,db,lib}/**/*"]
spec.test_files = Dir["spec_canvas/**/*"]
spec.add_dependency "rails", ">= 3.2", "< 5.2"
spec.add_dependency "rails", ">= 3.2"
end

View File

@ -16,6 +16,6 @@ Gem::Specification.new do |s|
s.files = Dir["{lib}/**/*"]
s.test_files = Dir["spec_canvas/**/*"]
s.add_dependency "rails", ">= 3.2", "< 5.2"
s.add_dependency "rails", ">= 3.2"
s.add_dependency "moodle2cc", "0.2.39"
end

View File

@ -13,5 +13,5 @@ Gem::Specification.new do |spec|
spec.files = Dir["{app,lib}/**/*"]
spec.test_files = Dir["spec_canvas/**/*"]
spec.add_dependency "rails", ">= 3.2", "< 5.2"
spec.add_dependency "rails", ">= 3.2"
end

View File

@ -15,7 +15,7 @@ Gem::Specification.new do |s|
s.files = Dir["{app,config,db,lib}/**/*"]
s.test_files = Dir["spec_canvas/**/*"]
s.add_dependency "rails", ">= 3.2", "< 5.2"
s.add_dependency "rails", ">= 3.2"
s.add_dependency "soap4r-middleware", "0.8.7"
# in spite of the name, this fork of soap4r works with all rubies
s.add_dependency "soap4r-ruby1.9", "2.0.5"

View File

@ -15,5 +15,5 @@ Gem::Specification.new do |s|
s.files = Dir["{app,config,db,lib}/**/*"]
s.test_files = Dir["spec_canvas/**/*"]
s.add_dependency "rails", ">= 3.2", "< 5.2"
s.add_dependency "rails", ">= 3.2"
end

View File

@ -15,7 +15,7 @@ Gem::Specification.new do |spec|
spec.require_paths = ["lib"]
spec.add_dependency "aws-sdk-s3"
spec.add_dependency "activesupport", ">= 3.2", "< 5.2"
spec.add_dependency "activerecord", ">= 3.2", "< 5.2"
spec.add_dependency "activesupport", ">= 3.2"
spec.add_dependency "activerecord", ">= 3.2"
spec.add_dependency "globby", ">= 0.1.2"
end

View File

@ -14,7 +14,7 @@ Gem::Specification.new do |spec|
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
spec.require_paths = ["lib"]
spec.add_dependency 'rails', ">= 3.2", "< 5.2"
spec.add_dependency 'rails', ">= 3.2"
spec.add_development_dependency "bundler", "~> 1.5"
spec.add_development_dependency "rake"

View File

@ -260,6 +260,7 @@ module AssignmentOverrideApplicator
[:id, :updated_at, :created_at].each { |attr|
clone[attr] = assignment.send(attr)
}
clone.clear_changes_information
self.copy_preloaded_associations_to_clone(assignment, clone)
yield(clone) if block_given?

View File

@ -125,7 +125,10 @@ module BrandableCSS
end
def check_if_we_need_to_create_a_db_migration
migrations = ActiveRecord::Migrator.migrations(ActiveRecord::Migrator.migrations_paths.first)
path = ActiveRecord::Migrator.migrations_paths.first
migrations = CANVAS_RAILS5_1 ?
ActiveRecord::Migrator.migrations(path) :
ActiveRecord::MigrationContext.new(path).migrations
['predeploy', 'postdeploy'].each do |pre_or_post|
migration = migrations.find { |m| m.name == MIGRATION_NAME + pre_or_post.camelize }
# they can't have the same id, so we just add 1 to the postdeploy one

View File

@ -74,7 +74,7 @@ class MessageableUser < User
scope = self.
select(MessageableUser.build_select(options)).
group(MessageableUser.connection.group_by(*columns)).
order(User.sortable_name_order_by_clause + ", users.id")
order(User.sortable_name_order_by_clause + Arel.sql(", users.id"))
if options[:strict_checks]
scope.where(AVAILABLE_CONDITIONS)

View File

@ -149,7 +149,7 @@ module Plannable
end
def order_by
@order_by ||= @columns.map { |col| column_order(col) }.join(', ')
@order_by ||= Arel.sql(@columns.map { |col| column_order(col) }.join(', '))
end
def column_order(col_name)

View File

@ -55,7 +55,7 @@ namespace :canvas do
generate_tasks << 'i18n:generate_js' if build_webpack
build_tasks = []
if build_webpack
# build dev bundles even in prod mode so you can debug with ?optimized_js=0 query string
# build dev bundles even in prod mode so you can debug with ?optimized_js=0 query string
# (except for on jenkins where we set JS_BUILD_NO_UGLIFY anyway so there's no need for an unminified fallback)
build_prod = ENV['RAILS_ENV'] == 'production' || ENV['USE_OPTIMIZED_JS'] == 'true' || ENV['USE_OPTIMIZED_JS'] == 'True'
dont_need_dev_fallback = build_prod && ENV['JS_BUILD_NO_UGLIFY']
@ -136,7 +136,9 @@ end
namespace :db do
desc "Shows pending db migrations."
task :pending_migrations => :environment do
migrations = ActiveRecord::Migrator.migrations(ActiveRecord::Migrator.migrations_paths)
migrations = CANVAS_RAILS5_1 ?
ActiveRecord::Migrator.migrations(ActiveRecord::Migrator.migrations_paths) :
ActiveRecord::Base.connection.migration_context.migrations
pending_migrations = ActiveRecord::Migrator.new(:up, migrations).pending_migrations
pending_migrations.each do |pending_migration|
tags = pending_migration.tags
@ -147,7 +149,9 @@ namespace :db do
desc "Shows skipped db migrations."
task :skipped_migrations => :environment do
migrations = ActiveRecord::Migrator.migrations(ActiveRecord::Migrator.migrations_paths)
migrations = CANVAS_RAILS5_1 ?
ActiveRecord::Migrator.migrations(ActiveRecord::Migrator.migrations_paths) :
ActiveRecord::Base.connection.migration_context.migrations
skipped_migrations = ActiveRecord::Migrator.new(:up, migrations).skipped_migrations
skipped_migrations.each do |skipped_migration|
tags = skipped_migration.tags
@ -159,7 +163,9 @@ namespace :db do
namespace :migrate do
desc "Run all pending predeploy migrations"
task :predeploy => [:environment, :load_config] do
migrations = ActiveRecord::Migrator.migrations(ActiveRecord::Migrator.migrations_paths)
migrations = CANVAS_RAILS5_1 ?
ActiveRecord::Migrator.migrations(ActiveRecord::Migrator.migrations_paths) :
ActiveRecord::Base.connection.migration_context.migrations
migrations = migrations.select { |m| m.tags.include?(:predeploy) }
ActiveRecord::Migrator.new(:up, migrations).migrate
end

View File

@ -341,10 +341,10 @@ describe FilesController do
it "should set cache headers for non text files" do
get 'show', params: {:course_id => @course.id, :id => @file.id, :download => 1, :verifier => @file.uuid, :download_frd => 1}
expect(response.header["Cache-Control"]).to include "private, max-age"
expect(response.header["Cache-Control"]).to include "private"
expect(response.header["Cache-Control"]).to include "max-age=#{1.day.seconds}"
expect(response.header["Cache-Control"]).not_to include "no-cache"
expect(response.header["Cache-Control"]).not_to include "no-store"
expect(response.header["Cache-Control"]).not_to include "max-age=0"
expect(response.header["Cache-Control"]).not_to include "must-revalidate"
expect(response.header).to include("Expires")
expect(response.header).not_to include("Pragma")
@ -354,11 +354,9 @@ describe FilesController do
@file.content_type = "text/html"
@file.save
get 'show', params: {:course_id => @course.id, :id => @file.id, :download => 1, :verifier => @file.uuid, :download_frd => 1}
expect(response.header["Cache-Control"]).not_to include "private, max-age"
expect(response.header["Cache-Control"]).not_to include "private"
expect(response.header["Cache-Control"]).to include "no-cache"
expect(response.header["Cache-Control"]).to include "no-store"
expect(response.header["Cache-Control"]).to include "max-age=0"
expect(response.header["Cache-Control"]).to include "must-revalidate"
expect(response.header).not_to include("Expires")
expect(response.header).to include("Pragma")
end

View File

@ -200,6 +200,7 @@ describe UsersController do
allow(authorization_mock).to receive_messages(:code= => nil, fetch_access_token!: nil, refresh_token:'refresh_token', access_token: 'access_token')
drive_mock = double('drive_mock', about: double(get: nil))
client_mock = double("client", discovered_api:drive_mock, :execute! => double('result', status: 200, data:{'permissionId' => 'permission_id'}))
allow(client_mock).to receive(:authorization).and_return(authorization_mock)
allow(GoogleDrive::Client).to receive(:create).and_return(client_mock)

View File

@ -143,14 +143,14 @@ describe CoursesHelper do
end
it "should return the score if graded" do
submission = Submission.new(:grade => 1.33333333, :workflow_state => 'graded')
submission.create_assignment(:points_possible => 5, :grading_type => 'points')
assignment = Assignment.new(:points_possible => 5, :grading_type => 'points')
submission = Submission.new(:grade => 1.33333333, :workflow_state => 'graded', :assignment => assignment)
expect(readable_grade(submission)).to eq '1.33 out of 5'
end
it "should not raise an error when passing a numeric type but grading_type is not 'points'" do
submission = Submission.new(grade: 1.33333333, workflow_state: 'graded')
submission.create_assignment(points_possible: 5, grading_type: 'percent')
assignment = Assignment.new(points_possible: 5, grading_type: 'percent')
submission = Submission.new(grade: 1.33333333, workflow_state: 'graded', assignment: assignment)
expect(readable_grade(submission)).to eq '1.33333%'
end
end

View File

@ -47,13 +47,13 @@ describe "site-wide" do
it "should set no-cache headers for html requests" do
get "/login"
expect(response['Pragma']).to match(/no-cache/)
expect(response['Cache-Control']).to match(/must-revalidate/)
expect(response['Cache-Control']).to match(/no-store/)
end
it "should NOT set no-cache headers for API/xhr requests" do
get "/api/v1/courses"
expect(response['Pragma']).to be_nil
expect(response['Cache-Control']).not_to match(/must-revalidate/)
expect(response['Cache-Control']).not_to match(/no-store/)
end
it "should set the x-frame-options http header" do

View File

@ -31,7 +31,11 @@ describe Autoextend do
# not found via autoloading? maybe it's a migration
if !extension.used
ActiveRecord::Migrator.migrations(ActiveRecord::Migrator.migrations_paths).map(&:disable_ddl_transaction)
if CANVAS_RAILS5_1
ActiveRecord::Migrator.migrations(ActiveRecord::Migrator.migrations_paths).map(&:disable_ddl_transaction)
else
ActiveRecord::Base.connection.migration_context.migrations.map(&:disable_ddl_transaction)
end
end
extension_name = if extension.module.is_a?(Module)

View File

@ -43,7 +43,7 @@ describe I18nTimeZone do
I18n.locale = :es
I18n.backend.stub({es: { time_zones: { international_date_line_west: "Línea de fecha internacional del oeste" }}}) do
tz = I18nTimeZone['International Date Line West']
expect(tz.to_s).to eq "Línea de fecha internacional del oeste (-11:00)"
expect(tz.to_s).to include "Línea de fecha internacional del oeste"
end
end
end

View File

@ -76,7 +76,7 @@ describe ExternalFeed do
account1 = account_model
course_with_student(:account => account1, :course => @course).update!(workflow_state: :active)
@feed = external_feed_model
@group = group_model(:is_public => true, :context => @course, :external_feeds => [@feed])
@group = group_model(:is_public => true, :context => @course)
@feed.update!(context: @group)
expect(@feed.inactive?).to be(false)
end
@ -85,7 +85,7 @@ describe ExternalFeed do
account1 = account_model
course_with_student(:account => account1, course: @course)
@feed = external_feed_model
@group = group_model(:is_public => true, :context => @course, :external_feeds => [@feed])
@group = group_model(:is_public => true, :context => @course)
@feed.update!(context: @group)
@course.complete!
expect(@feed.inactive?).to be(true)
@ -95,7 +95,7 @@ describe ExternalFeed do
account1 = account_model
course_with_student(:account => account1, course: @course)
@feed = external_feed_model
group_model(:is_public => true, :context => @course, :external_feeds => [@feed])
group_model(:is_public => true, :context => @course)
@feed.update!(context: @group)
@course.destroy!
expect(@feed.inactive?).to be(true)