active_record_shards 3.11.2 → 3.19.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,43 +1,50 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  module ActiveRecord
3
4
  class Migrator
4
- class << self
5
- [:up, :down, :run].each do |m|
6
- define_method("#{m}_with_sharding") do |*args|
7
- ActiveRecord::Base.on_shard(nil) do
8
- send("#{m}_without_sharding", *args)
9
- end
10
- ActiveRecord::Base.on_all_shards do
11
- send("#{m}_without_sharding", *args)
12
- end
13
- end
14
- alias_method :"#{m}_without_sharding", m.to_sym
15
- alias_method m.to_sym, :"#{m}_with_sharding"
5
+ def self.shards_migration_context
6
+ if ActiveRecord::VERSION::MAJOR >= 6
7
+ ActiveRecord::MigrationContext.new(ActiveRecord::Migrator.migrations_paths, ActiveRecord::SchemaMigration)
8
+ elsif ActiveRecord::VERSION::STRING >= '5.2.0'
9
+ ActiveRecord::MigrationContext.new(ActiveRecord::Migrator.migrations_paths)
10
+ else
11
+ self
16
12
  end
13
+ end
17
14
 
18
- def bootstrap_migrations_from_nil_shard(migrations_path, this_migration = nil)
19
- migrations = nil
20
- ActiveRecord::Base.on_shard(nil) do
21
- migrations = ActiveRecord::Migrator.new(:up, migrations_path).migrated
22
- end
15
+ def initialize_with_sharding(*args)
16
+ initialize_without_sharding(*args)
23
17
 
24
- puts "inserting #{migrations.size} migrations on all shards..."
25
- ActiveRecord::Base.on_all_shards do
26
- migrator = ActiveRecord::Migrator.new(:up, migrations_path)
27
- migrations.each do |m|
28
- migrator.__send__(:record_version_state_after_migrating, m)
29
- end
30
- if this_migration
31
- migrator.__send__(:record_version_state_after_migrating, this_migration)
32
- end
18
+ # Rails creates the internal tables on the unsharded DB. We make them
19
+ # manually on the sharded DBs.
20
+ ActiveRecord::Base.on_all_shards do
21
+ ActiveRecord::SchemaMigration.create_table
22
+ if ActiveRecord::VERSION::MAJOR >= 5
23
+ ActiveRecord::InternalMetadata.create_table
33
24
  end
34
25
  end
35
26
  end
27
+ alias_method :initialize_without_sharding, :initialize
28
+ alias_method :initialize, :initialize_with_sharding
29
+
30
+ def run_with_sharding
31
+ ActiveRecord::Base.on_shard(nil) { run_without_sharding }
32
+ ActiveRecord::Base.on_all_shards { run_without_sharding }
33
+ end
34
+ alias_method :run_without_sharding, :run
35
+ alias_method :run, :run_with_sharding
36
+
37
+ def migrate_with_sharding
38
+ ActiveRecord::Base.on_shard(nil) { migrate_without_sharding }
39
+ ActiveRecord::Base.on_all_shards { migrate_without_sharding }
40
+ end
41
+ alias_method :migrate_without_sharding, :migrate
42
+ alias_method :migrate, :migrate_with_sharding
36
43
 
37
44
  # don't allow Migrator class to cache versions
38
45
  undef migrated
39
46
  def migrated
40
- self.class.get_all_versions
47
+ self.class.shards_migration_context.get_all_versions
41
48
  end
42
49
 
43
50
  # list of pending migrations is any migrations that haven't run on all shards.
@@ -56,7 +63,7 @@ module ActiveRecord
56
63
  missing = {}
57
64
 
58
65
  collect = lambda do |shard|
59
- migrated = get_all_versions
66
+ migrated = shards_migration_context.get_all_versions
60
67
 
61
68
  p = versions - migrated
62
69
  pending[shard] = p if p.any?
@@ -82,9 +89,6 @@ module ActiveRecordShards
82
89
  end
83
90
  end
84
91
 
