Merge branch 'upgrade-to-rails-5-1' into 'master'
Upgrade Rails to 5.1 See merge request gitlab-org/gitlab-ce!27480
This commit is contained in:
commit
d369d69240
4
Gemfile
4
Gemfile
|
|
@ -1,6 +1,6 @@
|
|||
source 'https://rubygems.org'
|
||||
|
||||
gem 'rails', '5.0.7.2'
|
||||
gem 'rails', '5.1.7'
|
||||
|
||||
# Improves copy-on-write performance for MRI
|
||||
gem 'nakayoshi_fork', '~> 0.0.4'
|
||||
|
|
@ -18,7 +18,7 @@ gem 'mysql2', '~> 0.4.10', group: :mysql
|
|||
gem 'pg', '~> 1.1', group: :postgres
|
||||
|
||||
gem 'rugged', '~> 0.28'
|
||||
gem 'grape-path-helpers', '~> 1.0'
|
||||
gem 'grape-path-helpers', '~> 1.1'
|
||||
|
||||
gem 'faraday', '~> 0.12'
|
||||
|
||||
|
|
|
|||
93
Gemfile.lock
93
Gemfile.lock
|
|
@ -4,41 +4,41 @@ GEM
|
|||
RedCloth (4.3.2)
|
||||
abstract_type (0.0.7)
|
||||
ace-rails-ap (4.1.2)
|
||||
actioncable (5.0.7.2)
|
||||
actionpack (= 5.0.7.2)
|
||||
nio4r (>= 1.2, < 3.0)
|
||||
actioncable (5.1.7)
|
||||
actionpack (= 5.1.7)
|
||||
nio4r (~> 2.0)
|
||||
websocket-driver (~> 0.6.1)
|
||||
actionmailer (5.0.7.2)
|
||||
actionpack (= 5.0.7.2)
|
||||
actionview (= 5.0.7.2)
|
||||
activejob (= 5.0.7.2)
|
||||
actionmailer (5.1.7)
|
||||
actionpack (= 5.1.7)
|
||||
actionview (= 5.1.7)
|
||||
activejob (= 5.1.7)
|
||||
mail (~> 2.5, >= 2.5.4)
|
||||
rails-dom-testing (~> 2.0)
|
||||
actionpack (5.0.7.2)
|
||||
actionview (= 5.0.7.2)
|
||||
activesupport (= 5.0.7.2)
|
||||
actionpack (5.1.7)
|
||||
actionview (= 5.1.7)
|
||||
activesupport (= 5.1.7)
|
||||
rack (~> 2.0)
|
||||
rack-test (~> 0.6.3)
|
||||
rack-test (>= 0.6.3)
|
||||
rails-dom-testing (~> 2.0)
|
||||
rails-html-sanitizer (~> 1.0, >= 1.0.2)
|
||||
actionview (5.0.7.2)
|
||||
activesupport (= 5.0.7.2)
|
||||
actionview (5.1.7)
|
||||
activesupport (= 5.1.7)
|
||||
builder (~> 3.1)
|
||||
erubis (~> 2.7.0)
|
||||
erubi (~> 1.4)
|
||||
rails-dom-testing (~> 2.0)
|
||||
rails-html-sanitizer (~> 1.0, >= 1.0.3)
|
||||
activejob (5.0.7.2)
|
||||
activesupport (= 5.0.7.2)
|
||||
activejob (5.1.7)
|
||||
activesupport (= 5.1.7)
|
||||
globalid (>= 0.3.6)
|
||||
activemodel (5.0.7.2)
|
||||
activesupport (= 5.0.7.2)
|
||||
activerecord (5.0.7.2)
|
||||
activemodel (= 5.0.7.2)
|
||||
activesupport (= 5.0.7.2)
|
||||
arel (~> 7.0)
|
||||
activemodel (5.1.7)
|
||||
activesupport (= 5.1.7)
|
||||
activerecord (5.1.7)
|
||||
activemodel (= 5.1.7)
|
||||
activesupport (= 5.1.7)
|
||||
arel (~> 8.0)
|
||||
activerecord_sane_schema_dumper (1.0)
|
||||
rails (>= 5, < 6)
|
||||
activesupport (5.0.7.2)
|
||||
activesupport (5.1.7)
|
||||
concurrent-ruby (~> 1.0, >= 1.0.2)
|
||||
i18n (>= 0.7, < 2)
|
||||
minitest (~> 5.1)
|
||||
|
|
@ -52,7 +52,7 @@ GEM
|
|||
public_suffix (>= 2.0.2, < 4.0)
|
||||
aes_key_wrap (1.0.1)
|
||||
akismet (2.0.0)
|
||||
arel (7.1.4)
|
||||
arel (8.0.0)
|
||||
asana (0.8.1)
|
||||
faraday (~> 0.9)
|
||||
faraday_middleware (~> 0.9)
|
||||
|
|
@ -185,8 +185,7 @@ GEM
|
|||
mail (~> 2.7)
|
||||
encryptor (3.0.0)
|
||||
equalizer (0.0.11)
|
||||
erubi (1.7.1)
|
||||
erubis (2.7.0)
|
||||
erubi (1.8.0)
|
||||
escape_utils (1.2.1)
|
||||
et-orbi (1.1.7)
|
||||
tzinfo
|
||||
|
|
@ -257,8 +256,8 @@ GEM
|
|||
fog-xml (0.1.3)
|
||||
fog-core
|
||||
nokogiri (>= 1.5.11, < 2.0.0)
|
||||
font-awesome-rails (4.7.0.1)
|
||||
railties (>= 3.2, < 5.1)
|
||||
font-awesome-rails (4.7.0.4)
|
||||
railties (>= 3.2, < 6.0)
|
||||
foreman (0.84.0)
|
||||
thor (~> 0.19.1)
|
||||
formatador (0.2.5)
|
||||
|
|
@ -339,8 +338,8 @@ GEM
|
|||
grape-entity (0.7.1)
|
||||
activesupport (>= 4.0)
|
||||
multi_json (>= 1.3.2)
|
||||
grape-path-helpers (1.0.6)
|
||||
activesupport (>= 4, < 5.1)
|
||||
grape-path-helpers (1.1.0)
|
||||
activesupport
|
||||
grape (~> 1.0)
|
||||
rake (~> 12)
|
||||
grape_logging (1.7.0)
|
||||
|
|
@ -658,19 +657,19 @@ GEM
|
|||
rack
|
||||
rack-proxy (0.6.0)
|
||||
rack
|
||||
rack-test (0.6.3)
|
||||
rack (>= 1.0)
|
||||
rails (5.0.7.2)
|
||||
actioncable (= 5.0.7.2)
|
||||
actionmailer (= 5.0.7.2)
|
||||
actionpack (= 5.0.7.2)
|
||||
actionview (= 5.0.7.2)
|
||||
activejob (= 5.0.7.2)
|
||||
activemodel (= 5.0.7.2)
|
||||
activerecord (= 5.0.7.2)
|
||||
activesupport (= 5.0.7.2)
|
||||
rack-test (1.1.0)
|
||||
rack (>= 1.0, < 3)
|
||||
rails (5.1.7)
|
||||
actioncable (= 5.1.7)
|
||||
actionmailer (= 5.1.7)
|
||||
actionpack (= 5.1.7)
|
||||
actionview (= 5.1.7)
|
||||
activejob (= 5.1.7)
|
||||
activemodel (= 5.1.7)
|
||||
activerecord (= 5.1.7)
|
||||
activesupport (= 5.1.7)
|
||||
bundler (>= 1.3.0)
|
||||
railties (= 5.0.7.2)
|
||||
railties (= 5.1.7)
|
||||
sprockets-rails (>= 2.0.0)
|
||||
rails-controller-testing (1.0.2)
|
||||
actionpack (~> 5.x, >= 5.0.1)
|
||||
|
|
@ -684,9 +683,9 @@ GEM
|
|||
rails-i18n (5.1.1)
|
||||
i18n (>= 0.7, < 2)
|
||||
railties (>= 5.0, < 6)
|
||||
railties (5.0.7.2)
|
||||
actionpack (= 5.0.7.2)
|
||||
activesupport (= 5.0.7.2)
|
||||
railties (5.1.7)
|
||||
actionpack (= 5.1.7)
|
||||
activesupport (= 5.1.7)
|
||||
method_source
|
||||
rake (>= 0.8.7)
|
||||
thor (>= 0.18.1, < 2.0)
|
||||
|
|
@ -1067,7 +1066,7 @@ DEPENDENCIES
|
|||
gpgme (~> 2.0.18)
|
||||
grape (~> 1.1.0)
|
||||
grape-entity (~> 0.7.1)
|
||||
grape-path-helpers (~> 1.0)
|
||||
grape-path-helpers (~> 1.1)
|
||||
grape_logging (~> 1.7)
|
||||
graphiql-rails (~> 1.4.10)
|
||||
graphql (~> 1.8.0)
|
||||
|
|
@ -1142,7 +1141,7 @@ DEPENDENCIES
|
|||
rack-cors (~> 1.0.0)
|
||||
rack-oauth2 (~> 1.9.3)
|
||||
rack-proxy (~> 0.6.0)
|
||||
rails (= 5.0.7.2)
|
||||
rails (= 5.1.7)
|
||||
rails-controller-testing
|
||||
rails-i18n (~> 5.1)
|
||||
rainbow (~> 3.0)
|
||||
|
|
|
|||
|
|
@ -56,7 +56,7 @@ module Ci
|
|||
|
||||
update_project_statistics stat: :build_artifacts_size
|
||||
|
||||
after_save :update_file_store, if: :file_changed?
|
||||
after_save :update_file_store, if: :saved_change_to_file?
|
||||
|
||||
scope :with_files_stored_locally, -> { where(file_store: [nil, ::JobArtifactUploader::Store::LOCAL]) }
|
||||
|
||||
|
|
|
|||
|
|
@ -230,7 +230,7 @@ module Clusters
|
|||
end
|
||||
|
||||
def update_kubernetes_namespace
|
||||
return unless namespace_changed?
|
||||
return unless saved_change_to_namespace?
|
||||
|
||||
run_after_commit do
|
||||
ClusterConfigureWorker.perform_async(cluster_id)
|
||||
|
|
|
|||
|
|
@ -13,8 +13,8 @@ module Storage
|
|||
raise Gitlab::UpdatePathError.new("Namespace #{name} (#{id}) cannot be moved because at least one project (e.g. #{proj_with_tags.name} (#{proj_with_tags.id})) has tags in container registry")
|
||||
end
|
||||
|
||||
parent_was = if parent_changed? && parent_id_was.present?
|
||||
Namespace.find(parent_id_was) # raise NotFound early if needed
|
||||
parent_was = if parent_changed? && parent_id_before_last_save.present?
|
||||
Namespace.find(parent_id_before_last_save) # raise NotFound early if needed
|
||||
end
|
||||
|
||||
move_repositories
|
||||
|
|
|
|||
|
|
@ -39,12 +39,12 @@ module UpdateProjectStatistics
|
|||
end
|
||||
|
||||
def update_project_statistics_attribute_changed?
|
||||
attribute_changed?(self.class.statistic_attribute)
|
||||
saved_change_to_attribute?(self.class.statistic_attribute)
|
||||
end
|
||||
|
||||
def update_project_statistics_after_save
|
||||
attr = self.class.statistic_attribute
|
||||
delta = read_attribute(attr).to_i - attribute_was(attr).to_i
|
||||
delta = read_attribute(attr).to_i - attribute_before_last_save(attr).to_i
|
||||
|
||||
update_project_statistics(delta)
|
||||
end
|
||||
|
|
|
|||
|
|
@ -61,7 +61,7 @@ class Group < Namespace
|
|||
after_create :post_create_hook
|
||||
after_destroy :post_destroy_hook
|
||||
after_save :update_two_factor_requirement
|
||||
after_update :path_changed_hook, if: :path_changed?
|
||||
after_update :path_changed_hook, if: :saved_change_to_path?
|
||||
|
||||
class << self
|
||||
def sort_by_attribute(method)
|
||||
|
|
@ -411,7 +411,7 @@ class Group < Namespace
|
|||
private
|
||||
|
||||
def update_two_factor_requirement
|
||||
return unless require_two_factor_authentication_changed? || two_factor_grace_period_changed?
|
||||
return unless saved_change_to_require_two_factor_authentication? || saved_change_to_two_factor_grace_period?
|
||||
|
||||
users.find_each(&:update_two_factor_requirement)
|
||||
end
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ class LfsObject < ApplicationRecord
|
|||
|
||||
mount_uploader :file, LfsObjectUploader
|
||||
|
||||
after_save :update_file_store, if: :file_changed?
|
||||
after_save :update_file_store, if: :saved_change_to_file?
|
||||
|
||||
def update_file_store
|
||||
# The file.object_store is set during `uploader.store!`
|
||||
|
|
|
|||
|
|
@ -55,7 +55,7 @@ class GroupMember < Member
|
|||
end
|
||||
|
||||
def post_update_hook
|
||||
if access_level_changed?
|
||||
if saved_change_to_access_level?
|
||||
run_after_commit { notification_service.update_group_member(self) }
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -111,7 +111,7 @@ class ProjectMember < Member
|
|||
end
|
||||
|
||||
def post_update_hook
|
||||
if access_level_changed?
|
||||
if saved_change_to_access_level?
|
||||
run_after_commit { notification_service.update_project_member(self) }
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -698,7 +698,7 @@ class MergeRequest < ApplicationRecord
|
|||
end
|
||||
|
||||
def reload_diff_if_branch_changed
|
||||
if (source_branch_changed? || target_branch_changed?) &&
|
||||
if (saved_change_to_source_branch? || saved_change_to_target_branch?) &&
|
||||
(source_branch_head && target_branch_head)
|
||||
reload_diff
|
||||
end
|
||||
|
|
|
|||
|
|
@ -50,6 +50,8 @@ class Namespace < ApplicationRecord
|
|||
|
||||
validate :nesting_level_allowed
|
||||
|
||||
validates_associated :runners
|
||||
|
||||
delegate :name, to: :owner, allow_nil: true, prefix: true
|
||||
delegate :avatar_url, to: :owner, allow_nil: true
|
||||
|
||||
|
|
@ -57,7 +59,7 @@ class Namespace < ApplicationRecord
|
|||
|
||||
before_create :sync_share_with_group_lock_with_parent
|
||||
before_update :sync_share_with_group_lock_with_parent, if: :parent_changed?
|
||||
after_update :force_share_with_group_lock_on_descendants, if: -> { share_with_group_lock_changed? && share_with_group_lock? }
|
||||
after_update :force_share_with_group_lock_on_descendants, if: -> { saved_change_to_share_with_group_lock? && share_with_group_lock? }
|
||||
|
||||
# Legacy Storage specific hooks
|
||||
|
||||
|
|
@ -292,7 +294,7 @@ class Namespace < ApplicationRecord
|
|||
private
|
||||
|
||||
def path_or_parent_changed?
|
||||
path_changed? || parent_changed?
|
||||
saved_change_to_path? || saved_change_to_parent_id?
|
||||
end
|
||||
|
||||
def refresh_access_of_projects_invited_groups
|
||||
|
|
|
|||
|
|
@ -147,20 +147,20 @@ class PagesDomain < ApplicationRecord
|
|||
# rubocop: enable CodeReuse/ServiceClass
|
||||
|
||||
def pages_config_changed?
|
||||
project_id_changed? ||
|
||||
domain_changed? ||
|
||||
certificate_changed? ||
|
||||
key_changed? ||
|
||||
saved_change_to_project_id? ||
|
||||
saved_change_to_domain? ||
|
||||
saved_change_to_certificate? ||
|
||||
saved_change_to_key? ||
|
||||
became_enabled? ||
|
||||
became_disabled?
|
||||
end
|
||||
|
||||
def became_enabled?
|
||||
enabled_until.present? && !enabled_until_was.present?
|
||||
enabled_until.present? && !enabled_until_before_last_save.present?
|
||||
end
|
||||
|
||||
def became_disabled?
|
||||
!enabled_until.present? && enabled_until_was.present?
|
||||
!enabled_until.present? && enabled_until_before_last_save.present?
|
||||
end
|
||||
|
||||
def validate_matching_key
|
||||
|
|
|
|||
|
|
@ -90,7 +90,7 @@ class Project < ApplicationRecord
|
|||
|
||||
before_save :ensure_runners_token
|
||||
|
||||
after_save :update_project_statistics, if: :namespace_id_changed?
|
||||
after_save :update_project_statistics, if: :saved_change_to_namespace_id?
|
||||
|
||||
after_save :create_import_state, if: ->(project) { project.import? && project.import_state.nil? }
|
||||
|
||||
|
|
@ -116,7 +116,7 @@ class Project < ApplicationRecord
|
|||
after_initialize :use_hashed_storage
|
||||
after_create :check_repository_absence!
|
||||
after_create :ensure_storage_path_exists
|
||||
after_save :ensure_storage_path_exists, if: :namespace_id_changed?
|
||||
after_save :ensure_storage_path_exists, if: :saved_change_to_namespace_id?
|
||||
|
||||
acts_as_ordered_taggable
|
||||
|
||||
|
|
@ -1430,7 +1430,7 @@ class Project < ApplicationRecord
|
|||
|
||||
# update visibility_level of forks
|
||||
def update_forks_visibility_level
|
||||
return unless visibility_level < visibility_level_was
|
||||
return unless visibility_level < visibility_level_before_last_save
|
||||
|
||||
forks.each do |forked_project|
|
||||
if forked_project.visibility_level > visibility_level
|
||||
|
|
|
|||
|
|
@ -248,7 +248,7 @@ class RemoteMirror < ApplicationRecord
|
|||
|
||||
# Before adding a new remote we have to delete the data from
|
||||
# the previous remote name
|
||||
prev_remote_name = remote_name_was || fallback_remote_name
|
||||
prev_remote_name = remote_name_before_last_save || fallback_remote_name
|
||||
run_after_commit do
|
||||
project.repository.async_remove_remote(prev_remote_name)
|
||||
end
|
||||
|
|
|
|||
|
|
@ -14,26 +14,26 @@ class Route < ApplicationRecord
|
|||
|
||||
before_validation :delete_conflicting_orphaned_routes
|
||||
after_create :delete_conflicting_redirects
|
||||
after_update :delete_conflicting_redirects, if: :path_changed?
|
||||
after_update :delete_conflicting_redirects, if: :saved_change_to_path?
|
||||
after_update :create_redirect_for_old_path
|
||||
after_update :rename_descendants
|
||||
|
||||
scope :inside_path, -> (path) { where('routes.path LIKE ?', "#{sanitize_sql_like(path)}/%") }
|
||||
|
||||
def rename_descendants
|
||||
return unless path_changed? || name_changed?
|
||||
return unless saved_change_to_path? || saved_change_to_name?
|
||||
|
||||
descendant_routes = self.class.inside_path(path_was)
|
||||
descendant_routes = self.class.inside_path(path_before_last_save)
|
||||
|
||||
descendant_routes.each do |route|
|
||||
attributes = {}
|
||||
|
||||
if path_changed? && route.path.present?
|
||||
attributes[:path] = route.path.sub(path_was, path)
|
||||
if saved_change_to_path? && route.path.present?
|
||||
attributes[:path] = route.path.sub(path_before_last_save, path)
|
||||
end
|
||||
|
||||
if name_changed? && name_was.present? && route.name.present?
|
||||
attributes[:name] = route.name.sub(name_was, name)
|
||||
if saved_change_to_name? && name_before_last_save.present? && route.name.present?
|
||||
attributes[:name] = route.name.sub(name_before_last_save, name)
|
||||
end
|
||||
|
||||
if attributes.present?
|
||||
|
|
@ -65,7 +65,7 @@ class Route < ApplicationRecord
|
|||
private
|
||||
|
||||
def create_redirect_for_old_path
|
||||
create_redirect(path_was) if path_changed?
|
||||
create_redirect(path_before_last_save) if saved_change_to_path?
|
||||
end
|
||||
|
||||
def delete_conflicting_orphaned_routes
|
||||
|
|
|
|||
|
|
@ -194,7 +194,7 @@ class User < ApplicationRecord
|
|||
before_validation :ensure_namespace_correct
|
||||
before_save :ensure_namespace_correct # in case validation is skipped
|
||||
after_validation :set_username_errors
|
||||
after_update :username_changed_hook, if: :username_changed?
|
||||
after_update :username_changed_hook, if: :saved_change_to_username?
|
||||
after_destroy :post_destroy_hook
|
||||
after_destroy :remove_key_cache
|
||||
after_commit(on: :update) do
|
||||
|
|
|
|||
|
|
@ -80,7 +80,7 @@ module Projects
|
|||
value = value.is_a?(Hash) ? value.to_json : value
|
||||
|
||||
service_hash[ActiveRecord::Base.connection.quote_column_name(key)] =
|
||||
ActiveRecord::Base.sanitize(value)
|
||||
ActiveRecord::Base.connection.quote(value)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: Upgrade to Rails 5.1
|
||||
merge_request: 27480
|
||||
author: Jasper Maes
|
||||
type: other
|
||||
|
|
@ -164,9 +164,6 @@ module Gitlab
|
|||
# Version of your assets, change this if you want to expire all your assets
|
||||
config.assets.version = '1.0'
|
||||
|
||||
# Can be removed once upgraded to Rails 5.1 or higher
|
||||
config.action_controller.raise_on_unfiltered_parameters = true
|
||||
|
||||
# Nokogiri is significantly faster and uses less memory than REXML
|
||||
ActiveSupport::XmlMini.backend = 'Nokogiri'
|
||||
|
||||
|
|
|
|||
|
|
@ -1,94 +0,0 @@
|
|||
# This is a monkey patch which must be removed when migrating to Rails 5.1 from 5.0.
|
||||
#
|
||||
# In Rails 5.0 there was introduced a bug which casts types in the uniqueness validator.
|
||||
# https://github.com/rails/rails/pull/23523/commits/811a4fa8eb6ceea841e61e8ac05747ffb69595ae
|
||||
#
|
||||
# That causes to bugs like this:
|
||||
#
|
||||
# 1) API::Users POST /user/:id/gpg_keys/:key_id/revoke when authenticated revokes existing key
|
||||
# Failure/Error: let(:gpg_key) { create(:gpg_key, user: user) }
|
||||
#
|
||||
# TypeError:
|
||||
# can't cast Hash
|
||||
# # ./spec/requests/api/users_spec.rb:7:in `block (2 levels) in <top (required)>'
|
||||
# # ./spec/requests/api/users_spec.rb:908:in `block (4 levels) in <top (required)>'
|
||||
# # ------------------
|
||||
# # --- Caused by: ---
|
||||
# # TypeError:
|
||||
# # TypeError
|
||||
# # ./spec/requests/api/users_spec.rb:7:in `block (2 levels) in <top (required)>'
|
||||
#
|
||||
# This bug was fixed in Rails 5.1 by https://github.com/rails/rails/pull/24745/commits/aa062318c451512035c10898a1af95943b1a3803
|
||||
|
||||
if Rails.gem_version >= Gem::Version.new("5.1")
|
||||
raise "Remove this monkey patch: #{__FILE__}"
|
||||
end
|
||||
|
||||
# Copy-paste from https://github.com/kamipo/rails/blob/aa062318c451512035c10898a1af95943b1a3803/activerecord/lib/active_record/validations/uniqueness.rb
|
||||
# including local fixes to make Rubocop happy again.
|
||||
module ActiveRecord
|
||||
module Validations
|
||||
class UniquenessValidator < ActiveModel::EachValidator # :nodoc:
|
||||
def validate_each(record, attribute, value)
|
||||
finder_class = find_finder_class_for(record)
|
||||
table = finder_class.arel_table
|
||||
value = map_enum_attribute(finder_class, attribute, value)
|
||||
|
||||
relation = build_relation(finder_class, table, attribute, value)
|
||||
|
||||
if record.persisted?
|
||||
if finder_class.primary_key
|
||||
relation = relation.where.not(finder_class.primary_key => record.id_was || record.id)
|
||||
else
|
||||
raise UnknownPrimaryKey.new(finder_class, "Can not validate uniqueness for persisted record without primary key.")
|
||||
end
|
||||
end
|
||||
|
||||
relation = scope_relation(record, table, relation)
|
||||
relation = relation.merge(options[:conditions]) if options[:conditions]
|
||||
|
||||
if relation.exists?
|
||||
error_options = options.except(:case_sensitive, :scope, :conditions)
|
||||
error_options[:value] = value
|
||||
|
||||
record.errors.add(attribute, :taken, error_options)
|
||||
end
|
||||
rescue RangeError
|
||||
end
|
||||
|
||||
protected
|
||||
|
||||
def build_relation(klass, table, attribute, value) #:nodoc:
|
||||
if reflection = klass._reflect_on_association(attribute)
|
||||
attribute = reflection.foreign_key
|
||||
value = value.attributes[reflection.klass.primary_key] unless value.nil?
|
||||
end
|
||||
|
||||
# the attribute may be an aliased attribute
|
||||
if klass.attribute_alias?(attribute)
|
||||
attribute = klass.attribute_alias(attribute)
|
||||
end
|
||||
|
||||
attribute_name = attribute.to_s
|
||||
|
||||
column = klass.columns_hash[attribute_name]
|
||||
cast_type = klass.type_for_attribute(attribute_name)
|
||||
|
||||
comparison =
|
||||
if !options[:case_sensitive] && !value.nil?
|
||||
# will use SQL LOWER function before comparison, unless it detects a case insensitive collation
|
||||
klass.connection.case_insensitive_comparison(table, attribute, column, value)
|
||||
else
|
||||
klass.connection.case_sensitive_comparison(table, attribute, column, value)
|
||||
end
|
||||
|
||||
if value.nil?
|
||||
klass.unscoped.where(comparison)
|
||||
else
|
||||
bind = Relation::QueryAttribute.new(attribute_name, value, cast_type)
|
||||
klass.unscoped.where(comparison, bind)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
# rubocop:disable Gitlab/ModuleWithInstanceVariables
|
||||
|
||||
# build_select only selects the required fields if the model has ignored_columns.
|
||||
# This is incompatible with some migrations or background migration specs because
|
||||
# rails keeps a statement cache in memory. So if a model with ignored_columns in a
|
||||
# migration is used, the query with select table.col1, table.col2 is stored in the
|
||||
# statement cache. If a different migration is then run and one of these columns is
|
||||
# removed in the meantime, the query is invalid.
|
||||
|
||||
module ActiveRecord
|
||||
module QueryMethods
|
||||
private
|
||||
|
||||
def build_select(arel)
|
||||
if select_values.any?
|
||||
arel.project(*arel_columns(select_values.uniq))
|
||||
else
|
||||
arel.project(@klass.arel_table[Arel.star])
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -1,76 +0,0 @@
|
|||
# rubocop:disable Lint/RescueException
|
||||
|
||||
# Remove this monkey patch when we move to Rails 5.1, because the bug has been fixed in https://github.com/rails/rails/pull/26050.
|
||||
if Rails.gem_version >= Gem::Version.new("5.1")
|
||||
raise "Remove this monkey patch: #{__FILE__}"
|
||||
end
|
||||
|
||||
module ActiveRecord
|
||||
module Locking
|
||||
module Optimistic
|
||||
# We overwrite this method because we don't want to have default value
|
||||
# for newly created records
|
||||
def _create_record(attribute_names = self.attribute_names, *) # :nodoc:
|
||||
super
|
||||
end
|
||||
|
||||
def _update_record(attribute_names = self.attribute_names) #:nodoc:
|
||||
return super unless locking_enabled?
|
||||
return 0 if attribute_names.empty?
|
||||
|
||||
lock_col = self.class.locking_column
|
||||
previous_lock_value = send(lock_col).to_i
|
||||
increment_lock
|
||||
|
||||
attribute_names += [lock_col]
|
||||
attribute_names.uniq!
|
||||
|
||||
begin
|
||||
relation = self.class.unscoped
|
||||
|
||||
affected_rows = relation.where(
|
||||
self.class.primary_key => id,
|
||||
# Patched because when `lock_version` is read as `0`, it may actually be `NULL` in the DB.
|
||||
lock_col => previous_lock_value == 0 ? [nil, 0] : previous_lock_value
|
||||
).update_all(
|
||||
attributes_for_update(attribute_names).map do |name|
|
||||
[name, _read_attribute(name)]
|
||||
end.to_h
|
||||
)
|
||||
|
||||
unless affected_rows == 1
|
||||
raise ActiveRecord::StaleObjectError.new(self, "update")
|
||||
end
|
||||
|
||||
affected_rows
|
||||
|
||||
# If something went wrong, revert the version.
|
||||
rescue Exception
|
||||
send(lock_col + '=', previous_lock_value)
|
||||
raise
|
||||
end
|
||||
end
|
||||
|
||||
# This is patched because we need it to query `lock_version IS NULL`
|
||||
# rather than `lock_version = 0` whenever lock_version is NULL.
|
||||
def relation_for_destroy
|
||||
return super unless locking_enabled?
|
||||
|
||||
column_name = self.class.locking_column
|
||||
super.where(self.class.arel_table[column_name].eq(self[column_name]))
|
||||
end
|
||||
end
|
||||
|
||||
# This is patched because we want `lock_version` default to `NULL`
|
||||
# rather than `0`
|
||||
class LockingType
|
||||
def deserialize(value)
|
||||
super
|
||||
end
|
||||
|
||||
def serialize(value)
|
||||
super
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -4,7 +4,8 @@ module ActiveRecord
|
|||
module ConnectionAdapters
|
||||
class AbstractMysqlAdapter
|
||||
NATIVE_DATABASE_TYPES.merge!(
|
||||
bigserial: { name: 'bigint(20) auto_increment PRIMARY KEY' }
|
||||
bigserial: { name: 'bigint(20) auto_increment PRIMARY KEY' },
|
||||
serial: { name: 'int auto_increment PRIMARY KEY' }
|
||||
)
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -78,7 +78,7 @@ module ActiveRecord
|
|||
if index_name.length > max_index_length
|
||||
raise ArgumentError, "Index name '#{index_name}' on table '#{table_name}' is too long; the limit is #{max_index_length} characters"
|
||||
end
|
||||
if data_source_exists?(table_name) && index_name_exists?(table_name, index_name, false)
|
||||
if data_source_exists?(table_name) && index_name_exists?(table_name, index_name)
|
||||
raise ArgumentError, "Index name '#{index_name}' on table '#{table_name}' already exists"
|
||||
end
|
||||
index_columns = quoted_columns_for_index(column_names, options).join(", ")
|
||||
|
|
|
|||
|
|
@ -9,11 +9,11 @@ class AddUniqueIndexToSubscriptions < ActiveRecord::Migration[4.2]
|
|||
|
||||
def up
|
||||
add_concurrent_index :subscriptions, [:subscribable_id, :subscribable_type, :user_id, :project_id], { unique: true, name: 'index_subscriptions_on_subscribable_and_user_id_and_project_id' }
|
||||
remove_index :subscriptions, name: 'subscriptions_user_id_and_ref_fields' if index_name_exists?(:subscriptions, 'subscriptions_user_id_and_ref_fields', false)
|
||||
remove_index :subscriptions, name: 'subscriptions_user_id_and_ref_fields' if index_name_exists?(:subscriptions, 'subscriptions_user_id_and_ref_fields')
|
||||
end
|
||||
|
||||
def down
|
||||
add_concurrent_index :subscriptions, [:subscribable_id, :subscribable_type, :user_id], { unique: true, name: 'subscriptions_user_id_and_ref_fields' }
|
||||
remove_index :subscriptions, name: 'index_subscriptions_on_subscribable_and_user_id_and_project_id' if index_name_exists?(:subscriptions, 'index_subscriptions_on_subscribable_and_user_id_and_project_id', false)
|
||||
remove_index :subscriptions, name: 'index_subscriptions_on_subscribable_and_user_id_and_project_id' if index_name_exists?(:subscriptions, 'index_subscriptions_on_subscribable_and_user_id_and_project_id')
|
||||
end
|
||||
end
|
||||
|
|
|
|||
288
db/schema.rb
288
db/schema.rb
File diff suppressed because it is too large
Load Diff
|
|
@ -26,11 +26,7 @@ module Gitlab
|
|||
|
||||
subscribe('sql.active_record') do |_, start, finish, _, data|
|
||||
if Gitlab::SafeRequestStore.store[:peek_enabled]
|
||||
# data[:cached] is only available starting from Rails 5.1.0
|
||||
# https://github.com/rails/rails/blob/v5.1.0/activerecord/lib/active_record/connection_adapters/abstract/query_cache.rb#L113
|
||||
# Before that, data[:name] was set to 'CACHE'
|
||||
# https://github.com/rails/rails/blob/v4.2.9/activerecord/lib/active_record/connection_adapters/abstract/query_cache.rb#L80
|
||||
unless data.fetch(:cached, data[:name] == 'CACHE')
|
||||
unless data[:cached]
|
||||
track_query(data[:sql].strip, data[:binds], start, finish)
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -113,7 +113,7 @@ module Gitlab
|
|||
issues.full_search(query)
|
||||
end
|
||||
|
||||
issues.reorder('updated_at DESC')
|
||||
issues.reorder('issues.updated_at DESC')
|
||||
end
|
||||
# rubocop: enable CodeReuse/ActiveRecord
|
||||
|
||||
|
|
@ -121,7 +121,7 @@ module Gitlab
|
|||
def milestones
|
||||
milestones = Milestone.where(project_id: project_ids_relation)
|
||||
milestones = milestones.search(query)
|
||||
milestones.reorder('updated_at DESC')
|
||||
milestones.reorder('milestones.updated_at DESC')
|
||||
end
|
||||
# rubocop: enable CodeReuse/ActiveRecord
|
||||
|
||||
|
|
@ -139,7 +139,7 @@ module Gitlab
|
|||
merge_requests.full_search(query)
|
||||
end
|
||||
|
||||
merge_requests.reorder('updated_at DESC')
|
||||
merge_requests.reorder('merge_requests.updated_at DESC')
|
||||
end
|
||||
# rubocop: enable CodeReuse/ActiveRecord
|
||||
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@
|
|||
"iid": { "type": "integer" },
|
||||
"author_id": { "type": "integer" },
|
||||
"description": { "type": ["string", "null"] },
|
||||
"lock_version": { "type": ["string", "null"] },
|
||||
"lock_version": { "type": ["integer", "null"] },
|
||||
"milestone_id": { "type": ["string", "null"] },
|
||||
"title": { "type": "string" },
|
||||
"moved_to_id": { "type": ["integer", "null"] },
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@
|
|||
},
|
||||
"task_status": { "type": "string" },
|
||||
"task_status_short": { "type": "string" },
|
||||
"lock_version": { "type": ["string", "null"] }
|
||||
"lock_version": { "type": ["integer", "null"] }
|
||||
},
|
||||
"additionalProperties": false
|
||||
}
|
||||
|
|
|
|||
|
|
@ -58,7 +58,7 @@ describe('MergeRequest', function() {
|
|||
{
|
||||
merge_request: {
|
||||
description: '- [ ] Task List Item',
|
||||
lock_version: undefined,
|
||||
lock_version: 0,
|
||||
update_task: { line_number: lineNumber, line_source: lineSource, index, checked },
|
||||
},
|
||||
},
|
||||
|
|
|
|||
|
|
@ -177,7 +177,7 @@ describe Gitlab::BackgroundMigration::DeserializeMergeRequestDiffsAndCommits, :m
|
|||
end
|
||||
|
||||
before do
|
||||
allow_any_instance_of(described_class::MergeRequestDiff::ActiveRecord_Relation)
|
||||
allow_any_instance_of(ActiveRecord::Relation)
|
||||
.to receive(:update_all).and_raise(exception)
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -29,7 +29,7 @@ describe 'Import/Export attribute configuration' do
|
|||
it 'has no new columns' do
|
||||
relation_names.each do |relation_name|
|
||||
relation_class = relation_class_for_name(relation_name)
|
||||
relation_attributes = relation_class.new.attributes.keys
|
||||
relation_attributes = relation_class.new.attributes.keys - relation_class.encrypted_attributes.keys.map(&:to_s)
|
||||
|
||||
current_attributes = parsed_attributes(relation_name, relation_attributes)
|
||||
safe_attributes = safe_model_attributes[relation_class.to_s].dup || []
|
||||
|
|
|
|||
|
|
@ -73,9 +73,8 @@ describe Ci::Runner do
|
|||
end
|
||||
|
||||
it 'fails to save a group assigned to a project runner even if the runner is already saved' do
|
||||
group_runner
|
||||
|
||||
expect { create(:group, runners: [project_runner]) }
|
||||
group.runners << project_runner
|
||||
expect { group.save! }
|
||||
.to raise_error(ActiveRecord::RecordInvalid)
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -68,7 +68,7 @@ describe API::Runner, :clean_gitlab_redis_shared_state do
|
|||
post api('/runners'), params: { token: group.runners_token }
|
||||
|
||||
expect(response).to have_http_status 201
|
||||
expect(group.runners.size).to eq(1)
|
||||
expect(group.runners.reload.size).to eq(1)
|
||||
runner = Ci::Runner.first
|
||||
expect(runner.token).not_to eq(registration_token)
|
||||
expect(runner.token).not_to eq(group.runners_token)
|
||||
|
|
|
|||
|
|
@ -251,8 +251,8 @@ describe 'Rack Attack global throttles' do
|
|||
let(:throttle_setting_prefix) { 'throttle_authenticated_web' }
|
||||
|
||||
context 'with the token in the query string' do
|
||||
let(:get_args) { [rss_url(user), nil] }
|
||||
let(:other_user_get_args) { [rss_url(other_user), nil] }
|
||||
let(:get_args) { [rss_url(user), params: nil] }
|
||||
let(:other_user_get_args) { [rss_url(other_user), params: nil] }
|
||||
|
||||
it_behaves_like 'rate-limited token-authenticated requests'
|
||||
end
|
||||
|
|
|
|||
|
|
@ -440,6 +440,8 @@ describe Projects::UpdateService do
|
|||
context 'when auto devops is set to instance setting' do
|
||||
before do
|
||||
project.create_auto_devops!(enabled: nil)
|
||||
project.reload
|
||||
|
||||
allow(project.auto_devops).to receive(:previous_changes).and_return('enabled' => true)
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -210,6 +210,8 @@ describe Users::DestroyService do
|
|||
|
||||
describe "calls the before/after callbacks" do
|
||||
it 'of project_members' do
|
||||
expect_any_instance_of(ProjectMember).to receive(:run_callbacks).with(:find).once
|
||||
expect_any_instance_of(ProjectMember).to receive(:run_callbacks).with(:initialize).once
|
||||
expect_any_instance_of(ProjectMember).to receive(:run_callbacks).with(:destroy).once
|
||||
|
||||
service.execute(user)
|
||||
|
|
@ -219,6 +221,8 @@ describe Users::DestroyService do
|
|||
group_member = create(:group_member)
|
||||
group_member.group.group_members.create(user: user, access_level: 40)
|
||||
|
||||
expect_any_instance_of(GroupMember).to receive(:run_callbacks).with(:find).once
|
||||
expect_any_instance_of(GroupMember).to receive(:run_callbacks).with(:initialize).once
|
||||
expect_any_instance_of(GroupMember).to receive(:run_callbacks).with(:destroy).once
|
||||
|
||||
service.execute(user)
|
||||
|
|
|
|||
|
|
@ -80,7 +80,7 @@ describe Users::MigrateToGhostUserService do
|
|||
|
||||
context "when record migration fails with a rollback exception" do
|
||||
before do
|
||||
expect_any_instance_of(MergeRequest::ActiveRecord_Associations_CollectionProxy)
|
||||
expect_any_instance_of(ActiveRecord::Associations::CollectionProxy)
|
||||
.to receive(:update_all).and_raise(ActiveRecord::Rollback)
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ module ActiveRecord
|
|||
def callback(name, start, finish, message_id, values)
|
||||
show_backtrace(values) if ENV['QUERY_RECORDER_DEBUG']
|
||||
|
||||
if values[:name]&.include?("CACHE") && skip_cached
|
||||
if values[:cached] && skip_cached
|
||||
@cached << values[:sql]
|
||||
elsif !values[:name]&.include?("SCHEMA")
|
||||
@log << values[:sql]
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module TestRequestHelpers
|
||||
def test_request(remote_ip: '127.0.0.1')
|
||||
ActionController::TestRequest.new({ remote_ip: remote_ip }, ActionController::TestSession.new)
|
||||
def test_request(remote_ip: '127.0.0.1', controller: nil)
|
||||
ActionController::TestRequest.new({ remote_ip: remote_ip }, ActionController::TestSession.new, controller)
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -45,7 +45,7 @@ shared_examples "migrating a deleted user's associated records to the ghost user
|
|||
context "race conditions" do
|
||||
context "when #{record_class_name} migration fails and is rolled back" do
|
||||
before do
|
||||
expect_any_instance_of(record_class::ActiveRecord_Associations_CollectionProxy)
|
||||
expect_any_instance_of(ActiveRecord::Associations::CollectionProxy)
|
||||
.to receive(:update_all).and_raise(ActiveRecord::Rollback)
|
||||
end
|
||||
|
||||
|
|
@ -66,7 +66,7 @@ shared_examples "migrating a deleted user's associated records to the ghost user
|
|||
|
||||
context "when #{record_class_name} migration fails with a non-rollback exception" do
|
||||
before do
|
||||
expect_any_instance_of(record_class::ActiveRecord_Associations_CollectionProxy)
|
||||
expect_any_instance_of(ActiveRecord::Associations::CollectionProxy)
|
||||
.to receive(:update_all).and_raise(ArgumentError)
|
||||
end
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue