activerecord 8.0.3 → 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 (148) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +427 -522
  3. data/README.rdoc +1 -1
  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/builder/association.rb +16 -5
  7. data/lib/active_record/associations/builder/belongs_to.rb +17 -4
  8. data/lib/active_record/associations/builder/collection_association.rb +7 -3
  9. data/lib/active_record/associations/builder/has_one.rb +1 -1
  10. data/lib/active_record/associations/builder/singular_association.rb +33 -5
  11. data/lib/active_record/associations/collection_proxy.rb +22 -4
  12. data/lib/active_record/associations/deprecation.rb +88 -0
  13. data/lib/active_record/associations/errors.rb +3 -0
  14. data/lib/active_record/associations/join_dependency.rb +2 -0
  15. data/lib/active_record/associations/preloader/branch.rb +1 -0
  16. data/lib/active_record/associations.rb +159 -21
  17. data/lib/active_record/attribute_methods/serialization.rb +16 -3
  18. data/lib/active_record/attribute_methods.rb +1 -1
  19. data/lib/active_record/attributes.rb +3 -0
  20. data/lib/active_record/autosave_association.rb +1 -1
  21. data/lib/active_record/base.rb +2 -3
  22. data/lib/active_record/coders/json.rb +14 -5
  23. data/lib/active_record/connection_adapters/abstract/connection_handler.rb +1 -3
  24. data/lib/active_record/connection_adapters/abstract/connection_pool/queue.rb +15 -0
  25. data/lib/active_record/connection_adapters/abstract/connection_pool/reaper.rb +51 -12
  26. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +382 -51
  27. data/lib/active_record/connection_adapters/abstract/database_statements.rb +26 -30
  28. data/lib/active_record/connection_adapters/abstract/query_cache.rb +25 -18
  29. data/lib/active_record/connection_adapters/abstract/quoting.rb +15 -24
  30. data/lib/active_record/connection_adapters/abstract/schema_creation.rb +7 -2
  31. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +26 -34
  32. data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +2 -1
  33. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +85 -22
  34. data/lib/active_record/connection_adapters/abstract/transaction.rb +16 -3
  35. data/lib/active_record/connection_adapters/abstract_adapter.rb +66 -14
  36. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +43 -11
  37. data/lib/active_record/connection_adapters/column.rb +17 -4
  38. data/lib/active_record/connection_adapters/mysql/database_statements.rb +4 -4
  39. data/lib/active_record/connection_adapters/mysql/schema_creation.rb +2 -0
  40. data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +42 -5
  41. data/lib/active_record/connection_adapters/mysql/schema_statements.rb +26 -4
  42. data/lib/active_record/connection_adapters/mysql2/database_statements.rb +27 -22
  43. data/lib/active_record/connection_adapters/mysql2_adapter.rb +1 -0
  44. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +18 -23
  45. data/lib/active_record/connection_adapters/postgresql/oid/array.rb +2 -2
  46. data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +1 -1
  47. data/lib/active_record/connection_adapters/postgresql/quoting.rb +21 -10
  48. data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +1 -1
  49. data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +8 -21
  50. data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +65 -30
  51. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +74 -38
  52. data/lib/active_record/connection_adapters/postgresql_adapter.rb +10 -5
  53. data/lib/active_record/connection_adapters/schema_cache.rb +2 -2
  54. data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +37 -25
  55. data/lib/active_record/connection_adapters/sqlite3/quoting.rb +0 -8
  56. data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +4 -13
  57. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +54 -30
  58. data/lib/active_record/connection_adapters/trilogy/database_statements.rb +4 -3
  59. data/lib/active_record/connection_adapters/trilogy_adapter.rb +1 -1
  60. data/lib/active_record/connection_adapters.rb +1 -0
  61. data/lib/active_record/core.rb +5 -4
  62. data/lib/active_record/counter_cache.rb +33 -8
  63. data/lib/active_record/database_configurations/database_config.rb +5 -1
  64. data/lib/active_record/database_configurations/hash_config.rb +50 -9
  65. data/lib/active_record/database_configurations/url_config.rb +13 -3
  66. data/lib/active_record/database_configurations.rb +7 -3
  67. data/lib/active_record/delegated_type.rb +1 -1
  68. data/lib/active_record/dynamic_matchers.rb +54 -69
  69. data/lib/active_record/encryption/encryptable_record.rb +4 -4
  70. data/lib/active_record/encryption/encrypted_attribute_type.rb +1 -1
  71. data/lib/active_record/encryption/scheme.rb +1 -1
  72. data/lib/active_record/enum.rb +24 -8
  73. data/lib/active_record/errors.rb +23 -7
  74. data/lib/active_record/explain_registry.rb +0 -1
  75. data/lib/active_record/filter_attribute_handler.rb +73 -0
  76. data/lib/active_record/fixtures.rb +2 -2
  77. data/lib/active_record/gem_version.rb +3 -3
  78. data/lib/active_record/inheritance.rb +1 -1
  79. data/lib/active_record/insert_all.rb +12 -7
  80. data/lib/active_record/locking/optimistic.rb +7 -0
  81. data/lib/active_record/locking/pessimistic.rb +5 -0
  82. data/lib/active_record/log_subscriber.rb +1 -5
  83. data/lib/active_record/middleware/shard_selector.rb +34 -17
  84. data/lib/active_record/migration/command_recorder.rb +14 -1
  85. data/lib/active_record/migration/compatibility.rb +34 -24
  86. data/lib/active_record/migration/default_schema_versions_formatter.rb +30 -0
  87. data/lib/active_record/migration.rb +26 -16
  88. data/lib/active_record/model_schema.rb +10 -7
  89. data/lib/active_record/nested_attributes.rb +2 -0
  90. data/lib/active_record/persistence.rb +34 -3
  91. data/lib/active_record/query_cache.rb +22 -15
  92. data/lib/active_record/query_logs.rb +3 -7
  93. data/lib/active_record/railtie.rb +32 -3
  94. data/lib/active_record/railties/databases.rake +16 -4
  95. data/lib/active_record/railties/job_checkpoints.rb +15 -0
  96. data/lib/active_record/railties/job_runtime.rb +10 -11
  97. data/lib/active_record/reflection.rb +42 -3
  98. data/lib/active_record/relation/batches.rb +26 -12
  99. data/lib/active_record/relation/calculations.rb +20 -9
  100. data/lib/active_record/relation/delegation.rb +0 -1
  101. data/lib/active_record/relation/finder_methods.rb +27 -11
  102. data/lib/active_record/relation/merger.rb +2 -2
  103. data/lib/active_record/relation/predicate_builder.rb +2 -2
  104. data/lib/active_record/relation/query_attribute.rb +3 -1
  105. data/lib/active_record/relation/query_methods.rb +39 -29
  106. data/lib/active_record/relation/where_clause.rb +1 -10
  107. data/lib/active_record/relation.rb +25 -13
  108. data/lib/active_record/result.rb +44 -21
  109. data/lib/active_record/sanitization.rb +2 -0
  110. data/lib/active_record/schema_dumper.rb +12 -10
  111. data/lib/active_record/scoping.rb +0 -1
  112. data/lib/active_record/signed_id.rb +43 -15
  113. data/lib/active_record/statement_cache.rb +13 -9
  114. data/lib/active_record/store.rb +44 -19
  115. data/lib/active_record/tasks/abstract_tasks.rb +76 -0
  116. data/lib/active_record/tasks/database_tasks.rb +2 -21
  117. data/lib/active_record/tasks/mysql_database_tasks.rb +3 -40
  118. data/lib/active_record/tasks/postgresql_database_tasks.rb +5 -39
  119. data/lib/active_record/tasks/sqlite_database_tasks.rb +14 -26
  120. data/lib/active_record/test_databases.rb +10 -2
  121. data/lib/active_record/test_fixtures.rb +27 -2
  122. data/lib/active_record/testing/query_assertions.rb +8 -2
  123. data/lib/active_record/timestamp.rb +4 -2
  124. data/lib/active_record/transaction.rb +2 -5
  125. data/lib/active_record/transactions.rb +32 -10
  126. data/lib/active_record/type/hash_lookup_type_map.rb +2 -1
  127. data/lib/active_record/type/internal/timezone.rb +7 -0
  128. data/lib/active_record/type/json.rb +15 -2
  129. data/lib/active_record/type/serialized.rb +11 -4
  130. data/lib/active_record/type/type_map.rb +1 -1
  131. data/lib/active_record/type_caster/connection.rb +2 -1
  132. data/lib/active_record/validations/associated.rb +1 -1
  133. data/lib/active_record.rb +65 -3
  134. data/lib/arel/alias_predication.rb +2 -0
  135. data/lib/arel/crud.rb +6 -11
  136. data/lib/arel/nodes/count.rb +2 -2
  137. data/lib/arel/nodes/function.rb +4 -10
  138. data/lib/arel/nodes/named_function.rb +2 -2
  139. data/lib/arel/nodes/node.rb +1 -1
  140. data/lib/arel/nodes.rb +0 -2
  141. data/lib/arel/select_manager.rb +7 -2
  142. data/lib/arel/visitors/dot.rb +0 -3
  143. data/lib/arel/visitors/postgresql.rb +55 -0
  144. data/lib/arel/visitors/sqlite.rb +55 -8
  145. data/lib/arel/visitors/to_sql.rb +3 -21
  146. data/lib/arel.rb +3 -1
  147. metadata +13 -9
  148. data/lib/active_record/normalization.rb +0 -163