85
- # ok, so some 'splaining to do. Rails 3.1 puts the migrate() method on the instance of the
86
- # migration, where it should have been. But this makes our monkey patch incompatible.
87
- # So we're forced to *either* include or extend this.
88
92
  module ActualMigrationExtension
89
93
  def migrate_with_forced_shard(direction)
90
94
  if migration_shard.blank?
@@ -6,10 +6,11 @@ module ActiveRecordShards
6
6
  if self != ActiveRecord::Base && self != base_class
7
7
  raise "You should only call not_sharded on direct descendants of ActiveRecord::Base"
8
8
  end
9
+
9
10
  self.sharded = false
10
11
  end
11
12
 
12
- def is_sharded? # rubocop:disable Style/PredicateName
13
+ def is_sharded? # rubocop:disable Naming/PredicateName
13
14
  if self == ActiveRecord::Base
14
15
  sharded != false && supports_sharding?
15
16
  elsif self == base_class
@@ -23,34 +24,38 @@ module ActiveRecordShards
23
24
  end
24
25
  end
25
26
 
26
- def on_slave_by_default?
27
+ def on_replica_by_default?
27
28
  if self == ActiveRecord::Base
28
29
  false
29
30
  else
30
31
  base = base_class
31
- if base.instance_variable_defined?(:@on_slave_by_default)
32
- base.instance_variable_get(:@on_slave_by_default)
32
+ if base.instance_variable_defined?(:@on_replica_by_default)
33
+ base.instance_variable_get(:@on_replica_by_default)
33
34
  end
34
35
  end
35
36
  end
37
+ alias_method :on_slave_by_default?, :on_replica_by_default?
36
38
 
37
- def on_slave_by_default=(value)
39
+ def on_replica_by_default=(value)
38
40
  if self == ActiveRecord::Base
39
- raise ArgumentError, "Cannot set on_slave_by_default on ActiveRecord::Base"
41
+ raise ArgumentError, "Cannot set on_replica_by_default on ActiveRecord::Base"
40
42
  else
41
- base_class.instance_variable_set(:@on_slave_by_default, value)
43
+ base_class.instance_variable_set(:@on_replica_by_default, value)
42
44
  end
43
45
  end
46
+ alias_method :on_slave_by_default=, :on_replica_by_default=
44
47
 
45
48
  module InstanceMethods
46
- def initialize_shard_and_slave
47
- @from_slave = !!self.class.current_shard_selection.options[:slave]
49
+ def initialize_shard_and_replica
50
+ @from_replica = !!self.class.current_shard_selection.options[:replica]
48
51
  @from_shard = self.class.current_shard_selection.options[:shard]
49
52
  end
53
+ alias_method :initialize_shard_and_slave, :initialize_shard_and_replica
50
54
 
51
- def from_slave?
52
- @from_slave
55
+ def from_replica?
56
+ @from_replica
53
57
  end
58
+ alias_method :from_slave?, :from_replica?
54
59
 
55
60
  def from_shard
56
61
  @from_shard
@@ -59,7 +64,7 @@ module ActiveRecordShards
59
64
 
60
65
  def self.extended(base)
61
66
  base.send(:include, InstanceMethods)
62
- base.after_initialize :initialize_shard_and_slave
67
+ base.after_initialize :initialize_shard_and_replica
63
68
  end
64
69
 
65
70
  private
@@ -1,13 +1,9 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  require 'active_record_shards/connection_pool'
3
4
  require 'active_record_shards/connection_handler'
4
5
  require 'active_record_shards/connection_specification'
5
- require 'active_record_shards/schema_dumper_extension'
6
6
 
7
7
  ActiveRecordShards::ConnectionSpecification = ActiveRecord::ConnectionAdapters::ConnectionSpecification
8
8
  methods_to_override = [:establish_connection, :remove_connection, :pool_for, :pool_from_any_process_for]
9
9
  ActiveRecordShards.override_connection_handler_methods(methods_to_override)
