activerecord 7.1.3.4 → 7.1.4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (56) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +246 -0
  3. data/lib/active_record/associations/belongs_to_association.rb +4 -4
  4. data/lib/active_record/associations/collection_association.rb +4 -4
  5. data/lib/active_record/associations/has_many_association.rb +2 -2
  6. data/lib/active_record/associations/has_one_association.rb +2 -2
  7. data/lib/active_record/associations/join_dependency.rb +6 -8
  8. data/lib/active_record/associations.rb +6 -0
  9. data/lib/active_record/attribute_methods/dirty.rb +2 -2
  10. data/lib/active_record/attribute_methods/read.rb +3 -3
  11. data/lib/active_record/attribute_methods/write.rb +3 -3
  12. data/lib/active_record/attribute_methods.rb +46 -6
  13. data/lib/active_record/autosave_association.rb +5 -2
  14. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +8 -1
  15. data/lib/active_record/connection_adapters/abstract/database_statements.rb +1 -1
  16. data/lib/active_record/connection_adapters/abstract/query_cache.rb +1 -1
  17. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +8 -4
  18. data/lib/active_record/connection_adapters/abstract_adapter.rb +14 -15
  19. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +37 -13
  20. data/lib/active_record/connection_adapters/mysql/schema_statements.rb +2 -1
  21. data/lib/active_record/connection_adapters/mysql2_adapter.rb +16 -10
  22. data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +6 -0
  23. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +1 -1
  24. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +2 -2
  25. data/lib/active_record/connection_adapters/trilogy_adapter.rb +16 -20
  26. data/lib/active_record/core.rb +7 -2
  27. data/lib/active_record/counter_cache.rb +7 -3
  28. data/lib/active_record/database_configurations/hash_config.rb +6 -2
  29. data/lib/active_record/delegated_type.rb +6 -6
  30. data/lib/active_record/destroy_association_async_job.rb +1 -1
  31. data/lib/active_record/encryption/encrypted_attribute_type.rb +2 -2
  32. data/lib/active_record/encryption/scheme.rb +8 -4
  33. data/lib/active_record/future_result.rb +9 -0
  34. data/lib/active_record/gem_version.rb +2 -2
  35. data/lib/active_record/locking/optimistic.rb +1 -1
  36. data/lib/active_record/marshalling.rb +1 -1
  37. data/lib/active_record/message_pack.rb +1 -1
  38. data/lib/active_record/migration/compatibility.rb +6 -0
  39. data/lib/active_record/model_schema.rb +6 -2
  40. data/lib/active_record/persistence.rb +2 -2
  41. data/lib/active_record/query_cache.rb +1 -1
  42. data/lib/active_record/query_logs_formatter.rb +1 -1
  43. data/lib/active_record/railtie.rb +10 -13
  44. data/lib/active_record/railties/databases.rake +2 -2
  45. data/lib/active_record/reflection.rb +8 -2
  46. data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +6 -1
  47. data/lib/active_record/relation/query_methods.rb +21 -7
  48. data/lib/active_record/relation.rb +13 -3
  49. data/lib/active_record/result.rb +1 -1
  50. data/lib/active_record/tasks/database_tasks.rb +19 -8
  51. data/lib/active_record/test_fixtures.rb +1 -0
  52. data/lib/active_record/timestamp.rb +3 -1
  53. data/lib/active_record.rb +2 -2
  54. data/lib/arel/tree_manager.rb +5 -1
  55. data/lib/arel/visitors/to_sql.rb +2 -1
  56. metadata +10 -10
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 0e9a04a312e8155b7ff04c183a890419d536247cd4fc0db22fc8f9dcbcc9e247
4
- data.tar.gz: d98b8badee0267fb485889704fc12d5ef7a8b6e6d7bb3b5d7b4c6c4f9434b345
3
+ metadata.gz: e09aaba09c6a4c6e8c3e3968a076b9dd082f4d07218eb6d79f6778071e999624
4
+ data.tar.gz: 6acc734d0eda8b4c561b709dc2624f38ac86e1ae9644767548b917dc23cde6ad
5
5
  SHA512:
