activerecord 8.0.2 → 8.1.0.beta1

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.
Files changed (159) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +459 -413
  3. data/README.rdoc +2 -2
  4. data/lib/active_record/association_relation.rb +1 -1
  5. data/lib/active_record/associations/association.rb +1 -1
  6. data/lib/active_record/associations/belongs_to_association.rb +9 -1
  7. data/lib/active_record/associations/builder/association.rb +16 -5
  8. data/lib/active_record/associations/builder/belongs_to.rb +17 -4
  9. data/lib/active_record/associations/builder/collection_association.rb +7 -3
  10. data/lib/active_record/associations/builder/has_one.rb +1 -1
  11. data/lib/active_record/associations/builder/singular_association.rb +33 -5
  12. data/lib/active_record/associations/collection_association.rb +3 -3
  13. data/lib/active_record/associations/collection_proxy.rb +22 -4
  14. data/lib/active_record/associations/deprecation.rb +88 -0
  15. data/lib/active_record/associations/errors.rb +3 -0
  16. data/lib/active_record/associations/join_dependency.rb +2 -0
  17. data/lib/active_record/associations/preloader/branch.rb +1 -0
  18. data/lib/active_record/associations.rb +159 -21
  19. data/lib/active_record/attribute_methods/query.rb +34 -0
  20. data/lib/active_record/attribute_methods/serialization.rb +17 -4
  21. data/lib/active_record/attributes.rb +38 -24
  22. data/lib/active_record/base.rb +0 -1
  23. data/lib/active_record/coders/json.rb +14 -5
  24. data/lib/active_record/connection_adapters/abstract/connection_handler.rb +2 -4
  25. data/lib/active_record/connection_adapters/abstract/connection_pool/queue.rb +15 -0
  26. data/lib/active_record/connection_adapters/abstract/connection_pool/reaper.rb +51 -12
  27. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +384 -49
  28. data/lib/active_record/connection_adapters/abstract/database_statements.rb +26 -30
  29. data/lib/active_record/connection_adapters/abstract/query_cache.rb +19 -1
  30. data/lib/active_record/connection_adapters/abstract/quoting.rb +15 -24
  31. data/lib/active_record/connection_adapters/abstract/schema_creation.rb +7 -2
  32. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +26 -34
  33. data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +2 -1
  34. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +89 -23
  35. data/lib/active_record/connection_adapters/abstract/transaction.rb +16 -3
  36. data/lib/active_record/connection_adapters/abstract_adapter.rb +67 -13
  37. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +43 -11
  38. data/lib/active_record/connection_adapters/column.rb +17 -4
  39. data/lib/active_record/connection_adapters/mysql/database_statements.rb +4 -4
  40. data/lib/active_record/connection_adapters/mysql/schema_creation.rb +2 -0
  41. data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +42 -5
  42. data/lib/active_record/connection_adapters/mysql/schema_statements.rb +26 -4
  43. data/lib/active_record/connection_adapters/mysql2/database_statements.rb +27 -22
  44. data/lib/active_record/connection_adapters/mysql2_adapter.rb +1 -0
  45. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +18 -16
  46. data/lib/active_record/connection_adapters/postgresql/oid/array.rb +2 -2
  47. data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +1 -1
  48. data/lib/active_record/connection_adapters/postgresql/quoting.rb +21 -10
  49. data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +1 -1
  50. data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +8 -21
  51. data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +65 -30
  52. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +74 -38
  53. data/lib/active_record/connection_adapters/postgresql_adapter.rb +12 -7
  54. data/lib/active_record/connection_adapters/schema_cache.rb +2 -2
  55. data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +39 -27
  56. data/lib/active_record/connection_adapters/sqlite3/quoting.rb +0 -8
  57. data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +4 -13
  58. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +56 -32
  59. data/lib/active_record/connection_adapters/trilogy/database_statements.rb +4 -3
  60. data/lib/active_record/connection_adapters/trilogy_adapter.rb +1 -1
  61. data/lib/active_record/connection_adapters.rb +1 -0
  62. data/lib/active_record/connection_handling.rb +1 -1
  63. data/lib/active_record/core.rb +13 -10
  64. data/lib/active_record/counter_cache.rb +33 -8
  65. data/lib/active_record/database_configurations/database_config.rb +5 -1
  66. data/lib/active_record/database_configurations/hash_config.rb +56 -9
  67. data/lib/active_record/database_configurations/url_config.rb +13 -3
  68. data/lib/active_record/database_configurations.rb +7 -3
  69. data/lib/active_record/delegated_type.rb +2 -2
  70. data/lib/active_record/dynamic_matchers.rb +54 -69
  71. data/lib/active_record/encryption/encryptable_record.rb +5 -5
  72. data/lib/active_record/encryption/encrypted_attribute_type.rb +2 -2
  73. data/lib/active_record/encryption/encryptor.rb +27 -25
  74. data/lib/active_record/encryption/scheme.rb +1 -1
  75. data/lib/active_record/enum.rb +37 -20
  76. data/lib/active_record/errors.rb +20 -4
  77. data/lib/active_record/explain_registry.rb +0 -1
  78. data/lib/active_record/filter_attribute_handler.rb +73 -0
  79. data/lib/active_record/fixture_set/table_row.rb +19 -2
  80. data/lib/active_record/fixtures.rb +2 -2
  81. data/lib/active_record/gem_version.rb +3 -3
  82. data/lib/active_record/inheritance.rb +1 -1
  83. data/lib/active_record/insert_all.rb +12 -7
  84. data/lib/active_record/locking/optimistic.rb +7 -0
  85. data/lib/active_record/locking/pessimistic.rb +5 -0
  86. data/lib/active_record/log_subscriber.rb +1 -5
  87. data/lib/active_record/middleware/shard_selector.rb +34 -17
  88. data/lib/active_record/migration/command_recorder.rb +14 -1
  89. data/lib/active_record/migration/compatibility.rb +34 -24
  90. data/lib/active_record/migration/default_schema_versions_formatter.rb +30 -0
  91. data/lib/active_record/migration.rb +31 -21
  92. data/lib/active_record/model_schema.rb +10 -7
  93. data/lib/active_record/nested_attributes.rb +2 -0
  94. data/lib/active_record/persistence.rb +34 -3
  95. data/lib/active_record/query_cache.rb +22 -15
  96. data/lib/active_record/query_logs.rb +7 -7
  97. data/lib/active_record/querying.rb +4 -4
  98. data/lib/active_record/railtie.rb +34 -5
  99. data/lib/active_record/railties/databases.rake +23 -19
  100. data/lib/active_record/railties/job_checkpoints.rb +15 -0
  101. data/lib/active_record/railties/job_runtime.rb +10 -11
  102. data/lib/active_record/reflection.rb +42 -3
  103. data/lib/active_record/relation/batches.rb +26 -12
  104. data/lib/active_record/relation/calculations.rb +35 -25
  105. data/lib/active_record/relation/delegation.rb +0 -1
  106. data/lib/active_record/relation/finder_methods.rb +41 -24
  107. data/lib/active_record/relation/merger.rb +2 -2
  108. data/lib/active_record/relation/predicate_builder.rb +2 -2
  109. data/lib/active_record/relation/query_attribute.rb +3 -1
  110. data/lib/active_record/relation/query_methods.rb +43 -33
  111. data/lib/active_record/relation/spawn_methods.rb +6 -6
  112. data/lib/active_record/relation/where_clause.rb +7 -10
  113. data/lib/active_record/relation.rb +37 -15
  114. data/lib/active_record/result.rb +44 -21
  115. data/lib/active_record/sanitization.rb +2 -0
  116. data/lib/active_record/schema_dumper.rb +12 -10
  117. data/lib/active_record/scoping.rb +0 -1
  118. data/lib/active_record/secure_token.rb +3 -3
  119. data/lib/active_record/signed_id.rb +46 -18
  120. data/lib/active_record/statement_cache.rb +13 -9
  121. data/lib/active_record/store.rb +44 -19
  122. data/lib/active_record/tasks/abstract_tasks.rb +76 -0
  123. data/lib/active_record/tasks/database_tasks.rb +24 -35
  124. data/lib/active_record/tasks/mysql_database_tasks.rb +3 -40
  125. data/lib/active_record/tasks/postgresql_database_tasks.rb +14 -40
  126. data/lib/active_record/tasks/sqlite_database_tasks.rb +14 -26
  127. data/lib/active_record/test_databases.rb +11 -3
  128. data/lib/active_record/test_fixtures.rb +27 -2
  129. data/lib/active_record/testing/query_assertions.rb +8 -2
  130. data/lib/active_record/timestamp.rb +4 -2
  131. data/lib/active_record/transaction.rb +2 -5
  132. data/lib/active_record/transactions.rb +34 -10
  133. data/lib/active_record/type/hash_lookup_type_map.rb +2 -1
  134. data/lib/active_record/type/internal/timezone.rb +7 -0
  135. data/lib/active_record/type/json.rb +15 -2
  136. data/lib/active_record/type/serialized.rb +11 -4
  137. data/lib/active_record/type/type_map.rb +1 -1
  138. data/lib/active_record/type_caster/connection.rb +2 -1
  139. data/lib/active_record/validations/associated.rb +1 -1
  140. data/lib/active_record.rb +68 -5
  141. data/lib/arel/alias_predication.rb +2 -0
  142. data/lib/arel/crud.rb +8 -11
  143. data/lib/arel/delete_manager.rb +5 -0
  144. data/lib/arel/nodes/count.rb +2 -2
  145. data/lib/arel/nodes/delete_statement.rb +4 -2
  146. data/lib/arel/nodes/function.rb +4 -10
  147. data/lib/arel/nodes/named_function.rb +2 -2
  148. data/lib/arel/nodes/node.rb +1 -1
  149. data/lib/arel/nodes/update_statement.rb +4 -2
  150. data/lib/arel/nodes.rb +0 -2
  151. data/lib/arel/select_manager.rb +13 -4
  152. data/lib/arel/update_manager.rb +5 -0
  153. data/lib/arel/visitors/dot.rb +2 -3
  154. data/lib/arel/visitors/postgresql.rb +55 -0
  155. data/lib/arel/visitors/sqlite.rb +55 -8
  156. data/lib/arel/visitors/to_sql.rb +5 -21
  157. data/lib/arel.rb +3 -1
  158. metadata +15 -11
  159. data/lib/active_record/normalization.rb +0 -163