10
-
11
- ActiveRecord::Associations::Builder::HasAndBelongsToMany.include(ActiveRecordShards::DefaultSlavePatches::Rails41HasAndBelongsToManyBuilderExtension)
12
-
13
- ActiveRecord::SchemaDumper.prepend(ActiveRecordShards::SchemaDumperExtension)
@@ -1,4 +1,5 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  module ActiveRecordShards
3
4
  module SchemaDumperExtension
4
5
  def dump(stream)
@@ -23,15 +24,15 @@ module ActiveRecordShards
23
24
  def shard_header(stream)
24
25
  define_params = @version ? "version: #{@version}" : ""
25
26
 
26
- stream.puts <<HEADER
27
+ stream.puts <<~HEADER
27
28
 
28
29
 
29
- # This section generated by active_record_shards
30
+ # This section generated by active_record_shards
30
31
 
31
- ActiveRecord::Base.on_all_shards do
32
- ActiveRecord::Schema.define(#{define_params}) do
32
+ ActiveRecord::Base.on_all_shards do
33
+ ActiveRecord::Schema.define(#{define_params}) do
33
34
 
34
- HEADER
35
+ HEADER
35
36
  end
36
37
 
37
38
  def shard_trailer(stream)
@@ -1,11 +1,12 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  module ActiveRecordShards
3
4
  class ShardSelection
4
5
  NO_SHARD = :_no_shard
5
6
  cattr_accessor :default_shard
6
7
 
7
8
  def initialize
8
- @on_slave = false
9
+ @on_replica = false
9
10
  @shard = nil
10
11
  end
11
12
 
@@ -21,17 +22,17 @@ module ActiveRecordShards
21
22
  end
22
23
  end
23
24
 
24
- def shard_name(klass = nil, try_slave = true)
25
+ def shard_name(klass = nil, try_replica = true)
25
26
  the_shard = shard(klass)
26
27
 
27
28
  @shard_names ||= {}
28
29
  @shard_names[ActiveRecordShards.rails_env] ||= {}
29
30
  @shard_names[ActiveRecordShards.rails_env][the_shard] ||= {}
30
- @shard_names[ActiveRecordShards.rails_env][the_shard][try_slave] ||= {}
31
- @shard_names[ActiveRecordShards.rails_env][the_shard][try_slave][@on_slave] ||= begin
31
+ @shard_names[ActiveRecordShards.rails_env][the_shard][try_replica] ||= {}
32
+ @shard_names[ActiveRecordShards.rails_env][the_shard][try_replica][@on_replica] ||= begin
32
33
  s = ActiveRecordShards.rails_env.dup
33
34
  s << "_shard_#{the_shard}" if the_shard
34
- s << "_slave" if @on_slave && try_slave
35
+ s << "_replica" if @on_replica && try_replica
35
36
  s
36
37
  end
37
38
  end
@@ -46,25 +47,24 @@ module ActiveRecordShards
46
47
  end
47
48
  end
48
49
 
49
- PRIMARY = "primary".freeze
50
+ PRIMARY = "primary"
50
51
  def resolve_connection_name(sharded:, configurations:)
51
52
  resolved_shard = sharded ? shard : nil
52
-
53
- if !resolved_shard && !@on_slave
54
- return PRIMARY
55
- end
56
-
57
- @shard_names ||= {}
58
- @shard_names[ActiveRecordShards.rails_env] ||= {}
59
- @shard_names[ActiveRecordShards.rails_env][resolved_shard] ||= {}
60
- @shard_names[ActiveRecordShards.rails_env][resolved_shard][@on_slave] ||= begin
61
- s = ActiveRecordShards.rails_env.dup
62
- s << "_shard_#{resolved_shard}" if resolved_shard
63
-
64
- if @on_slave && configurations["#{s}_slave"] # fall back to master connection
65
- s << "_slave"
53
+ env = ActiveRecordShards.rails_env
54
+
55
+ @connection_names ||= {}
56
+ @connection_names[env] ||= {}
57
+ @connection_names[env][resolved_shard] ||= {}
58
+ @connection_names[env][resolved_shard][@on_replica] ||= begin
59
+ name = env.dup
60
+ name << "_shard_#{resolved_shard}" if resolved_shard
61
+ if @on_replica && configurations["#{name}_replica"]
62
+ "#{name}_replica"
63
+ else
64
+ # ActiveRecord always names its default connection pool 'primary'
65
+ # while everything else is named by the configuration name
66
+ resolved_shard ? name : PRIMARY
66
67
  end
67
- s
68
68
  end
69
69
  end
70
70
 
@@ -74,16 +74,18 @@ module ActiveRecordShards
74
74
  @shard = (new_shard || NO_SHARD)
75
75
  end
76
76
 
77
- def on_slave?
78
- @on_slave
77
+ def on_replica?
78
+ @on_replica
79
79
  end
80
+ alias_method :on_slave?, :on_replica?
80
81
 
81
- def on_slave=(new_slave)
82
- @on_slave = (new_slave == true)
82
+ def on_replica=(new_replica)
83
+ @on_replica = (new_replica == true)
83
84
  end
85
+ alias_method :on_slave=, :on_replica=
84
86
 
85
87
  def options
86
- { shard: @shard, slave: @on_slave }
88
+ { shard: @shard, replica: @on_replica }
87
89
  end
88
90
  end
89
91
  end
@@ -1,4 +1,5 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  module ActiveRecordShards
3
4
  class ShardSupport
4
5
  class ShardEnumerator
@@ -1,16 +1,23 @@
1
- # show which connection was picked to debug master/slave slowness when both servers are the same
1
+ # show which connection was picked to debug primary/replica slowness when both servers are the same
2
2
  module ActiveRecordShards
3
3
  module SqlComments
4
4
  module Methods
5
5
  def execute(query, name = nil)
6
- slave = ActiveRecord::Base.current_shard_selection.on_slave?
7
- query += " /* #{slave ? 'slave' : 'master'} */"
6
+ shard = ActiveRecord::Base.current_shard_selection.shard
7
+ shard_text = shard ? "shard #{shard}" : 'unsharded'
8
+ replica = ActiveRecord::Base.current_shard_selection.on_replica?
9
+ replica_text = replica ? 'replica' : 'primary'
10
+ query = "/* #{shard_text} #{replica_text} */ " + query
8
11
  super(query, name)
9
12
  end
10
13
  end
11
14
 
12
15
  def self.enable
13
- ActiveRecord::Base.on_shard(nil) { ActiveRecord::Base.connection.class.prepend(Methods) }
16
+ ActiveRecord::Base.on_replica do
17
+ ActiveRecord::Base.on_shard(nil) do
18
+ ActiveRecord::Base.connection.class.prepend(Methods)
19
+ end
20
+ end
14
21
  end
15
22
  end
16
23
  end
@@ -1,4 +1,5 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  require 'active_record_shards'
3
4
 
4
5
  %w[db:drop db:create db:abort_if_pending_migrations db:reset db:test:purge].each do |name|
@@ -8,15 +9,16 @@ end
8
9
  namespace :db do
9
10
  desc 'Drops the database for the current RAILS_ENV including shards'
10
11
  task drop: :load_config do
11
- ActiveRecord::Base.configurations.each do |key, conf|
12
- next if !key.starts_with?(ActiveRecordShards.rails_env) || key.ends_with?("_slave")
12
+ ActiveRecord::Base.configurations.to_h.each do |key, conf|
13
+ next if !key.start_with?(ActiveRecordShards.rails_env) || key.end_with?("_replica", "_slave")
14
+
13
15
  begin
14
16
  ActiveRecordShards::Tasks.root_connection(conf).drop_database(conf['database'])
15
17
  # rescue ActiveRecord::NoDatabaseError # TODO: exists in AR but never is raised here ...
16
18
  # $stderr.puts "Database '#{conf['database']}' does not exist"
17
- rescue StandardError => error
18
- $stderr.puts error, *error.backtrace
19
- $stderr.puts "Couldn't drop #{conf['database']}"
19
+ rescue StandardError => e
20
+ warn e, *e.backtrace
21
+ warn "Couldn't drop #{conf['database']}"
20
22
  end
21
23
  end
22
24
  end
@@ -28,25 +30,22 @@ namespace :db do
28
30
 
29
31
  desc "Create the database defined in config/database.yml for the current RAILS_ENV including shards"
30
32
  task create: :load_config do
31
- ActiveRecord::Base.configurations.each do |key, conf|
32
- next if !key.starts_with?(ActiveRecordShards.rails_env) || key.ends_with?("_slave")
33
- if ActiveRecord::VERSION::MAJOR >= 4
34
- begin
35
- # MysqlAdapter takes charset instead of encoding in Rails 4
36
- # https://github.com/rails/rails/commit/78b30fed9336336694fb2cb5d2825f95800b541c
37
- symbolized_configuration = conf.symbolize_keys
38
- symbolized_configuration[:charset] = symbolized_configuration[:encoding]
33
+ ActiveRecord::Base.configurations.to_h.each do |key, conf|
34
+ next if !key.start_with?(ActiveRecordShards.rails_env) || key.end_with?("_replica", "_slave")
35
+
36
+ begin
37
+ # MysqlAdapter takes charset instead of encoding in Rails 4.2 or greater
38
+ # https://github.com/rails/rails/blob/4-2-stable/activerecord/lib/active_record/tasks/mysql_database_tasks.rb#L85-L96
39
+ symbolized_configuration = conf.symbolize_keys
40
+ symbolized_configuration[:charset] = symbolized_configuration[:encoding]
39
41
 
40
- ActiveRecordShards::Tasks.root_connection(conf).create_database(conf['database'], symbolized_configuration)
41
- rescue ActiveRecord::StatementInvalid => ex
42
- if ex.message.include?('database exists')
43
- puts "#{conf['database']} already exists"
44
- else
45
- raise ex
46
- end
42
+ ActiveRecordShards::Tasks.root_connection(conf).create_database(conf['database'], symbolized_configuration)
43
+ rescue ActiveRecord::StatementInvalid => e
44
+ if e.message.include?('database exists')
45
+ puts "#{conf['database']} already exists"
46
+ else
47
+ raise e
47
48
  end
48
- else
49
- create_database(conf)
50
49
  end
51
50
  end
52
51
  ActiveRecord::Base.establish_connection(ActiveRecordShards.rails_env.to_sym)
@@ -56,16 +55,20 @@ namespace :db do
56
55
  task abort_if_pending_migrations: :environment do
57
56
  if defined? ActiveRecord
58
57
  pending_migrations =
59
- if Rails::VERSION::MAJOR >= 4
60
- ActiveRecord::Base.on_shard(nil) { ActiveRecord::Migrator.open(ActiveRecord::Migrator.migrations_paths).pending_migrations }
58
+ if ActiveRecord::VERSION::MAJOR >= 6
59
+ migrations = ActiveRecord::MigrationContext.new(ActiveRecord::Migrator.migrations_paths, ActiveRecord::SchemaMigration).migrations
60
+ ActiveRecord::Migrator.new(:up, migrations, ActiveRecord::SchemaMigration).pending_migrations
61
+ elsif ActiveRecord::VERSION::STRING >= "5.2.0"
62
+ migrations = ActiveRecord::MigrationContext.new(ActiveRecord::Migrator.migrations_paths).migrations
63
+ ActiveRecord::Migrator.new(:up, migrations).pending_migrations
61
64
  else
62
- ActiveRecord::Base.on_shard(nil) { ActiveRecord::Migrator.new(:up, 'db/migrate').pending_migrations }
65
+ ActiveRecord::Base.on_shard(nil) { ActiveRecord::Migrator.open(ActiveRecord::Migrator.migrations_paths).pending_migrations }
63
66
  end
64
67
 
65
68
  if pending_migrations.any?
66
- puts "You have #{pending_migrations.size} pending migrations:"
69
+ warn "You have #{pending_migrations.size} pending migrations:"
67
70
  pending_migrations.each do |pending_migration|
68
- puts ' %4d %s' % [pending_migration.version, pending_migration.name]
71
+ warn ' %4d %s' % [pending_migration.version, pending_migration.name]
69
72
  end
70
73
  abort %(Run "rake db:migrate" to update your database then try again.)
71
74
  end
@@ -89,17 +92,19 @@ end
89
92
 
90
93
  module ActiveRecordShards
91
94
  module Tasks
92
- if ActiveRecord::VERSION::MAJOR < 5
93
- def self.root_connection(conf)
94
- ActiveRecord::Base.send("#{conf['adapter']}_connection", conf.merge('database' => nil))
95
- end
96
- else
97
- def self.root_connection(conf)
98
- # this will trigger rails to load the adapter
95
+ class << self
96
+ def root_connection(conf)
99
97
  conf = conf.merge('database' => nil)
98
+ spec = spec_for(conf)
99
+
100
+ ActiveRecord::Base.send("#{conf['adapter']}_connection", spec.config)
101
+ end
102
+
103
+ private
104
+
105
+ def spec_for(conf)
100
106
  resolver = ActiveRecord::ConnectionAdapters::ConnectionSpecification::Resolver.new(ActiveRecord::Base.configurations)
101
107
  resolver.spec(conf)
102
- ActiveRecord::Base.send("#{conf['adapter']}_connection", conf)
103
108
  end
104
109
  end
105
110
  end
@@ -1,4 +1,5 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  require 'active_record'
3
4
  require 'active_record/base'
4
5
  require 'active_record_shards/configuration_parser'
@@ -7,7 +8,8 @@ require 'active_record_shards/shard_selection'
7
8
  require 'active_record_shards/connection_switcher'
8
9
  require 'active_record_shards/association_collection_connection_selection'
9
10
  require 'active_record_shards/migration'
10
- require 'active_record_shards/default_slave_patches'
11
+ require 'active_record_shards/default_replica_patches'
12
+ require 'active_record_shards/schema_dumper_extension'
11
13
 
12
14
  module ActiveRecordShards
13
15
  def self.rails_env
@@ -21,17 +23,119 @@ end
21
23
  ActiveRecord::Base.extend(ActiveRecordShards::ConfigurationParser)
22
24
  ActiveRecord::Base.extend(ActiveRecordShards::Model)
23
25
  ActiveRecord::Base.extend(ActiveRecordShards::ConnectionSwitcher)
24
- ActiveRecord::Base.extend(ActiveRecordShards::DefaultSlavePatches)
25
- ActiveRecord::Relation.include(ActiveRecordShards::DefaultSlavePatches::ActiveRelationPatches)
26
+ ActiveRecord::Base.extend(ActiveRecordShards::DefaultReplicaPatches)
27
+ ActiveRecord::Relation.include(ActiveRecordShards::DefaultReplicaPatches::ActiveRelationPatches)
26
28
  ActiveRecord::Associations::CollectionProxy.include(ActiveRecordShards::AssociationCollectionConnectionSelection)
29
+ ActiveRecord::Associations::Builder::HasAndBelongsToMany.include(ActiveRecordShards::DefaultReplicaPatches::Rails41HasAndBelongsToManyBuilderExtension)
30
+ ActiveRecord::SchemaDumper.prepend(ActiveRecordShards::SchemaDumperExtension)
27
31
 
28
32
  case "#{ActiveRecord::VERSION::MAJOR}.#{ActiveRecord::VERSION::MINOR}"
29
- when '3.2'
30
- require 'active_record_shards/patches-3-2'
31
33
  when '4.2'
32
34
  require 'active_record_shards/patches-4-2'
33
- when '5.0', '5.1'
34
- require 'active_record_shards/patches-5-0'
35
+
36
+ # https://github.com/rails/rails/blob/v4.2.11.3/activerecord/lib/active_record/associations/association.rb#L97
37
+ ActiveRecord::Associations::Association.prepend(ActiveRecordShards::DefaultReplicaPatches::AssociationsAssociationAssociationScopePatch)
38
+
39
+ # https://github.com/rails/rails/blob/v4.2.11.3/activerecord/lib/active_record/associations/singular_association.rb#L44-L53
40
+ ActiveRecord::Associations::SingularAssociation.prepend(ActiveRecordShards::DefaultReplicaPatches::AssociationsAssociationGetRecordsPatch)
41
+
42
+ # https://github.com/rails/rails/blob/v4.2.11.3/activerecord/lib/active_record/associations/collection_association.rb#L447-L456
43
+ ActiveRecord::Associations::CollectionAssociation.prepend(ActiveRecordShards::DefaultReplicaPatches::AssociationsAssociationGetRecordsPatch)
44
+
45
+ # https://github.com/rails/rails/blob/v4.2.11.3/activerecord/lib/active_record/associations/preloader/association.rb#L89
46
+ ActiveRecord::Associations::Preloader::Association.prepend(ActiveRecordShards::DefaultReplicaPatches::AssociationsPreloaderAssociationAssociatedRecordsByOwnerPatch)
47
+ when '5.0'
48
+ # https://github.com/rails/rails/blob/v5.0.7/activerecord/lib/active_record/associations/association.rb#L97
49
+ ActiveRecord::Associations::Association.prepend(ActiveRecordShards::DefaultReplicaPatches::AssociationsAssociationAssociationScopePatch)
50
+
51
+ # https://github.com/rails/rails/blob/v5.0.7/activerecord/lib/active_record/associations/singular_association.rb#L56-L65
52
+ ActiveRecord::Associations::SingularAssociation.prepend(ActiveRecordShards::DefaultReplicaPatches::AssociationsAssociationGetRecordsPatch)
53
+
54
+ # https://github.com/rails/rails/blob/v5.0.7/activerecord/lib/active_record/associations/collection_association.rb#L442-L451
55
+ ActiveRecord::Associations::CollectionAssociation.prepend(ActiveRecordShards::DefaultReplicaPatches::AssociationsAssociationGetRecordsPatch)
56
+
57
+ # https://github.com/rails/rails/blob/v5.0.7/activerecord/lib/active_record/associations/preloader/association.rb#L120
58
+ ActiveRecord::Associations::Preloader::Association.prepend(ActiveRecordShards::DefaultReplicaPatches::AssociationsPreloaderAssociationLoadRecordsPatch)
59
+ when '5.1'
60
+ # https://github.com/rails/rails/blob/v5.1.7/activerecord/lib/active_record/associations/association.rb#L97
61
+ ActiveRecord::Associations::Association.prepend(ActiveRecordShards::DefaultReplicaPatches::AssociationsAssociationAssociationScopePatch)
62
+
63
+ # https://github.com/rails/rails/blob/v5.1.7/activerecord/lib/active_record/associations/singular_association.rb#L41
64
+ ActiveRecord::Associations::SingularAssociation.prepend(ActiveRecordShards::DefaultReplicaPatches::AssociationsAssociationFindTargetPatch)
65
+
66
+ # https://github.com/rails/rails/blob/v5.1.7/activerecord/lib/active_record/associations/collection_association.rb#L305
67
+ ActiveRecord::Associations::CollectionAssociation.prepend(ActiveRecordShards::DefaultReplicaPatches::AssociationsAssociationFindTargetPatch)
68
+
69
+ # https://github.com/rails/rails/blob/v5.1.7/activerecord/lib/active_record/associations/preloader/association.rb#L120
70
+ ActiveRecord::Associations::Preloader::Association.prepend(ActiveRecordShards::DefaultReplicaPatches::AssociationsPreloaderAssociationLoadRecordsPatch)
71
+ when '5.2'
72
+ # https://github.com/rails/rails/blob/v5.2.6/activerecord/lib/active_record/relation.rb#L530
73
+ # But the #exec_queries method also calls #connection, and I don't know if we should patch that one, too...
74
+ ActiveRecord::Relation.prepend(ActiveRecordShards::DefaultReplicaPatches::Rails52RelationPatches)
75
+
76
+ # https://github.com/rails/rails/blob/v5.2.6/activerecord/lib/active_record/associations/singular_association.rb#L42
77
+ ActiveRecord::Associations::SingularAssociation.prepend(ActiveRecordShards::DefaultReplicaPatches::AssociationsAssociationFindTargetPatch)
78
+
79
+ # https://github.com/rails/rails/blob/v5.2.6/activerecord/lib/active_record/associations/collection_association.rb#L308
80
+ ActiveRecord::Associations::CollectionAssociation.prepend(ActiveRecordShards::DefaultReplicaPatches::AssociationsAssociationFindTargetPatch)
81
+
82
+ # https://github.com/rails/rails/blob/v5.2.6/activerecord/lib/active_record/associations/preloader/association.rb#L96
83
+ ActiveRecord::Associations::Preloader::Association.prepend(ActiveRecordShards::DefaultReplicaPatches::AssociationsPreloaderAssociationLoadRecordsPatch)
84
+ when '6.0'
85
+ # https://github.com/rails/rails/blob/v6.0.4/activerecord/lib/active_record/type_caster/connection.rb#L28
86
+ ActiveRecord::TypeCaster::Connection.prepend(ActiveRecordShards::DefaultReplicaPatches::TypeCasterConnectionConnectionPatch)
87
+
88
+ # https://github.com/rails/rails/blob/v6.0.4/activerecord/lib/active_record/schema.rb#L53-L54
89
+ ActiveRecord::Schema.prepend(ActiveRecordShards::DefaultReplicaPatches::SchemaDefinePatch)
90
+
91
+ # https://github.com/rails/rails/blob/v6.0.4/activerecord/lib/active_record/relation.rb#L739
92
+ # But the #exec_queries and #compute_cache_version methods also call #connection, and I don't know if we should patch those, too...
93
+ ActiveRecord::Relation.prepend(ActiveRecordShards::DefaultReplicaPatches::Rails52RelationPatches)
94
+
95
+ # https://github.com/rails/rails/blob/v6.0.4/activerecord/lib/active_record/associations/association.rb#L213
96
+ ActiveRecord::Associations::Association.prepend(ActiveRecordShards::DefaultReplicaPatches::AssociationsAssociationFindTargetPatch)
35
97
  else
36
98
  raise "ActiveRecordShards is not compatible with #{ActiveRecord::VERSION::STRING}"
37
99
  end
100
+
101
+ require 'active_record_shards/deprecation'
102
+
103
+ ActiveRecordShards::Deprecation.deprecate_methods(
104
+ ActiveRecordShards::AssociationCollectionConnectionSelection,
105
+ on_slave_if: :on_replica_if,
106
+ on_slave_unless: :on_replica_unless,
107
+ on_slave: :on_replica,
108
+ on_master: :on_primary,
109
+ on_master_if: :on_primary_if,
110
+ on_master_unless: :on_primary_unless
111
+ )
112
+
113
+ ActiveRecordShards::Deprecation.deprecate_methods(
114
+ ActiveRecordShards::ConnectionSwitcher,
115
+ on_slave_if: :on_replica_if,
116
+ on_slave_unless: :on_replica_unless,
117
+ on_master_or_slave: :on_primary_or_replica,
118
+ on_slave: :on_replica,
119
+ on_master: :on_primary,
120
+ on_master_if: :on_primary_if,
121
+ on_master_unless: :on_primary_unless,
122
+ on_slave?: :on_replica?
123
+ )
124
+
125
+ ActiveRecordShards::Deprecation.deprecate_methods(
126
+ ActiveRecordShards::DefaultReplicaPatches,
127
+ transaction_with_slave_off: :transaction_with_replica_off,
128
+ on_slave_unless_tx: :on_replica_unless_tx
129
+ )
130
+
131
+ ActiveRecordShards::Deprecation.deprecate_methods(
132
+ ActiveRecordShards::Model,
133
+ on_slave_by_default?: :on_replica_by_default?,
134
+ :on_slave_by_default= => :on_replica_by_default=
135
+ )
136
+
137
+ ActiveRecordShards::Deprecation.deprecate_methods(
138
+ ActiveRecordShards::ShardSelection,
139
+ on_slave?: :on_replica?,
140
+ :on_slave= => :on_replica=
141
+ )