6
- metadata.gz: 2401d90d4884387e659622e82e0a64cbe2a461a8ecdd234af41ddf47b98f1910954c0329ab7a185b19721c4f6cf9717681aeccb53e70801803acc0133f478d8a
7
- data.tar.gz: 9c36b9994a82c1e41ca1ce8c7e41399617ed6dbe15999ed8f9f0e5b7bd4fc38fc56297dfd5eda88d4ca62f50dff6f9b99069ad000b6d5bffe5f9690db35c3a73
6
+ metadata.gz: abd600104dc90bcbc169a88abd5feb96c2e2a6847e2e2278c264f3a414b9c51704268e5afb7dc406ca60ca5cff4ad84f5392e2f471e5e0c1466c426c5778640a
7
+ data.tar.gz: ac1160bf494d31d6a676605e849e909819afc3011efe31daa10b74de9c4132148726df113dd2fbdf69e35da80aac1eab23562e76e610fa69a295c0006857aaac
data/CHANGELOG.md CHANGED
@@ -1,3 +1,249 @@
1
+ ## Rails 7.1.4 (August 22, 2024) ##
2
+
3
+ * Allow to eager load nested nil associations.
4
+
5
+ *fatkodima*
6
+
7
+ * Fix `create_table` with `:auto_increment` option for MySQL adapter.
8
+
9
+ *fatkodima*
10
+
11
+ * Don't load has_one associations during autosave.
12
+
13
+ *Eugene Kenny*
14
+
15
+ * Fix migration ordering for `bin/rails db:prepare` across databases.
16
+
17
+ *fatkodima*
18
+
19
+ * Fix `alias_attribute` to ignore methods defined in parent classes.
20
+
21
+ *Jean Boussier*
22
+
23
+ * Fix a performance regression in attribute methods.
24
+
25
+ *Jean Boussier*
26
+
27
+ * Fix Active Record configs variable shadowing.
28
+
29
+ *Joel Lubrano*
30
+
31
+ * Fix running migrations on other databases when `database_tasks: false` on primary.
32
+
33
+ *fatkodima*
34
+
35
+ * Fix non-partial inserts for models with composite identity primary keys.
36
+
37
+ *fatkodima*
38
+
39
+ * Fix `ActiveRecord::Relation#touch_all` with custom attribute aliased as attribute for update.
40
+
41
+ *fatkodima*
42
+
43
+ * Fix a crash when an Executor wrapped fork exit.
44
+
45
+ *Joé Dupuis*
46
+
47
+ * Fix `destroy_async` job for owners with composite primary keys.
48
+
49
+ *fatkodima*
50
+
51
+ * Ensure pre-7.1 migrations use legacy index names when using `rename_table`.
52
+
53
+ *fatkodima*
54
+
55
+ * Allow `primary_key:` association option to be composite.
56
+
57
+ *Nikita Vasilevsky*
58
+
59
+ * Do not try to alias on key update when raw SQL is supplied.
60
+
61
+ *Gabriel Amaral*
62
+
63
+ * Memoize `key_provider` from `key` or deterministic `key_provider` if any.
64
+
65
+ *Rosa Gutierrez*
66
+
67
+ * Fix `upsert` warning for MySQL.
68
+
69
+ *fatkodima*
70
+
71
+ * Fix predicate builder for polymorphic models referencing models with composite primary keys.
72
+
73
+ *fatkodima*
74
+
75
+ * Fix `update_all/delete_all` on CPK model relation with join subquery.
76
+
77
+ *Nikita Vasilevsky*
78
+
79
+ * Remove memoization to accept `key_provider` overridden by `with_encryption_context`.
80
+
81
+ *John Hawthorn*
82
+
83
+ * Raise error for Trilogy when prepared_statements is true.
84
+
85
+ Trilogy doesn't currently support prepared statements. The error that
86
+ applications would see is a `StatementInvalid` error. This doesn't quite point
87
+ you to the fact this isn't supported. So raise a more appropriate error
88
+ pointing to what to change.
89
+
90
+ *Eileen M. Uchitelle*
91
+
92
+ * Fix loading schema cache when all databases have disabled database tasks.
93
+
94
+ *fatkodima*
95
+
96
+ * Always request `primary_key` in `RETURNING` if no other columns requested.
97
+
98
+ *Nikita Vasilevsky*
99
+
100
+ * Handle records being loaded with Marshal without triggering schema load
101
+
102
+ When using the old marshalling format for Active Record and loading
103
+ a serialized instance, it didn't trigger loading the schema and defining
104
+ attribute methods.
105
+
106
+ *Jean Boussier*
107
+
108
+ * Prevent some constant redefinition warnings when defining `inherited` on models.
109
+
110
+ *Adrian Hirt*
111
+
112
+ * Fix a memory perfomance regression in attribute methods.
113
+
114
+ Attribute methods used much more memory and were slower to define than
115
+ they should have been.
116
+
117
+ *Jean Boussier*
118
+
119
+ * Fix an issue that could cause database connection leaks.
120
+
121
+ If Active Record successfully connected to the database, but then failed
122
+ to read the server informations, the connection would be leaked until the
123
+ Ruby garbage collector triggers.
124
+
125
+ *Jean Boussier*
126
+
127
+ * Fix an issue where the IDs reader method did not return expected results
128
+ for preloaded associations in models using composite primary keys.
129
+
130
+ *Jay Ang*
131
+
132
+ * PostgreSQL `Cidr#change?` detects the address prefix change.
133
+
134
+ *Taketo Takashima*
135
+
136
+ * Fix Active Record serialization to not include instantiated but not loaded associations
137
+
138
+ *Jean Boussier*, *Ben Kyriakou*
139
+
140
+ * Allow `Sqlite3Adapter` to use `sqlite3` gem version `2.x`
141
+
142
+ *Mike Dalessio*
143
+
144
+ * Strict loading using `:n_plus_one_only` does not eagerly load child associations.
145
+
146
+ With this change, child associations are no longer eagerly loaded, to
147
+ match intended behavior and to prevent non-deterministic order issues caused
148
+ by calling methods like `first` or `last`. As `first` and `last` don't cause
149
+ an N+1 by themselves, calling child associations will no longer raise.
150
+ Fixes #49473.
151
+
152
+ Before:
153
+
154
+ ```ruby
155
+ person = Person.find(1)
156
+ person.strict_loading!(mode: :n_plus_one_only)
157
+ person.posts.first
158
+ # SELECT * FROM posts WHERE person_id = 1; -- non-deterministic order
159
+ person.posts.first.firm # raises ActiveRecord::StrictLoadingViolationError
160
+ ```
161
+
162
+ After:
163
+
164
+ ```ruby
165
+ person = Person.find(1)
166
+ person.strict_loading!(mode: :n_plus_one_only)
167
+ person.posts.first # this is 1+1, not N+1
168
+ # SELECT * FROM posts WHERE person_id = 1 ORDER BY id LIMIT 1;
169
+ person.posts.first.firm # no longer raises
170
+ ```
171
+
172
+ *Reid Lynch*
173
+
174
+ * Using `Model.query_constraints` with a single non-primary-key column used to raise as expected, but with an
175
+ incorrect error message. This has been fixed to raise with a more appropriate error message.
176
+
177
+ *Joshua Young*
178
+
179
+ * Fix `has_one` association autosave setting the foreign key attribute when it is unchanged.
180
+
181
+ This behaviour is also inconsistent with autosaving `belongs_to` and can have unintended side effects like raising
182
+ an `ActiveRecord::ReadonlyAttributeError` when the foreign key attribute is marked as read-only.
183
+
184
+ *Joshua Young*
185
+
186
+ * Fix an issue where `ActiveRecord::Encryption` configurations are not ready before the loading
187
+ of Active Record models, when an application is eager loaded. As a result, encrypted attributes
188
+ could be misconfigured in some cases.
189
+
190
+ *Maxime Réty*
191
+
192
+ * Properly synchronize `Mysql2Adapter#active?` and `TrilogyAdapter#active?`
193
+
194
+ As well as `disconnect!` and `verify!`.
195
+
196
+ This generally isn't a big problem as connections must not be shared between
197
+ threads, but is required when running transactional tests or system tests
198
+ and could lead to a SEGV.
199
+
200
+ *Jean Boussier*
201
+
202
+ * Fix counter caches when the foreign key is composite.
203
+
204
+ If the model holding the counter cache had a composite primary key,
205
+ inserting a dependent record would fail with an `ArgumentError`
206
+ `Expected corresponding value for...`
207
+
208
+ *fatkodima*
209
+
210
+ * Fix loading of schema cache for multiple databases.
211
+
212
+ Before this change, if you have multiple databases configured in your
213
+ application, and had schema cache present, Rails would load the same
214
+ cache to all databases.
215
+
216
+ *Rafael Mendonça França*
217
+
218
+ * Fix eager loading of composite primary key associations.
219
+
220
+ `relation.eager_load(:other_model)` could load the wrong records if `other_model`
221
+ had a composite primary key.
222
+
223
+ *Nikita Vasilevsky*
224
+
225
+ * Fix async queries returning a doubly wrapped result when hitting the query cache.
226
+
227
+ *fatkodima*
228
+
229
+ * Fix single quote escapes on default generated MySQL columns
230
+
231
+ MySQL 5.7.5+ supports generated columns, which can be used to create a column that is computed from an expression.
232
+
233
+ Previously, the schema dump would output a string with double escapes for generated columns with single quotes in the default expression.
234
+
235
+ This would result in issues when importing the schema on a fresh instance of a MySQL database.
236
+
237
+ Now, the string will not be escaped and will be valid Ruby upon importing of the schema.
238
+
239
+ *Yash Kapadia*
240
+
241
+ * Fix Migrations with versions older than 7.1 validating options given to
242
+ `t.references`.
243
+
244
+ *Hartley McGuire*
245
+
246
+
1
247
  ## Rails 7.1.3.4 (June 04, 2024) ##