@@ -21,7 +21,7 @@ module ActiveRecord
21
21
  # New migration functionality that will never be backward compatible should be added directly to `ActiveRecord::Migration`.
22
22
  #
23
23
  # There are classes for each prior Rails version. Each class descends from the *next* Rails version, so:
24
- # 5.2 < 6.0 < 6.1 < 7.0 < 7.1 < 7.2 < 8.0
24
+ # 5.2 < 6.0 < 6.1 < 7.0 < 7.1 < 7.2 < 8.0 < 8.1
25
25
  #
26
26
  # If you are introducing new migration functionality that should only apply from Rails 7 onward, then you should
27
27
  # find the class that immediately precedes it (6.1), and override the relevant migration methods to undo your changes.
@@ -29,7 +29,31 @@ module ActiveRecord
29
29
  # For example, Rails 6 added a default value for the `precision` option on datetime columns. So in this file, the `V5_2`
30
30
  # class sets the value of `precision` to `nil` if it's not explicitly provided. This way, the default value will not apply
31
31
  # for migrations written for 5.2, but will for migrations written for 6.0.
32
- V8_0 = Current
32
+ V8_1 = Current
33
+
34
+ class V8_0 < V8_1
35
+ module RemoveForeignKeyColumnMatch
36
+ def remove_foreign_key(from_table, to_table = nil, **options)
37
+ options[:_skip_column_match] = true
38
+ super
39
+ end
40
+ end
41
+
42
+ module TableDefinition
43
+ def remove_foreign_key(to_table = nil, **options)
44
+ options[:_skip_column_match] = true
45
+ super
46
+ end
47
+ end
48
+
49
+ include RemoveForeignKeyColumnMatch
50
+
51
+ private
52
+ def compatible_table_definition(t)
53
+ t.singleton_class.prepend(TableDefinition)
54
+ super
55
+ end
56
+ end
33
57
 