@@ -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
@@ -246,7 +246,7 @@ module ActiveRecord
246
246
  #
247
247
  # Example of a simple migration:
248
248
  #
249
- # class AddSsl < ActiveRecord::Migration[8.0]
249
+ # class AddSsl < ActiveRecord::Migration[8.1]
250
250
  # def up
251
251
  # add_column :accounts, :ssl_enabled, :boolean, default: true
252
252
  # end
@@ -266,7 +266,7 @@ module ActiveRecord
266
266
  #
267
267
  # Example of a more complex migration that also needs to initialize data:
268
268
  #
269
- # class AddSystemSettings < ActiveRecord::Migration[8.0]
269
+ # class AddSystemSettings < ActiveRecord::Migration[8.1]
270
270
  # def up
271
271
  # create_table :system_settings do |t|
272
272
  # t.string :name
@@ -395,7 +395,7 @@ module ActiveRecord
395
395
  # $ bin/rails generate migration add_fieldname_to_tablename fieldname:string
396
396
  #
397
397
  # This will generate the file <tt>timestamp_add_fieldname_to_tablename.rb</tt>, which will look like this:
398
- # class AddFieldnameToTablename < ActiveRecord::Migration[8.0]
398
+ # class AddFieldnameToTablename < ActiveRecord::Migration[8.1]
399
399
  # def change
