activerecord 8.0.0.1 → 8.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +208 -0
- data/lib/active_record/associations/alias_tracker.rb +6 -4
- data/lib/active_record/associations/belongs_to_association.rb +7 -1
- data/lib/active_record/associations/join_dependency/join_association.rb +25 -27
- data/lib/active_record/attribute_methods/primary_key.rb +2 -1
- data/lib/active_record/attribute_methods.rb +22 -17
- data/lib/active_record/attributes.rb +2 -2
- data/lib/active_record/autosave_association.rb +21 -11
- data/lib/active_record/connection_adapters/abstract/connection_handler.rb +17 -14
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +47 -34
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +5 -1
- data/lib/active_record/connection_adapters/abstract_adapter.rb +39 -22
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +14 -7
- data/lib/active_record/connection_adapters/mysql/quoting.rb +7 -1
- data/lib/active_record/connection_adapters/mysql/schema_statements.rb +7 -0
- data/lib/active_record/connection_adapters/mysql2/database_statements.rb +57 -11
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +8 -1
- data/lib/active_record/connection_adapters/pool_config.rb +7 -7
- data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +14 -12
- data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +7 -2
- data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +5 -1
- data/lib/active_record/connection_adapters/sqlite3/quoting.rb +13 -0
- data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +2 -0
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +7 -2
- data/lib/active_record/connection_adapters/statement_pool.rb +4 -2
- data/lib/active_record/connection_adapters/trilogy_adapter.rb +1 -1
- data/lib/active_record/core.rb +31 -2
- data/lib/active_record/counter_cache.rb +1 -1
- data/lib/active_record/database_configurations/connection_url_resolver.rb +3 -1
- data/lib/active_record/delegated_type.rb +17 -17
- data/lib/active_record/future_result.rb +3 -3
- data/lib/active_record/gem_version.rb +2 -2
- data/lib/active_record/migration/command_recorder.rb +5 -2
- data/lib/active_record/railties/databases.rake +1 -1
- data/lib/active_record/relation/calculations.rb +23 -17
- data/lib/active_record/relation/predicate_builder/association_query_value.rb +2 -0
- data/lib/active_record/relation/query_attribute.rb +1 -1
- data/lib/active_record/relation/query_methods.rb +1 -1
- data/lib/active_record/relation.rb +1 -1
- data/lib/active_record/schema_dumper.rb +29 -11
- data/lib/active_record/signed_id.rb +4 -3
- data/lib/active_record/statement_cache.rb +2 -2
- data/lib/active_record/transactions.rb +5 -6
- data/lib/active_record.rb +4 -2
- data/lib/arel/collectors/bind.rb +1 -1
- data/lib/arel/collectors/sql_string.rb +1 -1
- data/lib/arel/collectors/substitute_binds.rb +2 -2
- data/lib/arel/nodes/binary.rb +1 -1
- data/lib/arel/nodes/node.rb +1 -1
- data/lib/arel/nodes/sql_literal.rb +1 -1
- data/lib/arel/visitors/to_sql.rb +1 -1
- metadata +10 -13
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 82c8ca907ebe4ec74622fb27ce477cdd5a4536e05bb25334c3551560324507cd
|
4
|
+
data.tar.gz: 88787eb24c8acb59dc3517d85e919a50d85bf3c0bff149f59f76d2bf6b8495d8
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ea3714004780235f5bb1c78e8b667d229e642942b3ea12163b923d72fa66668e1bd9fc848c87347d96a83c85d3934e499411118883fd2a9c38779a87f031d83c
|
7
|
+
data.tar.gz: 7bacd8bf3eb5712fecdcbba881a2a92f9f4f6fe609c644802b12e423a3f95e7b5953669715ad4215b7170a80f37c70686d2bf090872ef585fb0f4ed8001ff03e
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,210 @@
|
|
1
|
+
## Rails 8.0.2 (March 12, 2025) ##
|
2
|
+
|
3
|
+
* No changes.
|
4
|
+
|
5
|
+
|
6
|
+
## Rails 8.0.2 (March 12, 2025) ##
|
7
|
+
|
8
|
+
* Fix inverting `rename_enum_value` when `:from`/`:to` are provided.
|
9
|
+
|
10
|
+
*fatkodima*
|
11
|
+
|
12
|
+
* Prevent persisting invalid record.
|
13
|
+
|
14
|
+
*Edouard Chin*
|
15
|
+
|
16
|
+
* Fix inverting `drop_table` without options.
|
17
|
+
|
18
|
+
*fatkodima*
|
19
|
+
|
20
|
+
* Fix count with group by qualified name on loaded relation.
|
21
|
+
|
22
|
+
*Ryuta Kamizono*
|
23
|
+
|
24
|
+
* Fix `sum` with qualified name on loaded relation.
|
25
|
+
|
26
|
+
*Chris Gunther*
|
27
|
+
|
28
|
+
* The SQLite3 adapter quotes non-finite Numeric values like "Infinity" and "NaN".
|
29
|
+
|
30
|
+
*Mike Dalessio*
|
31
|
+
|
32
|
+
* Handle libpq returning a database version of 0 on no/bad connection in `PostgreSQLAdapter`.
|
33
|
+
|
34
|
+
Before, this version would be cached and an error would be raised during connection configuration when
|
35
|
+
comparing it with the minimum required version for the adapter. This meant that the connection could
|
36
|
+
never be successfully configured on subsequent reconnection attempts.
|
37
|
+
|
38
|
+
Now, this is treated as a connection failure consistent with libpq, raising a `ActiveRecord::ConnectionFailed`
|
39
|
+
and ensuring the version isn't cached, which allows the version to be retrieved on the next connection attempt.
|
40
|
+
|
41
|
+
*Joshua Young*, *Rian McGuire*
|
42
|
+
|
43
|
+
* Fix error handling during connection configuration.
|
44
|
+
|
45
|
+
Active Record wasn't properly handling errors during the connection configuration phase.
|
46
|
+
This could lead to a partially configured connection being used, resulting in various exceptions,
|
47
|
+
the most common being with the PostgreSQLAdapter raising `undefined method `key?' for nil`
|
48
|
+
or `TypeError: wrong argument type nil (expected PG::TypeMap)`.
|
49
|
+
|
50
|
+
*Jean Boussier*
|
51
|
+
|
52
|
+
* Fix a case where a non-retryable query could be marked retryable.
|
53
|
+
|
54
|
+
*Hartley McGuire*
|
55
|
+
|
56
|
+
* Handle circular references when autosaving associations.
|
57
|
+
|
58
|
+
*zzak*
|
59
|
+
|
60
|
+
* PoolConfig no longer keeps a reference to the connection class.
|
61
|
+
|
62
|
+
Keeping a reference to the class caused subtle issues when combined with reloading in
|
63
|
+
development. Fixes #54343.
|
64
|
+
|
65
|
+
*Mike Dalessio*
|
66
|
+
|
67
|
+
* Fix SQL notifications sometimes not sent when using async queries.
|
68
|
+
|
69
|
+
```ruby
|
70
|
+
Post.async_count
|
71
|
+
ActiveSupport::Notifications.subscribed(->(*) { "Will never reach here" }) do
|
72
|
+
Post.count
|
73
|
+
end
|
74
|
+
```
|
75
|
+
|
76
|
+
In rare circumstances and under the right race condition, Active Support notifications
|
77
|
+
would no longer be dispatched after using an asynchronous query.
|
78
|
+
This is now fixed.
|
79
|
+
|
80
|
+
*Edouard Chin*
|
81
|
+
|
82
|
+
* Fix support for PostgreSQL enum types with commas in their name.
|
83
|
+
|
84
|
+
*Arthur Hess*
|
85
|
+
|
86
|
+
* Fix inserts on MySQL with no RETURNING support for a table with multiple auto populated columns.
|
87
|
+
|
88
|
+
*Nikita Vasilevsky*
|
89
|
+
|
90
|
+
* Fix joining on a scoped association with string joins and bind parameters.
|
91
|
+
|
92
|
+
```ruby
|
93
|
+
class Instructor < ActiveRecord::Base
|
94
|
+
has_many :instructor_roles, -> { active }
|
95
|
+
end
|
96
|
+
|
97
|
+
class InstructorRole < ActiveRecord::Base
|
98
|
+
scope :active, -> {
|
99
|
+
joins("JOIN students ON instructor_roles.student_id = students.id")
|
100
|
+
.where(students { status: 1 })
|
101
|
+
}
|
102
|
+
end
|
103
|
+
|
104
|
+
Instructor.joins(:instructor_roles).first
|
105
|
+
```
|
106
|
+
|
107
|
+
The above example would result in `ActiveRecord::StatementInvalid` because the
|
108
|
+
`active` scope bind parameters would be lost.
|
109
|
+
|
110
|
+
*Jean Boussier*
|
111
|
+
|
112
|
+
* Fix a potential race condition with system tests and transactional fixtures.
|
113
|
+
|
114
|
+
*Sjoerd Lagarde*
|
115
|
+
|
116
|
+
* Fix autosave associations to no longer validated unmodified associated records.
|
117
|
+
|
118
|
+
Active Record was incorrectly performing validation on associated record that
|
119
|
+
weren't created nor modified as part of the transaction:
|
120
|
+
|
121
|
+
```ruby
|
122
|
+
Post.create!(author: User.find(1)) # Fail if user is invalid
|
123
|
+
```
|
124
|
+
|
125
|
+
*Jean Boussier*
|
126
|
+
|
127
|
+
* Remember when a database connection has recently been verified (for
|
128
|
+
two seconds, by default), to avoid repeated reverifications during a
|
129
|
+
single request.
|
130
|
+
|
131
|
+
This should recreate a similar rate of verification as in Rails 7.1,
|
132
|
+
where connections are leased for the duration of a request, and thus
|
133
|
+
only verified once.
|
134
|
+
|
135
|
+
*Matthew Draper*
|
136
|
+
|
137
|
+
|
138
|
+
## Rails 8.0.1 (December 13, 2024) ##
|
139
|
+
|
140
|
+
* Fix removing foreign keys with :restrict action for MySQL.
|
141
|
+
|
142
|
+
*fatkodima*
|
143
|
+
|
144
|
+
* Fix a race condition in `ActiveRecord::Base#method_missing` when lazily defining attributes.
|
145
|
+
|
146
|
+
If multiple thread were concurrently triggering attribute definition on the same model,
|
147
|
+
it could result in a `NoMethodError` being raised.
|
148
|
+
|
149
|
+
*Jean Boussier*
|
150
|
+
|
151
|
+
* Fix MySQL default functions getting dropped when changing a column's nullability.
|
152
|
+
|
153
|
+
*Bastian Bartmann*
|
154
|
+
|
155
|
+
* Fix `add_unique_constraint`/`add_check_constraint`/`add_foreign_key` to be revertible when given invalid options.
|
156
|
+
|
157
|
+
*fatkodima*
|
158
|
+
|
159
|
+
* Fix asynchronous destroying of polymorphic `belongs_to` associations.
|
160
|
+
|
161
|
+
*fatkodima*
|
162
|
+
|
163
|
+
* Fix `insert_all` to not update existing records.
|
164
|
+
|
165
|
+
*fatkodima*
|
166
|
+
|
167
|
+
* `NOT VALID` constraints should not dump in `create_table`.
|
168
|
+
|
169
|
+
*Ryuta Kamizono*
|
170
|
+
|
171
|
+
* Fix finding by nil composite primary key association.
|
172
|
+
|
173
|
+
*fatkodima*
|
174
|
+
|
175
|
+
* Properly reset composite primary key configuration when setting a primary key.
|
176
|
+
|
177
|
+
*fatkodima*
|
178
|
+
|
179
|
+
* Fix Mysql2Adapter support for prepared statements
|
180
|
+
|
181
|
+
Using prepared statements with MySQL could result in a `NoMethodError` exception.
|
182
|
+
|
183
|
+
*Jean Boussier*, *Leo Arnold*, *zzak*
|
184
|
+
|
185
|
+
* Fix parsing of SQLite foreign key names when they contain non-ASCII characters
|
186
|
+
|
187
|
+
*Zacharias Knudsen*
|
188
|
+
|
189
|
+
* Fix parsing of MySQL 8.0.16+ CHECK constraints when they contain new lines.
|
190
|
+
|
191
|
+
*Steve Hill*
|
192
|
+
|
193
|
+
* Ensure normalized attribute queries use `IS NULL` consistently for `nil` and normalized `nil` values.
|
194
|
+
|
195
|
+
*Joshua Young*
|
196
|
+
|
197
|
+
* Fix `sum` when performing a grouped calculation.
|
198
|
+
|
199
|
+
`User.group(:friendly).sum` no longer worked. This is fixed.
|
200
|
+
|
201
|
+
*Edouard Chin*
|
202
|
+
|
203
|
+
* Restore back the ability to pass only database name to `DATABASE_URL`.
|
204
|
+
|
205
|
+
*fatkodima*
|
206
|
+
|
207
|
+
|
1
208
|
## Rails 8.0.0.1 (December 10, 2024) ##
|
2
209
|
|
3
210
|
* No changes.
|
@@ -11,6 +218,7 @@
|
|
11
218
|
|
12
219
|
*zzak*
|
13
220
|
|
221
|
+
|
14
222
|
## Rails 8.0.0.rc2 (October 30, 2024) ##
|
15
223
|
|
16
224
|
* NULLS NOT DISTINCT works with UNIQUE CONSTRAINT as well as UNIQUE INDEX.
|
@@ -26,16 +26,18 @@ module ActiveRecord
|
|
26
26
|
end
|
27
27
|
|
28
28
|
def self.initial_count_for(connection, name, table_joins)
|
29
|
-
|
29
|
+
quoted_name_escaped = nil
|
30
|
+
name_escaped = nil
|
30
31
|
|
31
32
|
counts = table_joins.map do |join|
|
32
33
|
if join.is_a?(Arel::Nodes::StringJoin)
|
33
|
-
#
|
34
|
-
|
34
|
+
# quoted_name_escaped should be case ignored as some database adapters (Oracle) return quoted name in uppercase
|
35
|
+
quoted_name_escaped ||= Regexp.escape(connection.quote_table_name(name))
|
36
|
+
name_escaped ||= Regexp.escape(name)
|
35
37
|
|
36
38
|
# Table names + table aliases
|
37
39
|
join.left.scan(
|
38
|
-
/JOIN(?:\s+\w+)?\s+(?:\S+\s+)?(?:#{
|
40
|
+
/JOIN(?:\s+\w+)?\s+(?:\S+\s+)?(?:#{quoted_name_escaped}|#{name_escaped})\sON/i
|
39
41
|
).size
|
40
42
|
elsif join.is_a?(Arel::Nodes::Join)
|
41
43
|
join.left.name == name ? 1 : 0
|
@@ -19,10 +19,16 @@ module ActiveRecord
|
|
19
19
|
id = owner.public_send(reflection.foreign_key)
|
20
20
|
end
|
21
21
|
|
22
|
+
association_class = if reflection.polymorphic?
|
23
|
+
owner.public_send(reflection.foreign_type)
|
24
|
+
else
|
25
|
+
reflection.klass
|
26
|
+
end
|
27
|
+
|
22
28
|
enqueue_destroy_association(
|
23
29
|
owner_model_name: owner.class.to_s,
|
24
30
|
owner_id: owner.id,
|
25
|
-
association_class:
|
31
|
+
association_class: association_class.to_s,
|
26
32
|
association_ids: [id],
|
27
33
|
association_primary_key_column: primary_key_column,
|
28
34
|
ensuring_owner_was_method: options.fetch(:ensuring_owner_was, nil)
|
@@ -38,41 +38,39 @@ module ActiveRecord
|
|
38
38
|
chain << [reflection, table]
|
39
39
|
end
|
40
40
|
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
klass = reflection.klass
|
41
|
+
# The chain starts with the target table, but we want to end with it here (makes
|
42
|
+
# more sense in this context), so we reverse
|
43
|
+
chain.reverse_each do |reflection, table|
|
44
|
+
klass = reflection.klass
|
46
45
|
|
47
|
-
|
46
|
+
scope = reflection.join_scope(table, foreign_table, foreign_klass)
|
48
47
|
|
49
|
-
|
50
|
-
|
48
|
+
unless scope.references_values.empty?
|
49
|
+
associations = scope.eager_load_values | scope.includes_values
|
51
50
|
|
52
|
-
|
53
|
-
|
54
|
-
end
|
51
|
+
unless associations.empty?
|
52
|
+
scope.joins! scope.construct_join_dependency(associations, Arel::Nodes::OuterJoin)
|
55
53
|
end
|
54
|
+
end
|
56
55
|
|
57
|
-
|
58
|
-
|
56
|
+
arel = scope.arel(alias_tracker.aliases)
|
57
|
+
nodes = arel.constraints.first
|
59
58
|
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
end
|
59
|
+
if nodes.is_a?(Arel::Nodes::And)
|
60
|
+
others = nodes.children.extract! do |node|
|
61
|
+
!Arel.fetch_attribute(node) { |attr| attr.relation.name == table.name }
|
64
62
|
end
|
63
|
+
end
|
65
64
|
|
66
|
-
|
65
|
+
joins << join_type.new(table, Arel::Nodes::On.new(nodes))
|
67
66
|
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
end
|
72
|
-
|
73
|
-
# The current table in this iteration becomes the foreign table in the next
|
74
|
-
foreign_table, foreign_klass = table, klass
|
67
|
+
if others && !others.empty?
|
68
|
+
joins.concat arel.join_sources
|
69
|
+
append_constraints(joins.last, others)
|
75
70
|
end
|
71
|
+
|
72
|
+
# The current table in this iteration becomes the foreign table in the next
|
73
|
+
foreign_table, foreign_klass = table, klass
|
76
74
|
end
|
77
75
|
|
78
76
|
joins
|
@@ -91,10 +89,10 @@ module ActiveRecord
|
|
91
89
|
end
|
92
90
|
|
93
91
|
private
|
94
|
-
def append_constraints(
|
92
|
+
def append_constraints(join, constraints)
|
95
93
|
if join.is_a?(Arel::Nodes::StringJoin)
|
96
94
|
join_string = Arel::Nodes::And.new(constraints.unshift join.left)
|
97
|
-
join.left =
|
95
|
+
join.left = join_string
|
98
96
|
else
|
99
97
|
right = join.right
|
100
98
|
right.expr = Arel::Nodes::And.new(constraints.unshift right.expr)
|
@@ -129,12 +129,13 @@ module ActiveRecord
|
|
129
129
|
# Project.primary_key # => "foo_id"
|
130
130
|
def primary_key=(value)
|
131
131
|
@primary_key = if value.is_a?(Array)
|
132
|
-
@composite_primary_key = true
|
133
132
|
include CompositePrimaryKey
|
134
133
|
@primary_key = value.map { |v| -v.to_s }.freeze
|
135
134
|
elsif value
|
136
135
|
-value.to_s
|
137
136
|
end
|
137
|
+
|
138
|
+
@composite_primary_key = value.is_a?(Array)
|
138
139
|
@attributes_builder = nil
|
139
140
|
end
|
140
141
|
|
@@ -116,10 +116,11 @@ module ActiveRecord
|
|
116
116
|
alias_attribute :id_value, :id if _has_attribute?("id")
|
117
117
|
end
|
118
118
|
|
119
|
-
@attribute_methods_generated = true
|
120
|
-
|
121
119
|
generate_alias_attributes
|
120
|
+
|
121
|
+
@attribute_methods_generated = true
|
122
122
|
end
|
123
|
+
|
123
124
|
true
|
124
125
|
end
|
125
126
|
|
@@ -472,23 +473,27 @@ module ActiveRecord
|
|
472
473
|
end
|
473
474
|
|
474
475
|
def method_missing(name, ...)
|
475
|
-
|
476
|
-
|
477
|
-
|
478
|
-
|
479
|
-
|
480
|
-
|
481
|
-
|
482
|
-
|
483
|
-
|
484
|
-
|
485
|
-
|
486
|
-
# Some attribute methods weren't generated yet, we retry the call
|
487
|
-
return public_send(name, ...)
|
488
|
-
end
|
476
|
+
# We can't know whether some method was defined or not because
|
477
|
+
# multiple thread might be concurrently be in this code path.
|
478
|
+
# So the first one would define the methods and the others would
|
479
|
+
# appear to already have them.
|
480
|
+
self.class.define_attribute_methods
|
481
|
+
|
482
|
+
# So in all cases we must behave as if the method was just defined.
|
483
|
+
method = begin
|
484
|
+
self.class.public_instance_method(name)
|
485
|
+
rescue NameError
|
486
|
+
nil
|
489
487
|
end
|
490
488
|
|
491
|
-
|
489
|
+
# The method might be explicitly defined in the model, but call a generated
|
490
|
+
# method with super. So we must resume the call chain at the right step.
|
491
|
+
method = method.super_method while method && !method.owner.is_a?(GeneratedAttributeMethods)
|
492
|
+
if method
|
493
|
+
method.bind_call(self, ...)
|
494
|
+
else
|
495
|
+
super
|
496
|
+
end
|
492
497
|
end
|
493
498
|
|
494
499
|
def attribute_method?(attr_name)
|
@@ -178,8 +178,8 @@ module ActiveRecord
|
|
178
178
|
# @currency_converter = currency_converter
|
179
179
|
# end
|
180
180
|
#
|
181
|
-
# # value will be the result of
|
182
|
-
# #
|
181
|
+
# # value will be the result of #deserialize or
|
182
|
+
# # #cast. Assumed to be an instance of Money in
|
183
183
|
# # this case.
|
184
184
|
# def serialize(value)
|
185
185
|
# value_in_bitcoins = @currency_converter.convert_to_bitcoins(value)
|
@@ -372,19 +372,29 @@ module ActiveRecord
|
|
372
372
|
return true if record.destroyed? || (association.options[:autosave] && record.marked_for_destruction?)
|
373
373
|
|
374
374
|
context = validation_context if custom_validation_context?
|
375
|
+
return true if record.valid?(context)
|
375
376
|
|
376
|
-
|
377
|
-
|
378
|
-
|
379
|
-
|
380
|
-
|
381
|
-
|
382
|
-
}
|
383
|
-
else
|
384
|
-
errors.add(association.reflection.name)
|
385
|
-
end
|
377
|
+
if record.changed? || record.new_record? || context
|
378
|
+
associated_errors = record.errors.objects
|
379
|
+
else
|
380
|
+
# If there are existing invalid records in the DB, we should still be able to reference them.
|
381
|
+
# Unless a record (no matter where in the association chain) is invalid and is being changed.
|
382
|
+
associated_errors = record.errors.objects.select { |error| error.is_a?(Associations::NestedError) }
|
386
383
|
end
|
387
|
-
|
384
|
+
|
385
|
+
if association.options[:autosave]
|
386
|
+
return if equal?(record)
|
387
|
+
|
388
|
+
associated_errors.each { |error|
|
389
|
+
errors.objects.append(
|
390
|
+
Associations::NestedError.new(association, error)
|
391
|
+
)
|
392
|
+
}
|
393
|
+
elsif associated_errors.any?
|
394
|
+
errors.add(association.reflection.name)
|
395
|
+
end
|
396
|
+
|
397
|
+
errors.any?
|
388
398
|
end
|
389
399
|
|
390
400
|
# Is used as an around_save callback to check while saving a collection
|
@@ -54,19 +54,22 @@ module ActiveRecord
|
|
54
54
|
# about the model. The model needs to pass a connection specification name to the handler,
|
55
55
|
# in order to look up the correct connection pool.
|
56
56
|
class ConnectionHandler
|
57
|
-
class
|
58
|
-
|
59
|
-
|
60
|
-
def initialize(name)
|
57
|
+
class ConnectionDescriptor # :nodoc:
|
58
|
+
def initialize(name, primary = false)
|
61
59
|
@name = name
|
60
|
+
@primary = primary
|
61
|
+
end
|
62
|
+
|
63
|
+
def name
|
64
|
+
primary_class? ? "ActiveRecord::Base" : @name
|
62
65
|
end
|
63
66
|
|
64
67
|
def primary_class?
|
65
|
-
|
68
|
+
@primary
|
66
69
|
end
|
67
70
|
|
68
71
|
def current_preventing_writes
|
69
|
-
|
72
|
+
ActiveRecord::Base.preventing_writes?(@name)
|
70
73
|
end
|
71
74
|
end
|
72
75
|
|
@@ -115,7 +118,7 @@ module ActiveRecord
|
|
115
118
|
pool_config = resolve_pool_config(config, owner_name, role, shard)
|
116
119
|
db_config = pool_config.db_config
|
117
120
|
|
118
|
-
pool_manager = set_pool_manager(pool_config.
|
121
|
+
pool_manager = set_pool_manager(pool_config.connection_descriptor)
|
119
122
|
|
120
123
|
# If there is an existing pool with the same values as the pool_config
|
121
124
|
# don't remove the connection. Connections should only be removed if we are
|
@@ -127,8 +130,8 @@ module ActiveRecord
|
|
127
130
|
# Update the pool_config's connection class if it differs. This is used
|
128
131
|
# for ensuring that ActiveRecord::Base and the primary_abstract_class use
|
129
132
|
# the same pool. Without this granular swapping will not work correctly.
|
130
|
-
if owner_name.primary_class? && (existing_pool_config.
|
131
|
-
existing_pool_config.
|
133
|
+
if owner_name.primary_class? && (existing_pool_config.connection_descriptor != owner_name)
|
134
|
+
existing_pool_config.connection_descriptor = owner_name
|
132
135
|
end
|
133
136
|
|
134
137
|
existing_pool_config.pool
|
@@ -137,7 +140,7 @@ module ActiveRecord
|
|
137
140
|
pool_manager.set_pool_config(role, shard, pool_config)
|
138
141
|
|
139
142
|
payload = {
|
140
|
-
connection_name: pool_config.
|
143
|
+
connection_name: pool_config.connection_descriptor.name,
|
141
144
|
role: role,
|
142
145
|
shard: shard,
|
143
146
|
config: db_config.configuration_hash
|
@@ -242,8 +245,8 @@ module ActiveRecord
|
|
242
245
|
end
|
243
246
|
|
244
247
|
# Get the existing pool manager or initialize and assign a new one.
|
245
|
-
def set_pool_manager(
|
246
|
-
connection_name_to_pool_manager[
|
248
|
+
def set_pool_manager(connection_descriptor)
|
249
|
+
connection_name_to_pool_manager[connection_descriptor.name] ||= PoolManager.new
|
247
250
|
end
|
248
251
|
|
249
252
|
def pool_managers
|
@@ -278,9 +281,9 @@ module ActiveRecord
|
|
278
281
|
|
279
282
|
def determine_owner_name(owner_name, config)
|
280
283
|
if owner_name.is_a?(String) || owner_name.is_a?(Symbol)
|
281
|
-
|
284
|
+
ConnectionDescriptor.new(owner_name.to_s)
|
282
285
|
elsif config.is_a?(Symbol)
|
283
|
-
|
286
|
+
ConnectionDescriptor.new(config.to_s)
|
284
287
|
else
|
285
288
|
owner_name
|
286
289
|
end
|