2
248
 
3
249
  * No changes.
@@ -12,11 +12,11 @@ module ActiveRecord
12
12
  raise ActiveRecord::Rollback unless target.destroy
13
13
  when :destroy_async
14
14
  if reflection.foreign_key.is_a?(Array)
15
- primary_key_column = reflection.active_record_primary_key.map(&:to_sym)
16
- id = reflection.foreign_key.map { |col| owner.public_send(col.to_sym) }
15
+ primary_key_column = reflection.active_record_primary_key
16
+ id = reflection.foreign_key.map { |col| owner.public_send(col) }
17
17
  else
18
- primary_key_column = reflection.active_record_primary_key.to_sym
19
- id = owner.public_send(reflection.foreign_key.to_sym)
18
+ primary_key_column = reflection.active_record_primary_key
19
+ id = owner.public_send(reflection.foreign_key)
20
20
  end
21
21
 
22
22
  enqueue_destroy_association(
@@ -48,11 +48,11 @@ module ActiveRecord
48
48
  # Implements the ids reader method, e.g. foo.item_ids for Foo.has_many :items
49
49
  def ids_reader
50
50
  if loaded?
51
- target.pluck(reflection.association_primary_key)
51
+ target.pluck(*reflection.association_primary_key)
52
52
  elsif !target.empty?
53
- load_target.pluck(reflection.association_primary_key)
53
+ load_target.pluck(*reflection.association_primary_key)
54
54
  else
55
- @association_ids ||= scope.pluck(reflection.association_primary_key)
55
+ @association_ids ||= scope.pluck(*reflection.association_primary_key)
56
56
  end
57
57
  end
58
58
 
@@ -303,7 +303,7 @@ module ActiveRecord
303
303
 
304
304
  def find_from_target?
305
305
  loaded? ||
306
- owner.strict_loading? ||
306
+ (owner.strict_loading? && owner.strict_loading_all?) ||
307
307
  reflection.strict_loading? ||
308
308
  owner.new_record? ||
309
309
  target.any? { |record| record.new_record? || record.changed? }
@@ -35,10 +35,10 @@ module ActiveRecord
35
35
  unless target.empty?
36
36
  association_class = target.first.class
37
37
  if association_class.query_constraints_list
38
- primary_key_column = association_class.query_constraints_list.map(&:to_sym)
38
+ primary_key_column = association_class.query_constraints_list
39
39
  ids = target.collect { |assoc| primary_key_column.map { |col| assoc.public_send(col) } }
40
40
  else
41
- primary_key_column = association_class.primary_key.to_sym
41
+ primary_key_column = association_class.primary_key
42
42
  ids = target.collect { |assoc| assoc.public_send(primary_key_column) }
43
43
  end
44
44
 
@@ -34,10 +34,10 @@ module ActiveRecord
34
34
  throw(:abort) unless target.destroyed?
35
35
  when :destroy_async
36
36
  if target.class.query_constraints_list
37
- primary_key_column = target.class.query_constraints_list.map(&:to_sym)
37
+ primary_key_column = target.class.query_constraints_list
38
38
  id = primary_key_column.map { |col| target.public_send(col) }
39
39
  else
40
- primary_key_column = target.class.primary_key.to_sym
40
+ primary_key_column = target.class.primary_key
41
41
  id = target.public_send(primary_key_column)
42
42
  end
43
43
 
@@ -61,7 +61,7 @@ module ActiveRecord
61
61
  when Hash
62
62
  associations.each do |k, v|
63
63
  cache = hash[k] ||= {}
64
- walk_tree v, cache
64
+ walk_tree v, cache if v
65
65
  end
66
66
  else
67
67
  raise ConfigurationError, associations.inspect
@@ -254,10 +254,10 @@ module ActiveRecord
254
254
 
255
255
  if node.primary_key
256
256
  keys = Array(node.primary_key).map { |column| aliases.column_alias(node, column) }
257
- ids = keys.map { |key| row[key] }
257
+ id = keys.map { |key| row[key] }
258
258
  else
259
259
  keys = Array(node.reflection.join_primary_key).map { |column| aliases.column_alias(node, column.to_s) }
260
- ids = keys.map { nil } # Avoid id-based model caching.
260
+ id = keys.map { nil } # Avoid id-based model caching.
261
261
  end
262
262
 
263
263
  if keys.any? { |key| row[key].nil? }
@@ -266,11 +266,9 @@ module ActiveRecord
266
266
  next
267
267
  end
268
268
 
269
- ids.each do |id|
270
- unless model = seen[ar_parent][node][id]
271
- model = construct_model(ar_parent, node, row, model_cache, id, strict_loading_value)
272
- seen[ar_parent][node][id] = model if id
273
- end
269
+ unless model = seen[ar_parent][node][id]
270
+ model = construct_model(ar_parent, node, row, model_cache, id, strict_loading_value)
271
+ seen[ar_parent][node][id] = model if id
274
272
  end
275
273
 
276
274
  construct(model, node, row, seen, model_cache, strict_loading_value)
@@ -1506,6 +1506,11 @@ module ActiveRecord
1506
1506
  # Serves as a composite foreign key. Defines the list of columns to be used to query the associated object.
1507
1507
  # This is an optional option. By default Rails will attempt to derive the value automatically.
1508
1508
  # When the value is set the Array size must match associated model's primary key or +query_constraints+ size.
1509
+ # [+:index_errors+]
1510
+ # Enables differentiation of multiple validation errors from the association records, by including
1511
+ # an index in the error attribute name, e.g. +roles[2].level+.
1512
+ # The index is based on association order, i.e. database order, with yet to be
1513
+ # persisted new records placed at the end.
1509
1514
  #
1510
1515
  # Option examples:
1511
1516
  # has_many :comments, -> { order("posted_on") }
@@ -1519,6 +1524,7 @@ module ActiveRecord
1519
1524
  # has_many :subscribers, through: :subscriptions, disable_joins: true
1520
1525
  # has_many :comments, strict_loading: true
1521
1526
  # has_many :comments, query_constraints: [:blog_id, :post_id]
1527
+ # has_many :comments, index_errors: true
1522
1528
  def has_many(name, scope = nil, **options, &extension)
1523
1529
  reflection = Builder::HasMany.build(self, name, scope, options, &extension)
1524
1530
  Reflection.add_reflection self, name, reflection
@@ -31,7 +31,7 @@ module ActiveRecord
31
31
  # person.name_in_database # => "Alice"
32
32
  # person.saved_change_to_name? # => true
33
33
  # person.saved_change_to_name # => ["Allison", "Alice"]
34
- # person.name_before_last_change # => "Allison"
34
+ # person.name_before_last_save # => "Allison"
35
35
  #
36
36
  # Similar to ActiveModel::Dirty, methods can be invoked as
37
37
  # +saved_change_to_name?+ or by passing an argument to the generic method
@@ -251,7 +251,7 @@ module ActiveRecord
251
251
  changed_attribute_names_to_save
252
252
  else
253
253
  attribute_names.reject do |attr_name|
254
- if column_for_attribute(attr_name).default_function
254
+ if column_for_attribute(attr_name).auto_populated?
255
255
  !attribute_changed?(attr_name)
256
256
  end
257
257
  end
@@ -8,11 +8,11 @@ module ActiveRecord
8
8
 
9
9
  module ClassMethods # :nodoc:
10
10
  private
11
- def define_method_attribute(name, owner:)
11
+ def define_method_attribute(canonical_name, owner:, as: canonical_name)
12
12
  ActiveModel::AttributeMethods::AttrNames.define_attribute_accessor_method(
13
- owner, name
13
+ owner, canonical_name
14
14
  ) do |temp_method_name, attr_name_expr|
15
- owner.define_cached_method(name, as: temp_method_name, namespace: :active_record) do |batch|
15
+ owner.define_cached_method(temp_method_name, as: as, namespace: :active_record) do |batch|
16
16
  batch <<
17
17
  "def #{temp_method_name}" <<
18
18
  " _read_attribute(#{attr_name_expr}) { |n| missing_attribute(n, caller) }" <<
@@ -12,11 +12,11 @@ module ActiveRecord
12
12
 
13
13
  module ClassMethods # :nodoc:
14
14
  private
15
- def define_method_attribute=(name, owner:)
15
+ def define_method_attribute=(canonical_name, owner:, as: canonical_name)
16
16
  ActiveModel::AttributeMethods::AttrNames.define_attribute_accessor_method(
17
- owner, name, writer: true,
17
+ owner, canonical_name, writer: true,
18
18
  ) do |temp_method_name, attr_name_expr|
19
- owner.define_cached_method("#{name}=", as: temp_method_name, namespace: :active_record) do |batch|
19
+ owner.define_cached_method(temp_method_name, as: "#{as}=", namespace: :active_record) do |batch|
20
20
  batch <<
21
21
  "def #{temp_method_name}(value)" <<
22
22
  " _write_attribute(#{attr_name_expr}, value)" <<
@@ -66,7 +66,7 @@ module ActiveRecord
66
66
 
67
67
  def generate_alias_attributes # :nodoc:
68
68
  superclass.generate_alias_attributes unless superclass == Base
69
- return if @alias_attributes_mass_generated
69
+ return false if @alias_attributes_mass_generated
70
70
 
71
71
  generated_attribute_methods.synchronize do
72
72
  return if @alias_attributes_mass_generated
@@ -80,12 +80,19 @@ module ActiveRecord
80
80
 
81
81
  @alias_attributes_mass_generated = true
82
82
  end
83
+ true
83
84
  end
84
85
 
85
- def alias_attribute_method_definition(code_generator, pattern, new_name, old_name)
86
+ def generate_alias_attribute_methods(code_generator, new_name, old_name) # :nodoc:
87
+ attribute_method_patterns.each do |pattern|
88
+ alias_attribute_method_definition(code_generator, pattern, new_name, old_name)
89
+ end
90
+ attribute_method_patterns_cache.clear
91
+ end
92
+
93
+ def alias_attribute_method_definition(code_generator, pattern, new_name, old_name) # :nodoc:
86
94
  method_name = pattern.method_name(new_name).to_s
87
95
  target_name = pattern.method_name(old_name).to_s
88
- parameters = pattern.parameters
89
96
  old_name = old_name.to_s
90
97
 
91
98
  method_defined = method_defined?(target_name) || private_method_defined?(target_name)
@@ -115,9 +122,7 @@ module ActiveRecord
115
122
  )