400
400
  # add_column :tablenames, :fieldname, :string
401
401
  # end
@@ -421,7 +421,7 @@ module ActiveRecord
421
421
  #
422
422
  # Not all migrations change the schema. Some just fix the data:
423
423
  #
424
- # class RemoveEmptyTags < ActiveRecord::Migration[8.0]
424
+ # class RemoveEmptyTags < ActiveRecord::Migration[8.1]
425
425
  # def up
426
426
  # Tag.all.each { |tag| tag.destroy if tag.pages.empty? }
427
427
  # end
@@ -434,7 +434,7 @@ module ActiveRecord
434
434
  #
435
435
  # Others remove columns when they migrate up instead of down:
436
436
  #
437
- # class RemoveUnnecessaryItemAttributes < ActiveRecord::Migration[8.0]
437
+ # class RemoveUnnecessaryItemAttributes < ActiveRecord::Migration[8.1]
438
438
  # def up
439
439
  # remove_column :items, :incomplete_items_count
440
440
  # remove_column :items, :completed_items_count
@@ -448,7 +448,7 @@ module ActiveRecord
448
448
  #
449
449
  # And sometimes you need to do something in SQL not abstracted directly by migrations:
450
450
  #
451
- # class MakeJoinUnique < ActiveRecord::Migration[8.0]
451
+ # class MakeJoinUnique < ActiveRecord::Migration[8.1]
452
452
  # def up