34
58
  class V7_2 < V8_0
35
59
  end
@@ -154,9 +178,7 @@ module ActiveRecord
154
178
 
155
179
  private
156
180
  def compatible_table_definition(t)
157
- class << t
158
- prepend TableDefinition
159
- end
181
+ t.singleton_class.prepend(TableDefinition)
160
182
  super
161
183
  end
162
184
  end
@@ -217,9 +239,7 @@ module ActiveRecord
217
239
 
218
240
  private
219
241
  def compatible_table_definition(t)
220
- class << t
221
- prepend TableDefinition
222
- end
242
+ t.singleton_class.prepend(TableDefinition)
223
243
  super
224
244
  end
225
245
  end
@@ -260,9 +280,7 @@ module ActiveRecord
260
280
 
261
281
  private
262
282
  def compatible_table_definition(t)
263
- class << t
264
- prepend TableDefinition
265
- end
283
+ t.singleton_class.prepend(TableDefinition)
266
284
  super
267
285
  end
268
286
  end
@@ -308,17 +326,13 @@ module ActiveRecord
308
326
 
309
327
  private
310
328
  def compatible_table_definition(t)
311
- class << t
312
- prepend TableDefinition
313
- end
329
+ t.singleton_class.prepend(TableDefinition)
314
330
  super
315
331
  end
316
332
 
317
333
  def command_recorder
318
334
  recorder = super
319
- class << recorder
320
- prepend CommandRecorder
321
- end
335
+ recorder.singleton_class.prepend(CommandRecorder)
322
336
  recorder
323
337
  end
324
338
  end
@@ -406,9 +420,7 @@ module ActiveRecord
406
420
 
407
421
  private
408
422
  def compatible_table_definition(t)
409
- class << t
410
- prepend TableDefinition
411
- end
423
+ t.singleton_class.prepend(TableDefinition)
412
424
  super
413
425
  end
414
426
  end
@@ -442,7 +454,7 @@ module ActiveRecord
442
454
  super
443
455
  end
444
456
 
445
- def index_exists?(table_name, column_name, **options)
457
+ def index_exists?(table_name, column_name = nil, **options)
446
458
  column_names = Array(column_name).map(&:to_s)
447
459
  options[:name] =
448
460
  if options[:name].present?
@@ -460,9 +472,7 @@ module ActiveRecord
460
472
 
461
473
  private
462
474
  def compatible_table_definition(t)
463
- class << t
464
- prepend TableDefinition
465
- end
475
+ t.singleton_class.prepend(TableDefinition)
466
476
  super
467
477
  end
468
478
 