116
123
  super
117
124
  else
118
- define_proxy_call(code_generator, method_name, pattern.proxy_target, parameters, old_name,
119
- namespace: :proxy_alias_attribute
120
- )
125
+ define_attribute_method_pattern(pattern, old_name, owner: code_generator, as: new_name, override: true)
121
126
  end
122
127
  end
123
128
 
@@ -133,6 +138,11 @@ module ActiveRecord
133
138
  super(attribute_names)
134
139
  @attribute_methods_generated = true
135
140
  end
141
+ true
142
+ end
143
+
144
+ def attribute_methods_generated? # :nodoc:
145
+ @attribute_methods_generated && @alias_attributes_mass_generated
136
146
  end
137
147
 
138
148
  def undefine_attribute_methods # :nodoc:
@@ -459,6 +469,36 @@ module ActiveRecord
459
469
  end
460
470
 
461
471
  private
472
+ def respond_to_missing?(name, include_private = false)
473
+ if self.class.define_attribute_methods
474
+ # Some methods weren't defined yet.
475
+ return true if self.class.method_defined?(name)
476
+ return true if include_private && self.class.private_method_defined?(name)
477
+ end
478
+
479
+ super
480
+ end
481
+
482
+ def method_missing(name, ...)
483
+ unless self.class.attribute_methods_generated?
484
+ if self.class.method_defined?(name)
485
+ # The method is explicitly defined in the model, but calls a generated
486
+ # method with super. So we must resume the call chain at the right setp.
487
+ last_method = method(name)
488
+ last_method = last_method.super_method while last_method.super_method
489
+ self.class.define_attribute_methods
490
+ if last_method.super_method
491
+ return last_method.super_method.call(...)
492
+ end
493
+ elsif self.class.define_attribute_methods | self.class.generate_alias_attributes
494
+ # Some attribute methods weren't generated yet, we retry the call
495
+ return public_send(name, ...)
496
+ end
497
+ end
498
+
499
+ super
500
+ end
501
+
462
502
  def attribute_method?(attr_name)