453
453
  # execute "ALTER TABLE `pages_linked_pages` ADD UNIQUE `page_id_linked_page_id` (`page_id`,`linked_page_id`)"
454
454
  # end
@@ -465,7 +465,7 @@ module ActiveRecord
465
465
  # <tt>Base#reset_column_information</tt> in order to ensure that the model has the
466
466
  # latest column data from after the new column was added. Example:
467
467
  #
468
- # class AddPeopleSalary < ActiveRecord::Migration[8.0]
468
+ # class AddPeopleSalary < ActiveRecord::Migration[8.1]
469
469
  # def up
470
470
  # add_column :people, :salary, :integer
471
471
  # Person.reset_column_information
@@ -527,7 +527,7 @@ module ActiveRecord
527
527
  # To define a reversible migration, define the +change+ method in your
528
528
  # migration like this:
529
529
  #
530
- # class TenderloveMigration < ActiveRecord::Migration[8.0]
530
+ # class TenderloveMigration < ActiveRecord::Migration[8.1]
531
531
  # def change
532
532
  # create_table(:horses) do |t|
533
533
  # t.column :content, :text
@@ -557,7 +557,7 @@ module ActiveRecord
557
557
  # can't execute inside a transaction though, and for these situations
558
558
  # you can turn the automatic transactions off.
559
559
  #
560
- # class ChangeEnum < ActiveRecord::Migration[8.0]
560
+ # class ChangeEnum < ActiveRecord::Migration[8.1]
561
561
  # disable_ddl_transaction!
562
562
  #
563
563
  # def up
@@ -570,6 +570,7 @@ module ActiveRecord
570
570
  class Migration
571
571
  autoload :CommandRecorder, "active_record/migration/command_recorder"
572
572
  autoload :Compatibility, "active_record/migration/compatibility"
573
+ autoload :DefaultSchemaVersionsFormatter, "active_record/migration/default_schema_versions_formatter"
573
574
  autoload :JoinTable, "active_record/migration/join_table"
574
575
  autoload :ExecutionStrategy, "active_record/migration/execution_strategy"
575
576
  autoload :DefaultStrategy, "active_record/migration/default_strategy"
@@ -781,6 +782,11 @@ module ActiveRecord
781
782
  system("bin/rails db:test:prepare")
782
783
  end
783
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
784
790
  end
785
791
 
786
792
  def disable_ddl_transaction # :nodoc:
@@ -818,7 +824,7 @@ module ActiveRecord
818
824
  # and create the table 'apples' on the way up, and the reverse
819
825
  # on the way down.
820
826
  #
821
- # class FixTLMigration < ActiveRecord::Migration[8.0]
827
+ # class FixTLMigration < ActiveRecord::Migration[8.1]
822
828
  # def change
823
829
  # revert do
824
830
  # create_table(:horses) do |t|
@@ -837,7 +843,7 @@ module ActiveRecord
837
843
  #
838
844
  # require_relative "20121212123456_tenderlove_migration"
839
845
  #
840
- # class FixupTLMigration < ActiveRecord::Migration[8.0]
846
+ # class FixupTLMigration < ActiveRecord::Migration[8.1]
841
847
  # def change
842
848
  # revert TenderloveMigration
843
849
  #
@@ -888,7 +894,7 @@ module ActiveRecord
888
894
  # when the three columns 'first_name', 'last_name' and 'full_name' exist,
889
895
  # even when migrating down:
890
896
  #