@@ -0,0 +1,30 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActiveRecord
4
+ class Migration
5
+ # This class is used by the schema dumper to format versions information.
6
+ #
7
+ # The class receives the current +connection+ when initialized.
8
+ class DefaultSchemaVersionsFormatter # :nodoc:
9
+ def initialize(connection)
10
+ @connection = connection
11
+ end
12
+
13
+ def format(versions)
14
+ sm_table = connection.quote_table_name(connection.pool.schema_migration.table_name)
15
+
16
+ if versions.is_a?(Array)
17
+ sql = +"INSERT INTO #{sm_table} (version) VALUES\n"
18
+ sql << versions.reverse.map { |v| "(#{connection.quote(v)})" }.join(",\n")
19
+ sql << ";"
20
+ sql
21
+ else
22
+ "INSERT INTO #{sm_table} (version) VALUES (#{connection.quote(versions)});"
23
+ end
24
+ end
25
+
26
+ private
27
+ attr_reader :connection
28
+ end
29
+ end
30
+ end
@@ -18,7 +18,7 @@ module ActiveRecord
18
18
  # For example the following migration is not reversible.
19
19
  # Rolling back this migration will raise an ActiveRecord::IrreversibleMigration error.
20
20
  #
21
- # class IrreversibleMigrationExample < ActiveRecord::Migration[8.0]
21
+ # class IrreversibleMigrationExample < ActiveRecord::Migration[8.1]
22
22
  # def change
23
23
  # create_table :distributors do |t|
24
24
  # t.string :zipcode
@@ -36,7 +36,7 @@ module ActiveRecord
36
36
  #
37
37
  # 1. Define <tt>#up</tt> and <tt>#down</tt> methods instead of <tt>#change</tt>:
38
38
  #
39
- # class ReversibleMigrationExample < ActiveRecord::Migration[8.0]
39
+ # class ReversibleMigrationExample < ActiveRecord::Migration[8.1]
40
40
  # def up
41
41
  # create_table :distributors do |t|
42
42
  # t.string :zipcode
@@ -61,7 +61,7 @@ module ActiveRecord
61
61
  #
62
62
  # 2. Use the #reversible method in <tt>#change</tt> method:
63
63
  #
64
- # class ReversibleMigrationExample < ActiveRecord::Migration[8.0]
64
+ # class ReversibleMigrationExample < ActiveRecord::Migration[8.1]
65
65
  # def change
66
66
  # create_table :distributors do |t|
67
67
  # t.string :zipcode
@@ -148,11 +148,10 @@ module ActiveRecord
148
148
  include ActiveSupport::ActionableError
149
149
 
150
150
  action "Run pending migrations" do
151
- ActiveRecord::Tasks::DatabaseTasks.migrate
151
+ ActiveRecord::Tasks::DatabaseTasks.migrate_all
152
152
 
153
153
  if ActiveRecord.dump_schema_after_migration
154
- connection = ActiveRecord::Tasks::DatabaseTasks.migration_connection
155
- ActiveRecord::Tasks::DatabaseTasks.dump_schema(connection.pool.db_config)
154
+ ActiveRecord::Tasks::DatabaseTasks.dump_all
156
155
  end
157
156
  end
158
157
 
@@ -247,7 +246,7 @@ module ActiveRecord
247
246
  #
248
247
  # Example of a simple migration:
249
248
  #
250
- # class AddSsl < ActiveRecord::Migration[8.0]
249
+ # class AddSsl < ActiveRecord::Migration[8.1]
251
250
  # def up
252
251
  # add_column :accounts, :ssl_enabled, :boolean, default: true
253
252
  # end
@@ -267,7 +266,7 @@ module ActiveRecord
267
266
  #
268
267
  # Example of a more complex migration that also needs to initialize data:
269
268
  #
270
- # class AddSystemSettings < ActiveRecord::Migration[8.0]
269
+ # class AddSystemSettings < ActiveRecord::Migration[8.1]
271
270
  # def up
272
271
  # create_table :system_settings do |t|
273
272
  # t.string :name
@@ -396,7 +395,7 @@ module ActiveRecord
396
395
  # $ bin/rails generate migration add_fieldname_to_tablename fieldname:string
397
396
  #
398
397
  # This will generate the file <tt>timestamp_add_fieldname_to_tablename.rb</tt>, which will look like this:
399
- # class AddFieldnameToTablename < ActiveRecord::Migration[8.0]
398
+ # class AddFieldnameToTablename < ActiveRecord::Migration[8.1]
400
399
  # def change
401
400
  # add_column :tablenames, :fieldname, :string
402
401
  # end
@@ -422,7 +421,7 @@ module ActiveRecord
422
421
  #
423
422
  # Not all migrations change the schema. Some just fix the data:
424
423
  #
425
- # class RemoveEmptyTags < ActiveRecord::Migration[8.0]
424
+ # class RemoveEmptyTags < ActiveRecord::Migration[8.1]
426
425
  # def up
427
426
  # Tag.all.each { |tag| tag.destroy if tag.pages.empty? }
428
427
  # end
@@ -435,7 +434,7 @@ module ActiveRecord
435
434
  #