463
503
  # We check defined? because Syck calls respond_to? before actually calling initialize.
464
504
  defined?(@attributes) && @attributes.key?(attr_name)
@@ -441,7 +441,9 @@ module ActiveRecord
441
441
  # ActiveRecord::Base after the AutosaveAssociation module, which it does by default.
442
442
  def save_has_one_association(reflection)
443
443
  association = association_instance_get(reflection.name)
444
- record = association && association.load_target
444
+ return unless association && association.loaded?
445
+
446
+ record = association.load_target
445
447
 
446
448
  if record && !record.destroyed?
447
449
  autosave = reflection.options[:autosave]
@@ -458,7 +460,8 @@ module ActiveRecord
458
460
  primary_key_foreign_key_pairs = primary_key.zip(foreign_key)
459
461
 
460
462
  primary_key_foreign_key_pairs.each do |primary_key, foreign_key|
461
- record[foreign_key] = _read_attribute(primary_key)
463
+ association_id = _read_attribute(primary_key)
464
+ record[foreign_key] = association_id unless record[foreign_key] == association_id
462
465
  end
463
466
  association.set_inverse_instance(record)
464
467
  end
@@ -675,7 +675,14 @@ module ActiveRecord
675
675
  def new_connection
676
676
  connection = Base.public_send(db_config.adapter_method, db_config.configuration_hash)