891
- # class SplitNameMigration < ActiveRecord::Migration[8.0]
897
+ # class SplitNameMigration < ActiveRecord::Migration[8.1]
892
898
  # def change
893
899
  # add_column :users, :first_name, :string
894
900
  # add_column :users, :last_name, :string
@@ -916,7 +922,7 @@ module ActiveRecord
916
922
  # In the following example, the new column +published+ will be given
917
923
  # the value +true+ for all existing records.
918
924
  #
919
- # class AddPublishedToPosts < ActiveRecord::Migration[8.0]
925
+ # class AddPublishedToPosts < ActiveRecord::Migration[8.1]
920
926
  # def change
921
927
  # add_column :posts, :published, :boolean, default: false
922
928
  # up_only do
@@ -1169,6 +1175,10 @@ module ActiveRecord
1169
1175
  def command_recorder
1170
1176
  CommandRecorder.new(connection)
1171
1177
  end
1178
+
1179
+ def respond_to_missing?(method, include_private = false)
1180
+ execution_strategy.respond_to?(method, include_private) || super
1181
+ end
1172
1182
  end
1173
1183
 
1174
1184
  # MigrationProxy is used to defer loading of the actual migration classes
@@ -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
@@ -69,7 +69,7 @@ module ActiveRecord
69
69
  #
70
70
  # Tag comments can be prepended to the query:
71
71
  #
72
- # ActiveRecord::QueryLogs.prepend_comment = true
72
+ # config.active_record.query_log_tags_prepend_comment = true
73
73
  #
74
74
  # For applications where the content will not change during the lifetime of
75
75
  # the request or job execution, the tags can be cached for reuse in every query:
@@ -157,11 +157,7 @@ module ActiveRecord
157
157
  end
158
158
 
159
159
  def query_source_location # :nodoc:
160
- Thread.each_caller_location do |location|
161
- frame = LogSubscriber.backtrace_cleaner.clean_frame(location)
162
- return frame if frame
163
- end
164
- nil
160
+ LogSubscriber.backtrace_cleaner.first_clean_frame
165
161
  end
166
162
 
167
163
  ActiveSupport::ExecutionContext.after_change { ActiveRecord::QueryLogs.clear_cache }
@@ -215,7 +211,7 @@ module ActiveRecord
215
211
  end
216
212
 
217
213
  def escape_sql_comment(content)
218
- # Sanitize a string to appear within a SQL comment
214
+ # Sanitize a string to appear within an SQL comment
219
215
  # For compatibility, this also surrounding "/*+", "/*", and "*/"
220
216
  # characters, possibly with single surrounding space.
221
217
  # Then follows that by replacing any internal "*/" or "/ *" with
@@ -35,9 +35,12 @@ module ActiveRecord
35
35
  config.active_record.query_log_tags = [ :application ]
36
36
  config.active_record.query_log_tags_format = :legacy
37
37
  config.active_record.cache_query_log_tags = false
38
+ config.active_record.query_log_tags_prepend_comment = false
38
39
  config.active_record.raise_on_assign_to_attr_readonly = false
39
40
  config.active_record.belongs_to_required_validates_foreign_key = true
40
41
  config.active_record.generate_secure_token_on = :create
42
+ config.active_record.use_legacy_signed_id_verifier = :generate_and_verify
43
+ config.active_record.deprecated_associations_options = { mode: :warn, backtrace: false }
41
44
 
42
45
  config.active_record.queues = ActiveSupport::InheritableOptions.new
43
46
 
@@ -229,10 +232,12 @@ To keep using the current cache store, you can turn off cache versioning entirel
229
232
  :query_log_tags,
230
233
  :query_log_tags_format,
231
234
  :cache_query_log_tags,
235
+ :query_log_tags_prepend_comment,
232
236
  :sqlite3_adapter_strict_strings_by_default,
233
237
  :check_schema_cache_dump_version,
234
238
  :use_schema_cache_dump,
235
239
  :postgresql_adapter_decode_dates,