436
435
  # Others remove columns when they migrate up instead of down:
437
436
  #
438
- # class RemoveUnnecessaryItemAttributes < ActiveRecord::Migration[8.0]
437
+ # class RemoveUnnecessaryItemAttributes < ActiveRecord::Migration[8.1]
439
438
  # def up
440
439
  # remove_column :items, :incomplete_items_count
441
440
  # remove_column :items, :completed_items_count
@@ -449,7 +448,7 @@ module ActiveRecord
449
448
  #
450
449
  # And sometimes you need to do something in SQL not abstracted directly by migrations:
451
450
  #
452
- # class MakeJoinUnique < ActiveRecord::Migration[8.0]
451
+ # class MakeJoinUnique < ActiveRecord::Migration[8.1]
453
452
  # def up
454
453
  # execute "ALTER TABLE `pages_linked_pages` ADD UNIQUE `page_id_linked_page_id` (`page_id`,`linked_page_id`)"
455
454
  # end
@@ -466,7 +465,7 @@ module ActiveRecord
466
465
  # <tt>Base#reset_column_information</tt> in order to ensure that the model has the
467
466
  # latest column data from after the new column was added. Example:
468
467
  #
469
- # class AddPeopleSalary < ActiveRecord::Migration[8.0]
468
+ # class AddPeopleSalary < ActiveRecord::Migration[8.1]
470
469
  # def up
471
470
  # add_column :people, :salary, :integer
472
471
  # Person.reset_column_information
@@ -528,7 +527,7 @@ module ActiveRecord
528
527
  # To define a reversible migration, define the +change+ method in your
529
528
  # migration like this:
530
529
  #
531
- # class TenderloveMigration < ActiveRecord::Migration[8.0]
530
+ # class TenderloveMigration < ActiveRecord::Migration[8.1]
532
531
  # def change
533
532
  # create_table(:horses) do |t|
534
533
  # t.column :content, :text
@@ -558,7 +557,7 @@ module ActiveRecord
558
557
  # can't execute inside a transaction though, and for these situations
559
558
  # you can turn the automatic transactions off.
560
559
  #
561
- # class ChangeEnum < ActiveRecord::Migration[8.0]
560
+ # class ChangeEnum < ActiveRecord::Migration[8.1]
562
561
  # disable_ddl_transaction!
563
562
  #
564
563
  # def up
@@ -571,6 +570,7 @@ module ActiveRecord
571
570
  class Migration
572
571
  autoload :CommandRecorder, "active_record/migration/command_recorder"
573
572
  autoload :Compatibility, "active_record/migration/compatibility"
573
+ autoload :DefaultSchemaVersionsFormatter, "active_record/migration/default_schema_versions_formatter"
574
574
  autoload :JoinTable, "active_record/migration/join_table"
575
575
  autoload :ExecutionStrategy, "active_record/migration/execution_strategy"
576
576
  autoload :DefaultStrategy, "active_record/migration/default_strategy"
@@ -747,7 +747,7 @@ module ActiveRecord
747
747
  private
748
748
  def any_schema_needs_update?
749
749
  !db_configs_in_current_env.all? do |db_config|
750
- Tasks::DatabaseTasks.schema_up_to_date?(db_config, ActiveRecord.schema_format)
750
+ Tasks::DatabaseTasks.schema_up_to_date?(db_config)
751
751
  end
752
752
  end
753
753
 
@@ -782,6 +782,11 @@ module ActiveRecord
782
782
  system("bin/rails db:test:prepare")
783
783
  end
784
784
  end
785
+
786
+ def respond_to_missing?(method, include_private = false)
787
+ return false if nearest_delegate == delegate
788
+ nearest_delegate.respond_to?(method, include_private)
789
+ end
785
790
  end
786
791
 
787
792
  def disable_ddl_transaction # :nodoc:
@@ -819,7 +824,7 @@ module ActiveRecord
819
824
  # and create the table 'apples' on the way up, and the reverse
820
825
  # on the way down.
821
826
  #
822
- # class FixTLMigration < ActiveRecord::Migration[8.0]
827
+ # class FixTLMigration < ActiveRecord::Migration[8.1]
823
828
  # def change
824
829
  # revert do
825
830
  # create_table(:horses) do |t|
@@ -838,7 +843,7 @@ module ActiveRecord
838
843
  #
839
844
  # require_relative "20121212123456_tenderlove_migration"
840
845
  #
841
- # class FixupTLMigration < ActiveRecord::Migration[8.0]
846
+ # class FixupTLMigration < ActiveRecord::Migration[8.1]
842
847
  # def change
843
848
  # revert TenderloveMigration
844
849
  #
@@ -889,7 +894,7 @@ module ActiveRecord
889
894
  # when the three columns 'first_name', 'last_name' and 'full_name' exist,
890
895
  # even when migrating down:
891
896
  #
892
- # class SplitNameMigration < ActiveRecord::Migration[8.0]
897
+ # class SplitNameMigration < ActiveRecord::Migration[8.1]
893
898
  # def change
894
899
  # add_column :users, :first_name, :string