677
677
  connection.pool = self
678
- connection.check_version
678
+
679
+ begin
680
+ connection.check_version
681
+ rescue
682
+ connection.disconnect!
683
+ raise
684
+ end
685
+
679
686
  connection
680
687
  rescue ConnectionNotEstablished => ex
681
688
  raise ex.set_pool(self)
@@ -629,7 +629,7 @@ module ActiveRecord
629
629
 
630
630
  result = internal_exec_query(sql, name, binds, prepare: prepare)
631
631
  if async
632
- FutureResult::Complete.new(result)
632
+ FutureResult.wrap(result)
633
633
  else
634
634
  result
635
635
  end
@@ -107,7 +107,7 @@ module ActiveRecord
107
107
 
108
108
  if async
109
109
  result = lookup_sql_cache(sql, name, binds) || super(sql, name, binds, preparable: preparable, async: async)
110
- FutureResult::Complete.new(result)
110
+ FutureResult.wrap(result)
111
111
  else
112
112
  cache_sql(sql, name, binds) { super(sql, name, binds, preparable: preparable, async: async) }
113
113
  end
@@ -963,7 +963,11 @@ module ActiveRecord
963
963
  def index_name(table_name, options) # :nodoc:
964
964
  if Hash === options
965
965
  if options[:column]