240
+ :use_legacy_signed_id_verifier,
236
241
  )
237
242
 
238
243
  configs_used_in_other_initializers.each do |k, v|
@@ -274,6 +279,13 @@ To keep using the current cache store, you can turn off cache versioning entirel
274
279
  end
275
280
  end
276
281
 
282
+ initializer "active_record.job_checkpoints" do
283
+ require "active_record/railties/job_checkpoints"
284
+ ActiveSupport.on_load(:active_job_continuable) do
285
+ prepend ActiveRecord::Railties::JobCheckpoints
286
+ end
287
+ end
288
+
277
289
  initializer "active_record.set_reloader_hooks" do
278
290
  ActiveSupport.on_load(:active_record) do
279
291
  ActiveSupport::Reloader.before_class_unload do
@@ -319,9 +331,22 @@ To keep using the current cache store, you can turn off cache versioning entirel
319
331
  end
320
332
  end
321
333
 
322
- initializer "active_record.set_signed_id_verifier_secret" do
323
- ActiveSupport.on_load(:active_record) do
324
- self.signed_id_verifier_secret ||= -> { Rails.application.key_generator.generate_key("active_record/signed_id") }
334
+ initializer "active_record.filter_attributes_as_log_parameters" do |app|
335
+ ActiveRecord::FilterAttributeHandler.new(app).enable
336
+ end
337
+
338
+ initializer "active_record.configure_message_verifiers" do |app|
339
+ ActiveRecord.message_verifiers = app.message_verifiers
340
+
341
+ use_legacy_signed_id_verifier = app.config.active_record.use_legacy_signed_id_verifier
342
+ legacy_options = { digest: "SHA256", serializer: JSON, url_safe: true }
343
+
344
+ if use_legacy_signed_id_verifier == :generate_and_verify
345
+ app.message_verifiers.prepend { |salt| legacy_options if salt == "active_record/signed_id" }
346
+ elsif use_legacy_signed_id_verifier == :verify
347
+ app.message_verifiers.rotate { |salt| legacy_options if salt == "active_record/signed_id" }
348
+ elsif use_legacy_signed_id_verifier
349
+ raise ArgumentError, "Unrecognized value for config.active_record.use_legacy_signed_id_verifier: #{use_legacy_signed_id_verifier.inspect}"
325
350
  end
326
351
  end
327
352
 
@@ -387,6 +412,10 @@ To keep using the current cache store, you can turn off cache versioning entirel
387
412
  if app.config.active_record.cache_query_log_tags
388
413
  ActiveRecord::QueryLogs.cache_query_log_tags = true
389
414
  end
415
+
416
+ if app.config.active_record.query_log_tags_prepend_comment
417
+ ActiveRecord::QueryLogs.prepend_comment = true
418
+ end
390
419
  end
391
420
  end
392
421
  end
@@ -163,6 +163,18 @@ db_namespace = namespace :db do
163
163
  desc "Resets your database using your migrations for the current environment"
164
164
  task reset: ["db:drop", "db:create", "db:schema:dump", "db:migrate"]
165
165
 
166
+ namespace :reset do
167
+ ActiveRecord::Tasks::DatabaseTasks.for_each(databases) do |name|
168
+ desc "Drop and recreate the #{name} database using migrations"
169
+ task name => :load_config do
170
+ db_namespace["drop:#{name}"].invoke
171
+ db_namespace["create:#{name}"].invoke
172
+ db_namespace["schema:dump:#{name}"].invoke
173
+ db_namespace["migrate:#{name}"].invoke
174
+ end
175
+ end
176
+ end
177
+
166
178
  desc 'Run the "up" for a given migration VERSION.'
167
179
  task up: :load_config do
168
180
  ActiveRecord::Tasks::DatabaseTasks.raise_for_multi_db(command: "db:migrate:up")
@@ -333,7 +345,7 @@ db_namespace = namespace :db do
333
345
  pending_migrations << pool.migration_context.open.pending_migrations
334
346
  end