895
900
  # add_column :users, :last_name, :string
@@ -917,7 +922,7 @@ module ActiveRecord
917
922
  # In the following example, the new column +published+ will be given
918
923
  # the value +true+ for all existing records.
919
924
  #
920
- # class AddPublishedToPosts < ActiveRecord::Migration[8.0]
925
+ # class AddPublishedToPosts < ActiveRecord::Migration[8.1]
921
926
  # def change
922
927
  # add_column :posts, :published, :boolean, default: false
923
928
  # up_only do
@@ -1170,6 +1175,10 @@ module ActiveRecord
1170
1175
  def command_recorder
1171
1176
  CommandRecorder.new(connection)
1172
1177
  end
1178
+
1179
+ def respond_to_missing?(method, include_private = false)
1180
+ execution_strategy.respond_to?(method, include_private) || super
1181
+ end
1173
1182
  end
1174
1183
 
1175
1184
  # MigrationProxy is used to defer loading of the actual migration classes
@@ -1529,7 +1538,8 @@ module ActiveRecord
1529
1538
  return if down? && !migrated.include?(migration.version.to_i)
1530
1539
  return if up? && migrated.include?(migration.version.to_i)
1531
1540
 
1532
- Base.logger.info "Migrating to #{migration.name} (#{migration.version})" if Base.logger
1541
+ message = up? ? "Migrating to" : "Reverting"
1542
+ Base.logger.info "#{message} #{migration.name} (#{migration.version})" if Base.logger
1533
1543
 
1534
1544
  ddl_transaction(migration) do
1535
1545
  migration.migrate(@direction)
@@ -113,17 +113,19 @@ module ActiveRecord
113
113
  # :singleton-method: implicit_order_column
114
114
  # :call-seq: implicit_order_column
115
115
  #
116
- # The name of the column records are ordered by if no explicit order clause
116
+ # The name of the column(s) records are ordered by if no explicit order clause
117
117
  # is used during an ordered finder call. If not set the primary key is used.
118
118
 
119
119
  ##
120
120
  # :singleton-method: implicit_order_column=
121
121
  # :call-seq: implicit_order_column=(column_name)
122
122
  #
123
- # Sets the column to sort records by when no explicit order clause is used
124
- # during an ordered finder call. Useful when the primary key is not an
125
- # auto-incrementing integer, for example when it's a UUID. Records are subsorted
126
- # by the primary key if it exists to ensure deterministic results.
123
+ # Sets the column(s) to sort records by when no explicit order clause is used
124
+ # during an ordered finder call. Useful for models where the primary key isn't an
125
+ # auto-incrementing integer (such as UUID).
126
+ #
127
+ # By default, records are subsorted by primary key to ensure deterministic results.
128
+ # To disable this subsort behavior, set `implicit_order_column` to `["column_name", nil]`.
127
129
 
128
130
  ##
129
131
  # :singleton-method: immutable_strings_by_default=
@@ -501,7 +503,7 @@ module ActiveRecord
501
503
  # when just after creating a table you want to populate it with some default
502
504
  # values, e.g.:
503
505
  #
504
- # class CreateJobLevels < ActiveRecord::Migration[8.0]
506
+ # class CreateJobLevels < ActiveRecord::Migration[8.1]
505
507
  # def up
506
508
  # create_table :job_levels do |t|
507
509
  # t.integer :id
@@ -620,7 +622,8 @@ module ActiveRecord
620
622
  end
621
623
 
622
624
  def type_for_column(connection, column)
623
- type = connection.lookup_cast_type_from_column(column)
625
+ # TODO: Remove the need for a connection after we release 8.1.
626
+ type = column.fetch_cast_type(connection)
624
627
 
625
628
  if immutable_strings_by_default && type.respond_to?(:to_immutable_string)
626
629
  type = type.to_immutable_string
@@ -387,6 +387,8 @@ module ActiveRecord
387
387
  generated_association_methods.module_eval <<-eoruby, __FILE__, __LINE__ + 1
388
388
  silence_redefinition_of_method :#{association_name}_attributes=
389
389
  def #{association_name}_attributes=(attributes)