966
- generate_index_name(table_name, options[:column])
966
+ if options[:_uses_legacy_index_name]
967
+ "index_#{table_name}_on_#{Array(options[:column]) * '_and_'}"
968
+ else
969
+ generate_index_name(table_name, options[:column])
970
+ end
967
971
  elsif options[:name]
968
972
  options[:name]
969
973
  else
@@ -1636,11 +1640,11 @@ module ActiveRecord
1636
1640
  end
1637
1641
  end
1638
1642
 
1639
- def rename_table_indexes(table_name, new_name)
1643
+ def rename_table_indexes(table_name, new_name, **options)
1640
1644
  indexes(new_name).each do |index|
1641
- generated_index_name = index_name(table_name, column: index.columns)
1645
+ generated_index_name = index_name(table_name, column: index.columns, **options)
1642
1646
  if generated_index_name == index.name
1643
- rename_index new_name, generated_index_name, index_name(new_name, column: index.columns)
1647
+ rename_index new_name, generated_index_name, index_name(new_name, column: index.columns, **options)
1644
1648
  end
1645
1649
  end
1646
1650
  end
@@ -711,13 +711,14 @@ module ActiveRecord
711
711
  end
712
712
  end
713
713
 
714
-
715
714
  # Disconnects from the database if already connected. Otherwise, this