335
347
 
336
- pending_migrations = pending_migrations.flatten!
348
+ pending_migrations.flatten!
337
349
 
338
350
  if pending_migrations.any?
339
351
  puts "You have #{pending_migrations.size} pending #{pending_migrations.size > 1 ? 'migrations:' : 'migration:'}"
@@ -454,12 +466,12 @@ db_namespace = namespace :db do
454
466
 
455
467
  desc "Load a database schema file (either db/schema.rb or db/structure.sql, depending on `ENV['SCHEMA_FORMAT']` or `config.active_record.schema_format`) into the database"
456
468
  task load: [:load_config, :check_protected_environments] do
457
- ActiveRecord::Tasks::DatabaseTasks.load_schema_current(ENV["SCHEMA_FORMAT"], ENV["SCHEMA"])
469
+ ActiveRecord::Tasks::DatabaseTasks.load_schema_current(nil, ENV["SCHEMA"])
458
470
  end
459
471
 
460
472
  namespace :dump do
461
473
  ActiveRecord::Tasks::DatabaseTasks.for_each(databases) do |name|
462
- desc "Create a database schema file (either db/schema.rb or db/structure.sql, depending on `ENV['SCHEMA_FORMAT']` or `config.active_record.schema_format`) for #{name} database"
474
+ desc "Create a database schema file (either db/schema.rb or db/structure.sql, depending on configuration) for #{name} database"
463
475
  task name => :load_config do
464
476
  ActiveRecord::Tasks::DatabaseTasks.with_temporary_pool_for_each(name: name) do |pool|
465
477
  db_config = pool.db_config
@@ -474,7 +486,7 @@ db_namespace = namespace :db do
474
486
  namespace :load do
475
487
  ActiveRecord::Tasks::DatabaseTasks.for_each(databases) do |name|
476
488
  desc "Load a database schema file (either db/schema.rb or db/structure.sql, depending on configuration) into the #{name} database"
477
- task name => "db:test:purge:#{name}" do
489
+ task name => [:load_config, :check_protected_environments] do
478
490
  ActiveRecord::Tasks::DatabaseTasks.with_temporary_pool_for_each(name: name) do |pool|
479
491
  db_config = pool.db_config
480
492
  ActiveRecord::Tasks::DatabaseTasks.load_schema(db_config, ENV["SCHEMA_FORMAT"] || db_config.schema_format)
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActiveRecord
4
+ module Railties # :nodoc:
5
+ module JobCheckpoints # :nodoc:
6
+ def checkpoint!
7
+ if ActiveRecord.all_open_transactions.any?
8
+ raise ActiveJob::Continuation::CheckpointError, "Cannot checkpoint job with open transactions"
9
+ else
10
+ super
11
+ end
12
+ end
13
+ end
14
+ end
15
+ end
@@ -5,19 +5,18 @@ require "active_record/runtime_registry"
5
5
  module ActiveRecord
6
6
  module Railties # :nodoc:
7
7
  module JobRuntime # :nodoc:
8
- private
9
- def instrument(operation, payload = {}, &block)
10
- if operation == :perform && block
11
- super(operation, payload) do
12
- db_runtime_before_perform = ActiveRecord::RuntimeRegistry.sql_runtime
13
- result = block.call
14
- payload[:db_runtime] = ActiveRecord::RuntimeRegistry.sql_runtime - db_runtime_before_perform
15
- result
16
- end
17
- else
18
- super
8
+ def instrument(operation, payload = {}, &block) # :nodoc:
9
+ if operation == :perform && block
10
+ super(operation, payload) do
11
+ db_runtime_before_perform = ActiveRecord::RuntimeRegistry.sql_runtime
12
+ result = block.call
13
+ payload[:db_runtime] = ActiveRecord::RuntimeRegistry.sql_runtime - db_runtime_before_perform
14
+ result
19
15
  end
16
+ else
17
+ super
20
18
  end
19
+ end
21
20
  end
22
21
  end
23
22
  end