activerecord 6.0.0 → 6.1.7.4
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +1413 -614
- data/MIT-LICENSE +1 -1
- data/README.rdoc +4 -4
- data/lib/active_record/aggregations.rb +5 -6
- data/lib/active_record/association_relation.rb +30 -10
- data/lib/active_record/associations/alias_tracker.rb +19 -16
- data/lib/active_record/associations/association.rb +55 -29
- data/lib/active_record/associations/association_scope.rb +19 -15
- data/lib/active_record/associations/belongs_to_association.rb +23 -10
- data/lib/active_record/associations/belongs_to_polymorphic_association.rb +8 -3
- data/lib/active_record/associations/builder/association.rb +32 -5
- data/lib/active_record/associations/builder/belongs_to.rb +10 -7
- data/lib/active_record/associations/builder/collection_association.rb +5 -4
- data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +0 -3
- data/lib/active_record/associations/builder/has_many.rb +6 -2
- data/lib/active_record/associations/builder/has_one.rb +11 -14
- data/lib/active_record/associations/builder/singular_association.rb +1 -1
- data/lib/active_record/associations/collection_association.rb +38 -13
- data/lib/active_record/associations/collection_proxy.rb +14 -7
- data/lib/active_record/associations/foreign_association.rb +13 -0
- data/lib/active_record/associations/has_many_association.rb +24 -3
- data/lib/active_record/associations/has_many_through_association.rb +10 -4
- data/lib/active_record/associations/has_one_association.rb +15 -1
- data/lib/active_record/associations/join_dependency/join_association.rb +39 -16
- data/lib/active_record/associations/join_dependency/join_part.rb +3 -3
- data/lib/active_record/associations/join_dependency.rb +77 -42
- data/lib/active_record/associations/preloader/association.rb +49 -25
- data/lib/active_record/associations/preloader/through_association.rb +2 -2
- data/lib/active_record/associations/preloader.rb +13 -8
- data/lib/active_record/associations/singular_association.rb +1 -1
- data/lib/active_record/associations/through_association.rb +1 -1
- data/lib/active_record/associations.rb +120 -13
- data/lib/active_record/attribute_assignment.rb +10 -9
- data/lib/active_record/attribute_methods/before_type_cast.rb +13 -10
- data/lib/active_record/attribute_methods/dirty.rb +3 -13
- data/lib/active_record/attribute_methods/primary_key.rb +6 -4
- data/lib/active_record/attribute_methods/query.rb +3 -6
- data/lib/active_record/attribute_methods/read.rb +8 -12
- data/lib/active_record/attribute_methods/serialization.rb +11 -6
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +12 -15
- data/lib/active_record/attribute_methods/write.rb +12 -21
- data/lib/active_record/attribute_methods.rb +64 -54
- data/lib/active_record/attributes.rb +33 -9
- data/lib/active_record/autosave_association.rb +63 -44
- data/lib/active_record/base.rb +2 -14
- data/lib/active_record/callbacks.rb +153 -24
- data/lib/active_record/coders/yaml_column.rb +24 -3
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +202 -138
- data/lib/active_record/connection_adapters/abstract/database_limits.rb +2 -44
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +87 -38
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +5 -10
- data/lib/active_record/connection_adapters/abstract/quoting.rb +44 -35
- data/lib/active_record/connection_adapters/abstract/savepoints.rb +3 -3
- data/lib/active_record/connection_adapters/abstract/schema_creation.rb +152 -116
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +145 -52
- data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +3 -3
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +267 -105
- data/lib/active_record/connection_adapters/abstract/transaction.rb +94 -36
- data/lib/active_record/connection_adapters/abstract_adapter.rb +76 -79
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +149 -115
- data/lib/active_record/connection_adapters/column.rb +15 -1
- data/lib/active_record/connection_adapters/deduplicable.rb +29 -0
- data/lib/active_record/connection_adapters/legacy_pool_manager.rb +35 -0
- data/lib/active_record/connection_adapters/mysql/column.rb +1 -1
- data/lib/active_record/connection_adapters/mysql/database_statements.rb +32 -36
- data/lib/active_record/connection_adapters/mysql/explain_pretty_printer.rb +1 -2
- data/lib/active_record/connection_adapters/mysql/quoting.rb +18 -3
- data/lib/active_record/connection_adapters/mysql/schema_creation.rb +32 -7
- data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +8 -0
- data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +5 -2
- data/lib/active_record/connection_adapters/mysql/schema_statements.rb +20 -13
- data/lib/active_record/connection_adapters/mysql/type_metadata.rb +10 -1
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +31 -13
- data/lib/active_record/connection_adapters/pool_config.rb +73 -0
- data/lib/active_record/connection_adapters/pool_manager.rb +47 -0
- data/lib/active_record/connection_adapters/postgresql/column.rb +24 -1
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +23 -56
- data/lib/active_record/connection_adapters/postgresql/oid/array.rb +0 -1
- data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +3 -5
- data/lib/active_record/connection_adapters/postgresql/oid/date.rb +2 -2
- data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +10 -2
- data/lib/active_record/connection_adapters/postgresql/oid/enum.rb +0 -1
- data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +0 -1
- data/lib/active_record/connection_adapters/postgresql/oid/interval.rb +49 -0
- data/lib/active_record/connection_adapters/postgresql/oid/legacy_point.rb +2 -3
- data/lib/active_record/connection_adapters/postgresql/oid/macaddr.rb +25 -0
- data/lib/active_record/connection_adapters/postgresql/oid/money.rb +2 -2
- data/lib/active_record/connection_adapters/postgresql/oid/oid.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/oid/point.rb +2 -3
- data/lib/active_record/connection_adapters/postgresql/oid/range.rb +24 -6
- data/lib/active_record/connection_adapters/postgresql/oid/specialized_string.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +11 -2
- data/lib/active_record/connection_adapters/postgresql/oid.rb +2 -0
- data/lib/active_record/connection_adapters/postgresql/quoting.rb +30 -4
- data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +2 -2
- data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +7 -3
- data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +0 -1
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +72 -54
- data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +8 -0
- data/lib/active_record/connection_adapters/postgresql/utils.rb +0 -1
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +84 -66
- data/lib/active_record/connection_adapters/schema_cache.rb +130 -15
- data/lib/active_record/connection_adapters/sql_type_metadata.rb +8 -0
- data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +40 -12
- data/lib/active_record/connection_adapters/sqlite3/quoting.rb +1 -2
- data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +5 -1
- data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +38 -5
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +61 -57
- data/lib/active_record/connection_adapters/statement_pool.rb +0 -1
- data/lib/active_record/connection_adapters.rb +52 -0
- data/lib/active_record/connection_handling.rb +219 -81
- data/lib/active_record/core.rb +283 -71
- data/lib/active_record/counter_cache.rb +4 -1
- data/lib/active_record/database_configurations/connection_url_resolver.rb +99 -0
- data/lib/active_record/database_configurations/database_config.rb +52 -9
- data/lib/active_record/database_configurations/hash_config.rb +54 -8
- data/lib/active_record/database_configurations/url_config.rb +15 -41
- data/lib/active_record/database_configurations.rb +125 -85
- data/lib/active_record/delegated_type.rb +209 -0
- data/lib/active_record/destroy_association_async_job.rb +36 -0
- data/lib/active_record/dynamic_matchers.rb +2 -3
- data/lib/active_record/enum.rb +80 -38
- data/lib/active_record/errors.rb +47 -12
- data/lib/active_record/explain.rb +9 -5
- data/lib/active_record/explain_subscriber.rb +1 -1
- data/lib/active_record/fixture_set/file.rb +10 -17
- data/lib/active_record/fixture_set/model_metadata.rb +1 -2
- data/lib/active_record/fixture_set/render_context.rb +1 -1
- data/lib/active_record/fixture_set/table_row.rb +2 -3
- data/lib/active_record/fixture_set/table_rows.rb +0 -1
- data/lib/active_record/fixtures.rb +58 -12
- data/lib/active_record/gem_version.rb +3 -3
- data/lib/active_record/inheritance.rb +40 -21
- data/lib/active_record/insert_all.rb +43 -10
- data/lib/active_record/integration.rb +3 -5
- data/lib/active_record/internal_metadata.rb +18 -7
- data/lib/active_record/legacy_yaml_adapter.rb +7 -3
- data/lib/active_record/locking/optimistic.rb +33 -18
- data/lib/active_record/locking/pessimistic.rb +6 -2
- data/lib/active_record/log_subscriber.rb +28 -9
- data/lib/active_record/middleware/database_selector/resolver/session.rb +3 -0
- data/lib/active_record/middleware/database_selector/resolver.rb +14 -14
- data/lib/active_record/middleware/database_selector.rb +4 -2
- data/lib/active_record/migration/command_recorder.rb +53 -45
- data/lib/active_record/migration/compatibility.rb +75 -21
- data/lib/active_record/migration/join_table.rb +0 -1
- data/lib/active_record/migration.rb +115 -85
- data/lib/active_record/model_schema.rb +120 -15
- data/lib/active_record/nested_attributes.rb +2 -5
- data/lib/active_record/no_touching.rb +1 -1
- data/lib/active_record/null_relation.rb +0 -1
- data/lib/active_record/persistence.rb +50 -46
- data/lib/active_record/query_cache.rb +15 -5
- data/lib/active_record/querying.rb +12 -7
- data/lib/active_record/railtie.rb +65 -45
- data/lib/active_record/railties/console_sandbox.rb +2 -4
- data/lib/active_record/railties/databases.rake +280 -99
- data/lib/active_record/readonly_attributes.rb +4 -0
- data/lib/active_record/reflection.rb +77 -63
- data/lib/active_record/relation/batches/batch_enumerator.rb +25 -9
- data/lib/active_record/relation/batches.rb +38 -32
- data/lib/active_record/relation/calculations.rb +106 -45
- data/lib/active_record/relation/delegation.rb +9 -7
- data/lib/active_record/relation/finder_methods.rb +55 -17
- data/lib/active_record/relation/from_clause.rb +5 -1
- data/lib/active_record/relation/merger.rb +27 -26
- data/lib/active_record/relation/predicate_builder/array_handler.rb +8 -9
- data/lib/active_record/relation/predicate_builder/association_query_value.rb +4 -5
- data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +10 -6
- data/lib/active_record/relation/predicate_builder/relation_handler.rb +1 -1
- data/lib/active_record/relation/predicate_builder.rb +59 -40
- data/lib/active_record/relation/query_methods.rb +346 -181
- data/lib/active_record/relation/record_fetch_warning.rb +3 -3
- data/lib/active_record/relation/spawn_methods.rb +8 -8
- data/lib/active_record/relation/where_clause.rb +111 -62
- data/lib/active_record/relation.rb +116 -82
- data/lib/active_record/result.rb +41 -34
- data/lib/active_record/runtime_registry.rb +2 -2
- data/lib/active_record/sanitization.rb +6 -17
- data/lib/active_record/schema_dumper.rb +34 -4
- data/lib/active_record/schema_migration.rb +2 -8
- data/lib/active_record/scoping/default.rb +1 -4
- data/lib/active_record/scoping/named.rb +7 -18
- data/lib/active_record/scoping.rb +0 -1
- data/lib/active_record/secure_token.rb +16 -8
- data/lib/active_record/serialization.rb +5 -3
- data/lib/active_record/signed_id.rb +116 -0
- data/lib/active_record/statement_cache.rb +20 -4
- data/lib/active_record/store.rb +9 -4
- data/lib/active_record/suppressor.rb +2 -2
- data/lib/active_record/table_metadata.rb +42 -36
- data/lib/active_record/tasks/database_tasks.rb +140 -113
- data/lib/active_record/tasks/mysql_database_tasks.rb +34 -36
- data/lib/active_record/tasks/postgresql_database_tasks.rb +24 -27
- data/lib/active_record/tasks/sqlite_database_tasks.rb +13 -10
- data/lib/active_record/test_databases.rb +5 -4
- data/lib/active_record/test_fixtures.rb +87 -20
- data/lib/active_record/timestamp.rb +4 -7
- data/lib/active_record/touch_later.rb +20 -21
- data/lib/active_record/transactions.rb +26 -73
- data/lib/active_record/type/adapter_specific_registry.rb +2 -5
- data/lib/active_record/type/hash_lookup_type_map.rb +0 -1
- data/lib/active_record/type/serialized.rb +6 -3
- data/lib/active_record/type/time.rb +10 -0
- data/lib/active_record/type/type_map.rb +0 -1
- data/lib/active_record/type/unsigned_integer.rb +0 -1
- data/lib/active_record/type.rb +8 -2
- data/lib/active_record/type_caster/connection.rb +0 -1
- data/lib/active_record/type_caster/map.rb +8 -5
- data/lib/active_record/validations/associated.rb +1 -2
- data/lib/active_record/validations/numericality.rb +35 -0
- data/lib/active_record/validations/uniqueness.rb +24 -4
- data/lib/active_record/validations.rb +3 -3
- data/lib/active_record.rb +7 -13
- data/lib/arel/attributes/attribute.rb +4 -0
- data/lib/arel/collectors/bind.rb +5 -0
- data/lib/arel/collectors/composite.rb +8 -0
- data/lib/arel/collectors/sql_string.rb +7 -0
- data/lib/arel/collectors/substitute_binds.rb +7 -0
- data/lib/arel/nodes/binary.rb +82 -8
- data/lib/arel/nodes/bind_param.rb +8 -0
- data/lib/arel/nodes/casted.rb +21 -9
- data/lib/arel/nodes/equality.rb +6 -9
- data/lib/arel/nodes/grouping.rb +3 -0
- data/lib/arel/nodes/homogeneous_in.rb +76 -0
- data/lib/arel/nodes/in.rb +8 -1
- data/lib/arel/nodes/infix_operation.rb +13 -1
- data/lib/arel/nodes/join_source.rb +1 -1
- data/lib/arel/nodes/node.rb +7 -6
- data/lib/arel/nodes/ordering.rb +27 -0
- data/lib/arel/nodes/sql_literal.rb +3 -0
- data/lib/arel/nodes/table_alias.rb +7 -3
- data/lib/arel/nodes/unary.rb +0 -1
- data/lib/arel/nodes.rb +3 -1
- data/lib/arel/predications.rb +17 -24
- data/lib/arel/select_manager.rb +1 -2
- data/lib/arel/table.rb +13 -5
- data/lib/arel/visitors/dot.rb +14 -3
- data/lib/arel/visitors/mysql.rb +11 -1
- data/lib/arel/visitors/postgresql.rb +15 -5
- data/lib/arel/visitors/sqlite.rb +0 -1
- data/lib/arel/visitors/to_sql.rb +89 -79
- data/lib/arel/visitors/visitor.rb +0 -1
- data/lib/arel/visitors.rb +0 -7
- data/lib/arel.rb +15 -12
- data/lib/rails/generators/active_record/application_record/application_record_generator.rb +0 -1
- data/lib/rails/generators/active_record/migration/migration_generator.rb +1 -0
- data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb.tt +2 -0
- data/lib/rails/generators/active_record/migration/templates/migration.rb.tt +4 -4
- data/lib/rails/generators/active_record/migration.rb +6 -2
- data/lib/rails/generators/active_record/model/model_generator.rb +38 -2
- data/lib/rails/generators/active_record/model/templates/abstract_base_class.rb.tt +7 -0
- metadata +31 -27
- data/lib/active_record/attribute_decorators.rb +0 -90
- data/lib/active_record/connection_adapters/connection_specification.rb +0 -297
- data/lib/active_record/connection_adapters/determine_if_preparable_visitor.rb +0 -29
- data/lib/active_record/define_callbacks.rb +0 -22
- data/lib/active_record/railties/collection_cache_association_loading.rb +0 -34
- data/lib/active_record/relation/predicate_builder/base_handler.rb +0 -18
- data/lib/active_record/relation/where_clause_factory.rb +0 -33
- data/lib/arel/attributes.rb +0 -22
- data/lib/arel/visitors/depth_first.rb +0 -204
- data/lib/arel/visitors/ibm_db.rb +0 -34
- data/lib/arel/visitors/informix.rb +0 -62
- data/lib/arel/visitors/mssql.rb +0 -157
- data/lib/arel/visitors/oracle.rb +0 -159
- data/lib/arel/visitors/oracle12.rb +0 -66
- data/lib/arel/visitors/where_sql.rb +0 -23
@@ -47,8 +47,9 @@ module ActiveRecord
|
|
47
47
|
# The exceptions AdapterNotSpecified, AdapterNotFound and +ArgumentError+
|
48
48
|
# may be returned on an error.
|
49
49
|
def establish_connection(config_or_env = nil)
|
50
|
-
|
51
|
-
|
50
|
+
config_or_env ||= DEFAULT_ENV.call.to_sym
|
51
|
+
db_config, owner_name = resolve_config_for_connection(config_or_env)
|
52
|
+
connection_handler.establish_connection(db_config, owner_name: owner_name, role: current_role, shard: current_shard)
|
52
53
|
end
|
53
54
|
|
54
55
|
# Connects a model to the databases specified. The +database+ keyword
|
@@ -64,25 +65,56 @@ module ActiveRecord
|
|
64
65
|
# connects_to database: { writing: :primary, reading: :primary_replica }
|
65
66
|
# end
|
66
67
|
#
|
67
|
-
#
|
68
|
-
|
68
|
+
# +connects_to+ also supports horizontal sharding. The horizontal sharding API
|
69
|
+
# also supports read replicas. Connect a model to a list of shards like this:
|
70
|
+
#
|
71
|
+
# class AnimalsModel < ApplicationRecord
|
72
|
+
# self.abstract_class = true
|
73
|
+
#
|
74
|
+
# connects_to shards: {
|
75
|
+
# default: { writing: :primary, reading: :primary_replica },
|
76
|
+
# shard_two: { writing: :primary_shard_two, reading: :primary_shard_replica_two }
|
77
|
+
# }
|
78
|
+
# end
|
79
|
+
#
|
80
|
+
# Returns an array of database connections.
|
81
|
+
def connects_to(database: {}, shards: {})
|
82
|
+
raise NotImplementedError, "`connects_to` can only be called on ActiveRecord::Base or abstract classes" unless self == Base || abstract_class?
|
83
|
+
|
84
|
+
if database.present? && shards.present?
|
85
|
+
raise ArgumentError, "`connects_to` can only accept a `database` or `shards` argument, but not both arguments."
|
86
|
+
end
|
87
|
+
|
69
88
|
connections = []
|
70
89
|
|
71
90
|
database.each do |role, database_key|
|
72
|
-
|
91
|
+
db_config, owner_name = resolve_config_for_connection(database_key)
|
73
92
|
handler = lookup_connection_handler(role.to_sym)
|
74
93
|
|
75
|
-
|
94
|
+
self.connection_class = true
|
95
|
+
connections << handler.establish_connection(db_config, owner_name: owner_name, role: role)
|
96
|
+
end
|
97
|
+
|
98
|
+
shards.each do |shard, database_keys|
|
99
|
+
database_keys.each do |role, database_key|
|
100
|
+
db_config, owner_name = resolve_config_for_connection(database_key)
|
101
|
+
handler = lookup_connection_handler(role.to_sym)
|
102
|
+
|
103
|
+
self.connection_class = true
|
104
|
+
connections << handler.establish_connection(db_config, owner_name: owner_name, role: role, shard: shard.to_sym)
|
105
|
+
end
|
76
106
|
end
|
77
107
|
|
78
108
|
connections
|
79
109
|
end
|
80
110
|
|
81
|
-
# Connects to a
|
82
|
-
#
|
111
|
+
# Connects to a role (ex writing, reading or a custom role) and/or
|
112
|
+
# shard for the duration of the block. At the end of the block the
|
113
|
+
# connection will be returned to the original role / shard.
|
83
114
|
#
|
84
|
-
# If a role is passed, Active Record will look up the connection
|
85
|
-
# based on the requested role
|
115
|
+
# If only a role is passed, Active Record will look up the connection
|
116
|
+
# based on the requested role. If a non-established role is requested
|
117
|
+
# an +ActiveRecord::ConnectionNotEstablished+ error will be raised:
|
86
118
|
#
|
87
119
|
# ActiveRecord::Base.connected_to(role: :writing) do
|
88
120
|
# Dog.create! # creates dog using dog writing connection
|
@@ -92,103 +124,155 @@ module ActiveRecord
|
|
92
124
|
# Dog.create! # throws exception because we're on a replica
|
93
125
|
# end
|
94
126
|
#
|
95
|
-
#
|
96
|
-
#
|
97
|
-
#
|
127
|
+
# When swapping to a shard, the role must be passed as well. If a non-existent
|
128
|
+
# shard is passed, an +ActiveRecord::ConnectionNotEstablished+ error will be
|
129
|
+
# raised.
|
98
130
|
#
|
99
|
-
#
|
100
|
-
#
|
101
|
-
# expects a symbol that corresponds to the database key in your config.
|
131
|
+
# When a shard and role is passed, Active Record will first lookup the role,
|
132
|
+
# and then look up the connection by shard key.
|
102
133
|
#
|
103
|
-
# ActiveRecord::Base.connected_to(
|
104
|
-
# Dog.
|
134
|
+
# ActiveRecord::Base.connected_to(role: :reading, shard: :shard_one_replica) do
|
135
|
+
# Dog.first # finds first Dog record stored on the shard one replica
|
105
136
|
# end
|
106
137
|
#
|
107
|
-
#
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
138
|
+
# The database kwarg is deprecated and will be removed in Rails 7.0.0 without replacement.
|
139
|
+
def connected_to(database: nil, role: nil, shard: nil, prevent_writes: false, &blk)
|
140
|
+
if legacy_connection_handling
|
141
|
+
if self != Base
|
142
|
+
raise NotImplementedError, "`connected_to` can only be called on ActiveRecord::Base with legacy connection handling."
|
143
|
+
end
|
144
|
+
else
|
145
|
+
if self != Base && !abstract_class
|
146
|
+
raise NotImplementedError, "calling `connected_to` is only allowed on ActiveRecord::Base or abstract classes."
|
147
|
+
end
|
148
|
+
|
149
|
+
if name != connection_specification_name && !primary_class?
|
150
|
+
raise NotImplementedError, "calling `connected_to` is only allowed on the abstract class that established the connection."
|
151
|
+
end
|
152
|
+
end
|
153
|
+
|
154
|
+
if database && (role || shard)
|
155
|
+
raise ArgumentError, "`connected_to` cannot accept a `database` argument with any other arguments."
|
120
156
|
elsif database
|
157
|
+
ActiveSupport::Deprecation.warn("The database key in `connected_to` is deprecated. It will be removed in Rails 7.0.0 without replacement.")
|
158
|
+
|
121
159
|
if database.is_a?(Hash)
|
122
160
|
role, database = database.first
|
123
161
|
role = role.to_sym
|
124
162
|
end
|
125
163
|
|
126
|
-
|
164
|
+
db_config, owner_name = resolve_config_for_connection(database)
|
127
165
|
handler = lookup_connection_handler(role)
|
128
166
|
|
129
|
-
handler.establish_connection(
|
167
|
+
handler.establish_connection(db_config, owner_name: owner_name, role: role)
|
130
168
|
|
131
169
|
with_handler(role, &blk)
|
132
|
-
elsif role
|
133
|
-
|
170
|
+
elsif role || shard
|
171
|
+
unless role
|
172
|
+
raise ArgumentError, "`connected_to` cannot accept a `shard` argument without a `role`."
|
173
|
+
end
|
174
|
+
|
175
|
+
with_role_and_shard(role, shard, prevent_writes, &blk)
|
134
176
|
else
|
135
|
-
raise ArgumentError, "must provide a `
|
177
|
+
raise ArgumentError, "must provide a `shard` and/or `role`."
|
136
178
|
end
|
137
179
|
end
|
138
180
|
|
139
|
-
#
|
181
|
+
# Connects a role and/or shard to the provided connection names. Optionally +prevent_writes+
|
182
|
+
# can be passed to block writes on a connection. +reading+ will automatically set
|
183
|
+
# +prevent_writes+ to true.
|
140
184
|
#
|
141
|
-
#
|
142
|
-
#
|
143
|
-
#
|
185
|
+
# +connected_to_many+ is an alternative to deeply nested +connected_to+ blocks.
|
186
|
+
#
|
187
|
+
# Usage:
|
188
|
+
#
|
189
|
+
# ActiveRecord::Base.connected_to_many(AnimalsRecord, MealsRecord, role: :reading) do
|
190
|
+
# Dog.first # Read from animals replica
|
191
|
+
# Dinner.first # Read from meals replica
|
192
|
+
# Person.first # Read from primary writer
|
144
193
|
# end
|
145
|
-
def
|
146
|
-
|
194
|
+
def connected_to_many(*classes, role:, shard: nil, prevent_writes: false)
|
195
|
+
classes = classes.flatten
|
196
|
+
|
197
|
+
if legacy_connection_handling
|
198
|
+
raise NotImplementedError, "connected_to_many is not available with legacy connection handling"
|
199
|
+
end
|
200
|
+
|
201
|
+
if self != Base || classes.include?(Base)
|
202
|
+
raise NotImplementedError, "connected_to_many can only be called on ActiveRecord::Base."
|
203
|
+
end
|
204
|
+
|
205
|
+
prevent_writes = true if role == reading_role
|
206
|
+
|
207
|
+
connected_to_stack << { role: role, shard: shard, prevent_writes: prevent_writes, klasses: classes }
|
208
|
+
yield
|
209
|
+
ensure
|
210
|
+
connected_to_stack.pop
|
147
211
|
end
|
148
212
|
|
149
|
-
#
|
213
|
+
# Use a specified connection.
|
150
214
|
#
|
151
|
-
#
|
152
|
-
#
|
153
|
-
# end
|
215
|
+
# This method is useful for ensuring that a specific connection is
|
216
|
+
# being used. For example, when booting a console in readonly mode.
|
154
217
|
#
|
155
|
-
#
|
156
|
-
#
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
218
|
+
# It is not recommended to use this method in a request since it
|
219
|
+
# does not yield to a block like +connected_to+.
|
220
|
+
def connecting_to(role: default_role, shard: default_shard, prevent_writes: false)
|
221
|
+
if legacy_connection_handling
|
222
|
+
raise NotImplementedError, "`connecting_to` is not available with `legacy_connection_handling`."
|
223
|
+
end
|
161
224
|
|
162
|
-
|
163
|
-
handler_key ||= ActiveRecord::Base.writing_role
|
164
|
-
connection_handlers[handler_key] ||= ActiveRecord::ConnectionAdapters::ConnectionHandler.new
|
165
|
-
end
|
225
|
+
prevent_writes = true if role == reading_role
|
166
226
|
|
167
|
-
|
168
|
-
handler = lookup_connection_handler(handler_key)
|
169
|
-
swap_connection_handler(handler, &blk)
|
227
|
+
self.connected_to_stack << { role: role, shard: shard, prevent_writes: prevent_writes, klasses: [self] }
|
170
228
|
end
|
171
229
|
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
230
|
+
# Prevent writing to the database regardless of role.
|
231
|
+
#
|
232
|
+
# In some cases you may want to prevent writes to the database
|
233
|
+
# even if you are on a database that can write. +while_preventing_writes+
|
234
|
+
# will prevent writes to the database for the duration of the block.
|
235
|
+
#
|
236
|
+
# This method does not provide the same protection as a readonly
|
237
|
+
# user and is meant to be a safeguard against accidental writes.
|
238
|
+
#
|
239
|
+
# See +READ_QUERY+ for the queries that are blocked by this
|
240
|
+
# method.
|
241
|
+
def while_preventing_writes(enabled = true, &block)
|
242
|
+
if legacy_connection_handling
|
243
|
+
connection_handler.while_preventing_writes(enabled, &block)
|
244
|
+
else
|
245
|
+
connected_to(role: current_role, prevent_writes: enabled, &block)
|
246
|
+
end
|
247
|
+
end
|
178
248
|
|
179
|
-
|
180
|
-
|
181
|
-
|
249
|
+
# Returns true if role is the current connected role.
|
250
|
+
#
|
251
|
+
# ActiveRecord::Base.connected_to(role: :writing) do
|
252
|
+
# ActiveRecord::Base.connected_to?(role: :writing) #=> true
|
253
|
+
# ActiveRecord::Base.connected_to?(role: :reading) #=> false
|
254
|
+
# end
|
255
|
+
def connected_to?(role:, shard: ActiveRecord::Base.default_shard)
|
256
|
+
current_role == role.to_sym && current_shard == shard.to_sym
|
257
|
+
end
|
182
258
|
|
183
|
-
|
259
|
+
def lookup_connection_handler(handler_key) # :nodoc:
|
260
|
+
if ActiveRecord::Base.legacy_connection_handling
|
261
|
+
handler_key ||= ActiveRecord::Base.writing_role
|
262
|
+
connection_handlers[handler_key] ||= ActiveRecord::ConnectionAdapters::ConnectionHandler.new
|
263
|
+
else
|
264
|
+
ActiveRecord::Base.connection_handler
|
265
|
+
end
|
184
266
|
end
|
185
267
|
|
186
268
|
# Clears the query cache for all connections associated with the current thread.
|
187
269
|
def clear_query_caches_for_current_thread
|
188
|
-
ActiveRecord::Base.
|
189
|
-
|
190
|
-
|
270
|
+
if ActiveRecord::Base.legacy_connection_handling
|
271
|
+
ActiveRecord::Base.connection_handlers.each_value do |handler|
|
272
|
+
clear_on_handler(handler)
|
191
273
|
end
|
274
|
+
else
|
275
|
+
clear_on_handler(ActiveRecord::Base.connection_handler)
|
192
276
|
end
|
193
277
|
end
|
194
278
|
|
@@ -201,10 +285,10 @@ module ActiveRecord
|
|
201
285
|
|
202
286
|
attr_writer :connection_specification_name
|
203
287
|
|
204
|
-
# Return the specification name from the current class or its parent.
|
288
|
+
# Return the connection specification name from the current class or its parent.
|
205
289
|
def connection_specification_name
|
206
290
|
if !defined?(@connection_specification_name) || @connection_specification_name.nil?
|
207
|
-
return
|
291
|
+
return self == Base ? Base.name : superclass.connection_specification_name
|
208
292
|
end
|
209
293
|
@connection_specification_name
|
210
294
|
end
|
@@ -220,20 +304,32 @@ module ActiveRecord
|
|
220
304
|
#
|
221
305
|
# Please use only for reading.
|
222
306
|
def connection_config
|
223
|
-
connection_pool.
|
307
|
+
connection_pool.db_config.configuration_hash
|
308
|
+
end
|
309
|
+
deprecate connection_config: "Use connection_db_config instead"
|
310
|
+
|
311
|
+
# Returns the db_config object from the associated connection:
|
312
|
+
#
|
313
|
+
# ActiveRecord::Base.connection_db_config
|
314
|
+
# #<ActiveRecord::DatabaseConfigurations::HashConfig:0x00007fd1acbded10 @env_name="development",
|
315
|
+
# @name="primary", @config={pool: 5, timeout: 5000, database: "db/development.sqlite3", adapter: "sqlite3"}>
|
316
|
+
#
|
317
|
+
# Use only for reading.
|
318
|
+
def connection_db_config
|
319
|
+
connection_pool.db_config
|
224
320
|
end
|
225
321
|
|
226
322
|
def connection_pool
|
227
|
-
connection_handler.retrieve_connection_pool(connection_specification_name) || raise(ConnectionNotEstablished)
|
323
|
+
connection_handler.retrieve_connection_pool(connection_specification_name, role: current_role, shard: current_shard) || raise(ConnectionNotEstablished)
|
228
324
|
end
|
229
325
|
|
230
326
|
def retrieve_connection
|
231
|
-
connection_handler.retrieve_connection(connection_specification_name)
|
327
|
+
connection_handler.retrieve_connection(connection_specification_name, role: current_role, shard: current_shard)
|
232
328
|
end
|
233
329
|
|
234
330
|
# Returns +true+ if Active Record is connected.
|
235
331
|
def connected?
|
236
|
-
connection_handler.connected?(connection_specification_name)
|
332
|
+
connection_handler.connected?(connection_specification_name, role: current_role, shard: current_shard)
|
237
333
|
end
|
238
334
|
|
239
335
|
def remove_connection(name = nil)
|
@@ -241,11 +337,11 @@ module ActiveRecord
|
|
241
337
|
# if removing a connection that has a pool, we reset the
|
242
338
|
# connection_specification_name so it will use the parent
|
243
339
|
# pool.
|
244
|
-
if connection_handler.retrieve_connection_pool(name)
|
340
|
+
if connection_handler.retrieve_connection_pool(name, role: current_role, shard: current_shard)
|
245
341
|
self.connection_specification_name = nil
|
246
342
|
end
|
247
343
|
|
248
|
-
connection_handler.
|
344
|
+
connection_handler.remove_connection_pool(name, role: current_role, shard: current_shard)
|
249
345
|
end
|
250
346
|
|
251
347
|
def clear_cache! # :nodoc:
|
@@ -256,10 +352,52 @@ module ActiveRecord
|
|
256
352
|
:clear_all_connections!, :flush_idle_connections!, to: :connection_handler
|
257
353
|
|
258
354
|
private
|
355
|
+
def clear_on_handler(handler)
|
356
|
+
handler.all_connection_pools.each do |pool|
|
357
|
+
pool.connection.clear_query_cache if pool.active_connection?
|
358
|
+
end
|
359
|
+
end
|
360
|
+
|
361
|
+
def resolve_config_for_connection(config_or_env)
|
362
|
+
raise "Anonymous class is not allowed." unless name
|
363
|
+
|
364
|
+
owner_name = primary_class? ? Base.name : name
|
365
|
+
self.connection_specification_name = owner_name
|
366
|
+
|
367
|
+
db_config = Base.configurations.resolve(config_or_env)
|
368
|
+
[db_config, self]
|
369
|
+
end
|
370
|
+
|
371
|
+
def with_handler(handler_key, &blk)
|
372
|
+
handler = lookup_connection_handler(handler_key)
|
373
|
+
swap_connection_handler(handler, &blk)
|
374
|
+
end
|
375
|
+
|
376
|
+
def with_role_and_shard(role, shard, prevent_writes)
|
377
|
+
prevent_writes = true if role == reading_role
|
378
|
+
|
379
|
+
if ActiveRecord::Base.legacy_connection_handling
|
380
|
+
with_handler(role.to_sym) do
|
381
|
+
connection_handler.while_preventing_writes(prevent_writes) do
|
382
|
+
self.connected_to_stack << { shard: shard, klasses: [self] }
|
383
|
+
yield
|
384
|
+
end
|
385
|
+
end
|
386
|
+
else
|
387
|
+
self.connected_to_stack << { role: role, shard: shard, prevent_writes: prevent_writes, klasses: [self] }
|
388
|
+
return_value = yield
|
389
|
+
return_value.load if return_value.is_a? ActiveRecord::Relation
|
390
|
+
return_value
|
391
|
+
end
|
392
|
+
ensure
|
393
|
+
self.connected_to_stack.pop
|
394
|
+
end
|
259
395
|
|
260
396
|
def swap_connection_handler(handler, &blk) # :nodoc:
|
261
397
|
old_handler, ActiveRecord::Base.connection_handler = ActiveRecord::Base.connection_handler, handler
|
262
|
-
yield
|
398
|
+
return_value = yield
|
399
|
+
return_value.load if return_value.is_a? ActiveRecord::Relation
|
400
|
+
return_value
|
263
401
|
ensure
|
264
402
|
ActiveRecord::Base.connection_handler = old_handler
|
265
403
|
end
|