716
715
  # method does nothing.
717
716
  def disconnect!
718
- clear_cache!(new_connection: true)
719
- reset_transaction
720
- @raw_connection_dirty = false
717
+ @lock.synchronize do
718
+ clear_cache!(new_connection: true)
719
+ reset_transaction
720
+ @raw_connection_dirty = false
721
+ end
721
722
  end
722
723
 
723
724
  # Immediately forget this connection ever existed. Unlike disconnect!,
@@ -773,19 +774,17 @@ module ActiveRecord
773
774
  # is no longer active, then this method will reconnect to the database.
774
775
  def verify!
775
776
  unless active?
776
- if @unconfigured_connection
777
- @lock.synchronize do
778
- if @unconfigured_connection
779
- @raw_connection = @unconfigured_connection
780
- @unconfigured_connection = nil
781
- configure_connection
782
- @verified = true
783
- return
784
- end
777
+ @lock.synchronize do
778
+ if @unconfigured_connection
779
+ @raw_connection = @unconfigured_connection
780
+ @unconfigured_connection = nil
781
+ configure_connection
782
+ @verified = true
783
+ return
785
784
  end
786
- end
787
785
 
788
- reconnect!(restore_transactions: true)
786
+ reconnect!(restore_transactions: true)
787
+ end
789
788
  end
790
789
 
791
790
  @verified = true