390
+ association = association(:#{association_name})
391
+ deprecated_associations_api_guard(association, __method__)
390
392
  assign_nested_attributes_for_#{type}_association(:#{association_name}, attributes)
391
393
  end
392
394
  eoruby
@@ -492,6 +492,7 @@ module ActiveRecord
492
492
  becoming.instance_variable_set(:@attributes, @attributes)
493
493
  becoming.instance_variable_set(:@mutations_from_database, @mutations_from_database ||= nil)
494
494
  becoming.instance_variable_set(:@new_record, new_record?)
495
+ becoming.instance_variable_set(:@previously_new_record, previously_new_record?)
495
496
  becoming.instance_variable_set(:@destroyed, destroyed?)
496
497
  becoming.errors.copy!(errors)
497
498
  end
@@ -581,8 +582,8 @@ module ActiveRecord
581
582
  end
582
583
 
583
584
  # Equivalent to <code>update_columns(name => value)</code>.
584
- def update_column(name, value)
585
- update_columns(name => value)
585
+ def update_column(name, value, touch: nil)
586
+ update_columns(name => value, touch: touch)
586
587
  end
587
588
 
588
589
  # Updates the attributes directly in the database issuing an UPDATE SQL
@@ -596,11 +597,25 @@ module ActiveRecord
596
597
  #
597
598
  # * \Validations are skipped.
598
599
  # * \Callbacks are skipped.
599
- # * +updated_at+/+updated_on+ are not updated.
600
+ # * +updated_at+/+updated_on+ are updated if the +touch+ option is set to +true+.
600
601
  # * However, attributes are serialized with the same rules as ActiveRecord::Relation#update_all
601
602
  #
602
603
  # This method raises an ActiveRecord::ActiveRecordError when called on new
603
604
  # objects, or when at least one of the attributes is marked as readonly.
605
+ #
606
+ # ==== Parameters
607
+ #
608
+ # * <tt>:touch</tt> option - Touch the timestamp columns when updating.
609
+ # * If attribute names are passed, they are updated along with +updated_at+/+updated_on+ attributes.
610
+ #
611
+ # ==== Examples
612
+ #
613
+ # # Update a single attribute.
614
+ # user.update_columns(last_request_at: Time.current)
615
+ #
616
+ # # Update with touch option.
617
+ # user.update_columns(last_request_at: Time.current, touch: true)
618
+
604
619
  def update_columns(attributes)
605
620
  raise ActiveRecordError, "cannot update a new record" if new_record?
606
621
  raise ActiveRecordError, "cannot update a destroyed record" if destroyed?
@@ -612,6 +627,15 @@ module ActiveRecord
612
627
  verify_readonly_attribute(name) || name
613
628
  end
614
629
 
630
+ touch = attributes.delete("touch")
631
+ if touch
632
+ names = touch if touch != true
633
+ names = Array.wrap(names)
634
+ options = names.extract_options!
635
+ touch_updates = self.class.touch_attributes_with_time(*names, **options)
636
+ attributes.with_defaults!(touch_updates) unless touch_updates.empty?
637
+ end
638
+
615
639
  update_constraints = _query_constraints_hash
616
640
  attributes = attributes.each_with_object({}) do |(k, v), h|
617
641
  h[k] = @attributes.write_cast_value(k, v)
@@ -640,8 +664,15 @@ module ActiveRecord
640
664
  # This means that any other modified attributes will still be dirty.
641
665
  # Validations and callbacks are skipped. Supports the +touch+ option from
642
666
  # +update_counters+, see that for more.
667
+ #
668
+ # This method raises an ActiveRecord::ActiveRecordError when called on new
669
+ # objects, or when at least one of the attributes is marked as readonly.
670
+ #
643
671
  # Returns +self+.
644
672
  def increment!(attribute, by = 1, touch: nil)
673
+ raise ActiveRecordError, "cannot update a new record" if new_record?
674
+ raise ActiveRecordError, "cannot update a destroyed record" if destroyed?
675
+
645
676
  increment(attribute, by)
646
677
  change = public_send(attribute) - (public_send(:"#{attribute}_in_database") || 0)
647
678
  self.class.update_counters(id, attribute => change, touch: touch)
@@ -3,6 +3,7 @@
3
3
  module ActiveRecord
4
4
  # = Active Record Query Cache
5
5
  class QueryCache
6
+ # ActiveRecord::Base extends this module, so these methods are available in models.
6
7
  module ClassMethods
7
8
  # Enable the query cache within the block if Active Record is configured.
8
9
  # If it's not, it will execute the given block.
@@ -20,11 +21,15 @@ module ActiveRecord
20
21
  end
21
22
  end
22
23
 
23
- # Disable the query cache within the block if Active Record is configured.
24
- # If it's not, it will execute the given block.
24
+ # Runs the block with the query cache disabled.
25
+ #
26
+ # If the query cache was enabled before the block was executed, it is
27
+ # enabled again after it.
25
28
  #
26
- # Set <tt>dirties: false</tt> to prevent query caches on all connections from being cleared by write operations.
27
- # (By default, write operations dirty all connections' query caches in case they are replicas whose cache would now be outdated.)
29
+ # Set <tt>dirties: false</tt> to prevent query caches on all connections
30
+ # from being cleared by write operations. (By default, write operations
31
+ # dirty all connections' query caches in case they are replicas whose
32
+ # cache would now be outdated.)
28
33
  def uncached(dirties: true, &block)
29
34
  if connected? || !configurations.empty?
30
35
  connection_pool.disable_query_cache(dirties: dirties, &block)
@@ -34,22 +39,24 @@ module ActiveRecord
34
39
  end
35
40
  end
36
41
 
37
- def self.run
38
- ActiveRecord::Base.connection_handler.each_connection_pool.reject(&:query_cache_enabled).each do |pool|
39
- next if pool.db_config&.query_cache == false
40
- pool.enable_query_cache!
42
+ module ExecutorHooks # :nodoc:
43
+ def self.run
44
+ ActiveRecord::Base.connection_handler.each_connection_pool.reject(&:query_cache_enabled).each do |pool|
45
+ next if pool.db_config&.query_cache == false
46
+ pool.enable_query_cache!
47
+ end
41
48
  end
42
- end
43
49
 
44
- def self.complete(pools)
45
- pools.each do |pool|
46
- pool.disable_query_cache!
47
- pool.clear_query_cache
50
+ def self.complete(pools)
51
+ pools.each do |pool|
52
+ pool.disable_query_cache!
53
+ pool.clear_query_cache
54
+ end
48
55
  end
49
56
  end
50
57
 
51
- def self.install_executor_hooks(executor = ActiveSupport::Executor)
52
- executor.register_hook(self)
58
+ def self.install_executor_hooks(executor = ActiveSupport::Executor) # :nodoc:
59
+ executor.register_hook(ExecutorHooks)
53
60
  end
54
61
  end
55
62
  end
@@ -28,6 +28,10 @@ module ActiveRecord
28
28
  # * +database+
29
29
  # * +source_location+
30
30
  #
31
+ # WARNING: Calculating the +source_location+ of a query can be slow, so you should consider its impact if using it in a production environment.
32
+ #
33
+ # Also see {config.active_record.verbose_query_logs}[https://guides.rubyonrails.org/debugging_rails_applications.html#verbose-query-logs].
34
+ #
31
35
  # Action Controller adds default tags when loaded:
32
36
  #
33
37
  # * +controller+
@@ -65,7 +69,7 @@ module ActiveRecord
65
69
  #
66
70
  # Tag comments can be prepended to the query:
67
71
  #
68
- # ActiveRecord::QueryLogs.prepend_comment = true
72
+ # config.active_record.query_log_tags_prepend_comment = true
69
73
  #
70
74
  # For applications where the content will not change during the lifetime of
71
75
  # the request or job execution, the tags can be cached for reuse in every query:
@@ -153,11 +157,7 @@ module ActiveRecord
153
157
  end
154
158
 
155
159
  def query_source_location # :nodoc:
156
- Thread.each_caller_location do |location|
157
- frame = LogSubscriber.backtrace_cleaner.clean_frame(location)
158
- return frame if frame
159
- end
160
- nil
160
+ LogSubscriber.backtrace_cleaner.first_clean_frame
161
161
  end
162
162
 
163
163
  ActiveSupport::ExecutionContext.after_change { ActiveRecord::QueryLogs.clear_cache }
@@ -211,7 +211,7 @@ module ActiveRecord
211
211
  end
212
212
 
213
213
  def escape_sql_comment(content)
214
- # Sanitize a string to appear within a SQL comment
214
+ # Sanitize a string to appear within an SQL comment
215
215
  # For compatibility, this also surrounding "/*+", "/*", and "*/"
216
216
  # characters, possibly with single surrounding space.
217
217
  # Then follows that by replacing any internal "*/" or "/ *" with
@@ -46,8 +46,8 @@ module ActiveRecord
46
46
  # Post.find_by_sql ["SELECT title FROM posts WHERE author = ? AND created > ?", author_id, start_date]
47
47
  # Post.find_by_sql ["SELECT body FROM comments WHERE author = :user_id OR approved_by = :user_id", { :user_id => user_id }]
48
48
  #
49
- # Note that building your own SQL query string from user input may expose your application to
50
- # injection attacks (https://guides.rubyonrails.org/security.html#sql-injection).
49
+ # Note that building your own SQL query string from user input {may expose your application to
50
+ # injection attacks}[https://guides.rubyonrails.org/security.html#sql-injection].
51
51
  def find_by_sql(sql, binds = [], preparable: nil, allow_retry: false, &block)
52
52
  result = with_connection do |c|
53
53
  _query_by_sql(c, sql, binds, preparable: preparable, allow_retry: allow_retry)
@@ -55,7 +55,7 @@ module ActiveRecord
55
55
  _load_from_sql(result, &block)
56
56
  end
57
57
 
58
- # Same as <tt>#find_by_sql</tt> but perform the query asynchronously and returns an ActiveRecord::Promise.
58
+ # Same as #find_by_sql but perform the query asynchronously and returns an ActiveRecord::Promise.
59
59
  def async_find_by_sql(sql, binds = [], preparable: nil, allow_retry: false, &block)
60
60
  with_connection do |c|
61
61
  _query_by_sql(c, sql, binds, preparable: preparable, allow_retry: allow_retry, async: true)
@@ -112,7 +112,7 @@ module ActiveRecord
112
112
  end
113
113
  end
114
114
 
115
- # Same as <tt>#count_by_sql</tt> but perform the query asynchronously and returns an ActiveRecord::Promise.
115
+ # Same as #count_by_sql but perform the query asynchronously and returns an ActiveRecord::Promise.
116
116
  def async_count_by_sql(sql)
117
117
  with_connection do |c|
118
118
  c.select_value(sanitize_sql(sql), "#{name} Count", async: true).then(&:to_i)