activerecord 6.1.6 → 7.0.0.alpha1

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of activerecord might be problematic. Click here for more details.

Files changed (218) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +728 -1279
  3. data/MIT-LICENSE +1 -1
  4. data/README.rdoc +1 -1
  5. data/lib/active_record/aggregations.rb +1 -1
  6. data/lib/active_record/association_relation.rb +0 -10
  7. data/lib/active_record/associations/association.rb +31 -9
  8. data/lib/active_record/associations/association_scope.rb +1 -3
  9. data/lib/active_record/associations/belongs_to_association.rb +15 -4
  10. data/lib/active_record/associations/belongs_to_polymorphic_association.rb +10 -2
  11. data/lib/active_record/associations/builder/association.rb +8 -2
  12. data/lib/active_record/associations/builder/belongs_to.rb +19 -6
  13. data/lib/active_record/associations/builder/collection_association.rb +1 -1
  14. data/lib/active_record/associations/builder/has_many.rb +3 -2
  15. data/lib/active_record/associations/builder/has_one.rb +2 -1
  16. data/lib/active_record/associations/builder/singular_association.rb +2 -2
  17. data/lib/active_record/associations/collection_association.rb +14 -23
  18. data/lib/active_record/associations/collection_proxy.rb +8 -3
  19. data/lib/active_record/associations/disable_joins_association_scope.rb +59 -0
  20. data/lib/active_record/associations/has_many_association.rb +1 -1
  21. data/lib/active_record/associations/has_many_through_association.rb +2 -1
  22. data/lib/active_record/associations/has_one_association.rb +10 -7
  23. data/lib/active_record/associations/has_one_through_association.rb +1 -1
  24. data/lib/active_record/associations/preloader/association.rb +161 -47
  25. data/lib/active_record/associations/preloader/batch.rb +51 -0
  26. data/lib/active_record/associations/preloader/branch.rb +147 -0
  27. data/lib/active_record/associations/preloader/through_association.rb +37 -11
  28. data/lib/active_record/associations/preloader.rb +46 -110
  29. data/lib/active_record/associations/singular_association.rb +8 -2
  30. data/lib/active_record/associations/through_association.rb +1 -1
  31. data/lib/active_record/associations.rb +76 -81
  32. data/lib/active_record/asynchronous_queries_tracker.rb +57 -0
  33. data/lib/active_record/attribute_assignment.rb +1 -1
  34. data/lib/active_record/attribute_methods/before_type_cast.rb +7 -2
  35. data/lib/active_record/attribute_methods/dirty.rb +41 -16
  36. data/lib/active_record/attribute_methods/primary_key.rb +2 -2
  37. data/lib/active_record/attribute_methods/query.rb +2 -2
  38. data/lib/active_record/attribute_methods/read.rb +7 -5
  39. data/lib/active_record/attribute_methods/serialization.rb +66 -12
  40. data/lib/active_record/attribute_methods/time_zone_conversion.rb +4 -3
  41. data/lib/active_record/attribute_methods/write.rb +7 -10
  42. data/lib/active_record/attribute_methods.rb +6 -9
  43. data/lib/active_record/attributes.rb +24 -35
  44. data/lib/active_record/autosave_association.rb +3 -18
  45. data/lib/active_record/base.rb +19 -1
  46. data/lib/active_record/callbacks.rb +2 -2
  47. data/lib/active_record/connection_adapters/abstract/connection_handler.rb +312 -0
  48. data/lib/active_record/connection_adapters/abstract/connection_pool/queue.rb +209 -0
  49. data/lib/active_record/connection_adapters/abstract/connection_pool/reaper.rb +76 -0
  50. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +31 -558
  51. data/lib/active_record/connection_adapters/abstract/database_statements.rb +45 -21
  52. data/lib/active_record/connection_adapters/abstract/query_cache.rb +24 -12
  53. data/lib/active_record/connection_adapters/abstract/quoting.rb +11 -4
  54. data/lib/active_record/connection_adapters/abstract/schema_creation.rb +4 -17
  55. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +30 -13
  56. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +60 -16
  57. data/lib/active_record/connection_adapters/abstract/transaction.rb +3 -3
  58. data/lib/active_record/connection_adapters/abstract_adapter.rb +112 -66
  59. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +96 -81
  60. data/lib/active_record/connection_adapters/mysql/database_statements.rb +33 -23
  61. data/lib/active_record/connection_adapters/mysql/quoting.rb +16 -1
  62. data/lib/active_record/connection_adapters/mysql/schema_statements.rb +1 -1
  63. data/lib/active_record/connection_adapters/mysql2_adapter.rb +12 -6
  64. data/lib/active_record/connection_adapters/pool_config.rb +1 -3
  65. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +19 -14
  66. data/lib/active_record/connection_adapters/postgresql/oid/date.rb +8 -0
  67. data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +5 -0
  68. data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +53 -14
  69. data/lib/active_record/connection_adapters/postgresql/oid/range.rb +1 -1
  70. data/lib/active_record/connection_adapters/postgresql/oid/timestamp.rb +15 -0
  71. data/lib/active_record/connection_adapters/postgresql/oid/timestamp_with_time_zone.rb +28 -0
  72. data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +18 -6
  73. data/lib/active_record/connection_adapters/postgresql/oid.rb +2 -0
  74. data/lib/active_record/connection_adapters/postgresql/quoting.rb +6 -6
  75. data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +32 -0
  76. data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +5 -1
  77. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +12 -12
  78. data/lib/active_record/connection_adapters/postgresql_adapter.rb +157 -100
  79. data/lib/active_record/connection_adapters/schema_cache.rb +36 -37
  80. data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +23 -19
  81. data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +4 -2
  82. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +61 -30
  83. data/lib/active_record/connection_adapters.rb +6 -5
  84. data/lib/active_record/connection_handling.rb +20 -38
  85. data/lib/active_record/core.rb +111 -110
  86. data/lib/active_record/database_configurations/connection_url_resolver.rb +0 -1
  87. data/lib/active_record/database_configurations/database_config.rb +12 -0
  88. data/lib/active_record/database_configurations/hash_config.rb +27 -1
  89. data/lib/active_record/database_configurations/url_config.rb +2 -2
  90. data/lib/active_record/database_configurations.rb +17 -9
  91. data/lib/active_record/delegated_type.rb +33 -11
  92. data/lib/active_record/destroy_association_async_job.rb +1 -1
  93. data/lib/active_record/disable_joins_association_relation.rb +39 -0
  94. data/lib/active_record/dynamic_matchers.rb +1 -1
  95. data/lib/active_record/encryption/cipher/aes256_gcm.rb +98 -0
  96. data/lib/active_record/encryption/cipher.rb +53 -0
  97. data/lib/active_record/encryption/config.rb +44 -0
  98. data/lib/active_record/encryption/configurable.rb +61 -0
  99. data/lib/active_record/encryption/context.rb +35 -0
  100. data/lib/active_record/encryption/contexts.rb +72 -0
  101. data/lib/active_record/encryption/derived_secret_key_provider.rb +12 -0
  102. data/lib/active_record/encryption/deterministic_key_provider.rb +14 -0
  103. data/lib/active_record/encryption/encryptable_record.rb +208 -0
  104. data/lib/active_record/encryption/encrypted_attribute_type.rb +140 -0
  105. data/lib/active_record/encryption/encrypted_fixtures.rb +38 -0
  106. data/lib/active_record/encryption/encrypting_only_encryptor.rb +12 -0
  107. data/lib/active_record/encryption/encryptor.rb +155 -0
  108. data/lib/active_record/encryption/envelope_encryption_key_provider.rb +55 -0
  109. data/lib/active_record/encryption/errors.rb +15 -0
  110. data/lib/active_record/encryption/extended_deterministic_queries.rb +160 -0
  111. data/lib/active_record/encryption/extended_deterministic_uniqueness_validator.rb +29 -0
  112. data/lib/active_record/encryption/key.rb +28 -0
  113. data/lib/active_record/encryption/key_generator.rb +42 -0
  114. data/lib/active_record/encryption/key_provider.rb +46 -0
  115. data/lib/active_record/encryption/message.rb +33 -0
  116. data/lib/active_record/encryption/message_serializer.rb +80 -0
  117. data/lib/active_record/encryption/null_encryptor.rb +21 -0
  118. data/lib/active_record/encryption/properties.rb +76 -0
  119. data/lib/active_record/encryption/read_only_null_encryptor.rb +24 -0
  120. data/lib/active_record/encryption/scheme.rb +99 -0
  121. data/lib/active_record/encryption.rb +55 -0
  122. data/lib/active_record/enum.rb +41 -41
  123. data/lib/active_record/errors.rb +66 -3
  124. data/lib/active_record/fixture_set/file.rb +15 -1
  125. data/lib/active_record/fixture_set/table_row.rb +40 -5
  126. data/lib/active_record/fixture_set/table_rows.rb +4 -4
  127. data/lib/active_record/fixtures.rb +16 -11
  128. data/lib/active_record/future_result.rb +139 -0
  129. data/lib/active_record/gem_version.rb +4 -4
  130. data/lib/active_record/inheritance.rb +55 -17
  131. data/lib/active_record/insert_all.rb +34 -5
  132. data/lib/active_record/integration.rb +1 -1
  133. data/lib/active_record/internal_metadata.rb +1 -5
  134. data/lib/active_record/locking/optimistic.rb +10 -9
  135. data/lib/active_record/log_subscriber.rb +6 -2
  136. data/lib/active_record/middleware/database_selector/resolver.rb +6 -10
  137. data/lib/active_record/middleware/database_selector.rb +8 -3
  138. data/lib/active_record/migration/command_recorder.rb +4 -4
  139. data/lib/active_record/migration/compatibility.rb +89 -10
  140. data/lib/active_record/migration/join_table.rb +1 -1
  141. data/lib/active_record/migration.rb +109 -79
  142. data/lib/active_record/model_schema.rb +45 -31
  143. data/lib/active_record/nested_attributes.rb +3 -3
  144. data/lib/active_record/no_touching.rb +2 -2
  145. data/lib/active_record/null_relation.rb +2 -6
  146. data/lib/active_record/persistence.rb +134 -45
  147. data/lib/active_record/query_cache.rb +2 -2
  148. data/lib/active_record/query_logs.rb +203 -0
  149. data/lib/active_record/querying.rb +15 -5
  150. data/lib/active_record/railtie.rb +117 -17
  151. data/lib/active_record/railties/controller_runtime.rb +1 -1
  152. data/lib/active_record/railties/databases.rake +72 -48
  153. data/lib/active_record/readonly_attributes.rb +11 -0
  154. data/lib/active_record/reflection.rb +45 -44
  155. data/lib/active_record/relation/batches/batch_enumerator.rb +19 -5
  156. data/lib/active_record/relation/batches.rb +3 -3
  157. data/lib/active_record/relation/calculations.rb +39 -26
  158. data/lib/active_record/relation/delegation.rb +6 -6
  159. data/lib/active_record/relation/finder_methods.rb +31 -22
  160. data/lib/active_record/relation/merger.rb +20 -13
  161. data/lib/active_record/relation/predicate_builder.rb +1 -6
  162. data/lib/active_record/relation/query_attribute.rb +5 -11
  163. data/lib/active_record/relation/query_methods.rb +230 -47
  164. data/lib/active_record/relation/record_fetch_warning.rb +2 -2
  165. data/lib/active_record/relation/spawn_methods.rb +2 -2
  166. data/lib/active_record/relation/where_clause.rb +8 -4
  167. data/lib/active_record/relation.rb +166 -77
  168. data/lib/active_record/result.rb +17 -2
  169. data/lib/active_record/runtime_registry.rb +2 -4
  170. data/lib/active_record/sanitization.rb +11 -7
  171. data/lib/active_record/schema_dumper.rb +3 -3
  172. data/lib/active_record/schema_migration.rb +0 -4
  173. data/lib/active_record/scoping/default.rb +61 -12
  174. data/lib/active_record/scoping/named.rb +3 -11
  175. data/lib/active_record/scoping.rb +40 -22
  176. data/lib/active_record/serialization.rb +1 -1
  177. data/lib/active_record/signed_id.rb +1 -1
  178. data/lib/active_record/tasks/database_tasks.rb +106 -22
  179. data/lib/active_record/tasks/mysql_database_tasks.rb +1 -1
  180. data/lib/active_record/tasks/postgresql_database_tasks.rb +14 -11
  181. data/lib/active_record/test_databases.rb +1 -1
  182. data/lib/active_record/test_fixtures.rb +4 -4
  183. data/lib/active_record/timestamp.rb +3 -4
  184. data/lib/active_record/transactions.rb +9 -14
  185. data/lib/active_record/translation.rb +2 -2
  186. data/lib/active_record/type/adapter_specific_registry.rb +32 -7
  187. data/lib/active_record/type/hash_lookup_type_map.rb +34 -1
  188. data/lib/active_record/type/internal/timezone.rb +2 -2
  189. data/lib/active_record/type/serialized.rb +1 -1
  190. data/lib/active_record/type/type_map.rb +17 -20
  191. data/lib/active_record/type.rb +1 -2
  192. data/lib/active_record/validations/associated.rb +1 -1
  193. data/lib/active_record.rb +170 -2
  194. data/lib/arel/attributes/attribute.rb +0 -8
  195. data/lib/arel/crud.rb +18 -22
  196. data/lib/arel/delete_manager.rb +2 -4
  197. data/lib/arel/insert_manager.rb +2 -3
  198. data/lib/arel/nodes/casted.rb +1 -1
  199. data/lib/arel/nodes/delete_statement.rb +8 -13
  200. data/lib/arel/nodes/insert_statement.rb +2 -2
  201. data/lib/arel/nodes/select_core.rb +2 -2
  202. data/lib/arel/nodes/select_statement.rb +2 -2
  203. data/lib/arel/nodes/update_statement.rb +3 -2
  204. data/lib/arel/predications.rb +1 -1
  205. data/lib/arel/select_manager.rb +10 -4
  206. data/lib/arel/table.rb +0 -1
  207. data/lib/arel/tree_manager.rb +0 -12
  208. data/lib/arel/update_manager.rb +2 -4
  209. data/lib/arel/visitors/dot.rb +80 -90
  210. data/lib/arel/visitors/mysql.rb +6 -1
  211. data/lib/arel/visitors/postgresql.rb +0 -10
  212. data/lib/arel/visitors/to_sql.rb +43 -2
  213. data/lib/arel.rb +1 -1
  214. data/lib/rails/generators/active_record/application_record/templates/application_record.rb.tt +1 -1
  215. data/lib/rails/generators/active_record/model/templates/abstract_base_class.rb.tt +1 -1
  216. data/lib/rails/generators/active_record/model/templates/model.rb.tt +1 -1
  217. data/lib/rails/generators/active_record/model/templates/module.rb.tt +2 -2
  218. metadata +55 -17
@@ -17,20 +17,7 @@ module ActiveRecord
17
17
  # Accepts a logger conforming to the interface of Log4r which is then
18
18
  # passed on to any new database connections made and which can be
19
19
  # retrieved on both a class and instance level by calling +logger+.
20
- mattr_accessor :logger, instance_writer: false
21
-
22
- ##
23
- # :singleton-method:
24
- #
25
- # Specifies if the methods calling database queries should be logged below
26
- # their relevant queries. Defaults to false.
27
- mattr_accessor :verbose_query_logs, instance_writer: false, default: false
28
-
29
- ##
30
- # :singleton-method:
31
- #
32
- # Specifies the names of the queues used by background jobs.
33
- mattr_accessor :queues, instance_accessor: false, default: {}
20
+ class_attribute :logger, instance_writer: false
34
21
 
35
22
  ##
36
23
  # :singleton-method:
@@ -72,80 +59,17 @@ module ActiveRecord
72
59
 
73
60
  ##
74
61
  # :singleton-method:
75
- # Determines whether to use Time.utc (using :utc) or Time.local (using :local) when pulling
76
- # dates and times from the database. This is set to :utc by default.
77
- mattr_accessor :default_timezone, instance_writer: false, default: :utc
78
-
79
- ##
80
- # :singleton-method:
81
- # Specifies the format to use when dumping the database schema with Rails'
82
- # Rakefile. If :sql, the schema is dumped as (potentially database-
83
- # specific) SQL statements. If :ruby, the schema is dumped as an
84
- # ActiveRecord::Schema file which can be loaded into any database that
85
- # supports migrations. Use :ruby if you want to have different database
86
- # adapters for, e.g., your development and test environments.
87
- mattr_accessor :schema_format, instance_writer: false, default: :ruby
88
-
89
- ##
90
- # :singleton-method:
91
- # Specifies if an error should be raised if the query has an order being
92
- # ignored when doing batch queries. Useful in applications where the
93
- # scope being ignored is error-worthy, rather than a warning.
94
- mattr_accessor :error_on_ignored_order, instance_writer: false, default: false
95
-
96
- ##
97
- # :singleton-method:
98
- # Specify whether or not to use timestamps for migration versions
99
- mattr_accessor :timestamped_migrations, instance_writer: false, default: true
100
-
101
- ##
102
- # :singleton-method:
103
- # Specify whether schema dump should happen at the end of the
104
- # db:migrate rails command. This is true by default, which is useful for the
105
- # development environment. This should ideally be false in the production
106
- # environment where dumping schema is rarely needed.
107
- mattr_accessor :dump_schema_after_migration, instance_writer: false, default: true
108
-
109
- ##
110
- # :singleton-method:
111
- # Specifies which database schemas to dump when calling db:schema:dump.
112
- # If the value is :schema_search_path (the default), any schemas listed in
113
- # schema_search_path are dumped. Use :all to dump all schemas regardless
114
- # of schema_search_path, or a string of comma separated schemas for a
115
- # custom list.
116
- mattr_accessor :dump_schemas, instance_writer: false, default: :schema_search_path
117
-
118
- ##
119
- # :singleton-method:
120
- # Specify a threshold for the size of query result sets. If the number of
121
- # records in the set exceeds the threshold, a warning is logged. This can
122
- # be used to identify queries which load thousands of records and
123
- # potentially cause memory bloat.
124
- mattr_accessor :warn_on_records_fetched_greater_than, instance_writer: false
125
-
126
- ##
127
- # :singleton-method:
128
- # Show a warning when Rails couldn't parse your database.yml
129
- # for multiple databases.
130
- mattr_accessor :suppress_multiple_database_warning, instance_writer: false, default: false
131
-
132
- mattr_accessor :maintain_test_schema, instance_accessor: false
62
+ # Force enumeration of all columns in SELECT statements.
63
+ # e.g. `SELECT first_name, last_name FROM ...` instead of `SELECT * FROM ...`
64
+ # This avoids +PreparedStatementCacheExpired+ errors when a column is added
65
+ # to the database while the app is running.
66
+ class_attribute :enumerate_columns_in_select_statements, instance_accessor: false, default: false
133
67
 
134
68
  class_attribute :belongs_to_required_by_default, instance_accessor: false
135
69
 
136
- ##
137
- # :singleton-method:
138
- # Set the application to log or raise when an association violates strict loading.
139
- # Defaults to :raise.
140
- mattr_accessor :action_on_strict_loading_violation, instance_accessor: false, default: :raise
141
-
142
70
  class_attribute :strict_loading_by_default, instance_accessor: false, default: false
143
71
 
144
- mattr_accessor :writing_role, instance_accessor: false, default: :writing
145
-
146
- mattr_accessor :reading_role, instance_accessor: false, default: :reading
147
-
148
- mattr_accessor :has_many_inversing, instance_accessor: false, default: false
72
+ class_attribute :has_many_inversing, instance_accessor: false, default: false
149
73
 
150
74
  class_attribute :default_connection_handler, instance_writer: false
151
75
 
@@ -153,7 +77,15 @@ module ActiveRecord
153
77
 
154
78
  class_attribute :default_shard, instance_writer: false
155
79
 
156
- mattr_accessor :legacy_connection_handling, instance_writer: false, default: true
80
+ def self.application_record_class? # :nodoc:
81
+ if ActiveRecord.application_record_class
82
+ self == ActiveRecord.application_record_class
83
+ else
84
+ if defined?(ApplicationRecord) && self == ApplicationRecord
85
+ true
86
+ end
87
+ end
88
+ end
157
89
 
158
90
  self.filter_attributes = []
159
91
 
@@ -166,7 +98,8 @@ module ActiveRecord
166
98
  end
167
99
 
168
100
  def self.connection_handlers
169
- unless legacy_connection_handling
101
+ if ActiveRecord.legacy_connection_handling
102
+ else
170
103
  raise NotImplementedError, "The new connection handling does not support accessing multiple connection handlers."
171
104
  end
172
105
 
@@ -174,13 +107,32 @@ module ActiveRecord
174
107
  end
175
108
 
176
109
  def self.connection_handlers=(handlers)
177
- unless legacy_connection_handling
178
- raise NotImplementedError, "The new connection handling does not setting support multiple connection handlers."
110
+ if ActiveRecord.legacy_connection_handling
111
+ ActiveSupport::Deprecation.warn(<<~MSG)
112
+ Using legacy connection handling is deprecated. Please set
113
+ `legacy_connection_handling` to `false` in your application.
114
+
115
+ The new connection handling does not support `connection_handlers`
116
+ getter and setter.
117
+
118
+ Read more about how to migrate at: https://guides.rubyonrails.org/active_record_multiple_databases.html#migrate-to-the-new-connection-handling
119
+ MSG
120
+ else
121
+ raise NotImplementedError, "The new connection handling does not support multiple connection handlers."
179
122
  end
180
123
 
181
124
  @@connection_handlers = handlers
182
125
  end
183
126
 
127
+ def self.asynchronous_queries_session # :nodoc:
128
+ asynchronous_queries_tracker.current_session
129
+ end
130
+
131
+ def self.asynchronous_queries_tracker # :nodoc:
132
+ Thread.current.thread_variable_get(:ar_asynchronous_queries_tracker) ||
133
+ Thread.current.thread_variable_set(:ar_asynchronous_queries_tracker, AsynchronousQueriesTracker.new)
134
+ end
135
+
184
136
  # Returns the symbol representing the current connected role.
185
137
  #
186
138
  # ActiveRecord::Base.connected_to(role: :writing) do
@@ -191,7 +143,7 @@ module ActiveRecord
191
143
  # ActiveRecord::Base.current_role #=> :reading
192
144
  # end
193
145
  def self.current_role
194
- if ActiveRecord::Base.legacy_connection_handling
146
+ if ActiveRecord.legacy_connection_handling
195
147
  connection_handlers.key(connection_handler) || default_role
196
148
  else
197
149
  connected_to_stack.reverse_each do |hash|
@@ -232,7 +184,7 @@ module ActiveRecord
232
184
  # ActiveRecord::Base.current_preventing_writes #=> false
233
185
  # end
234
186
  def self.current_preventing_writes
235
- if legacy_connection_handling
187
+ if ActiveRecord.legacy_connection_handling
236
188
  connection_handler.prevent_writes
237
189
  else
238
190
  connected_to_stack.reverse_each do |hash|
@@ -258,7 +210,7 @@ module ActiveRecord
258
210
  @connection_class = b
259
211
  end
260
212
 
261
- def self.connection_class # :nodoc
213
+ def self.connection_class # :nodoc:
262
214
  @connection_class ||= false
263
215
  end
264
216
 
@@ -286,11 +238,11 @@ module ActiveRecord
286
238
  end
287
239
 
288
240
  self.default_connection_handler = ConnectionAdapters::ConnectionHandler.new
289
- self.default_role = writing_role
241
+ self.default_role = ActiveRecord.writing_role
290
242
  self.default_shard = :default
291
243
 
292
244
  def self.strict_loading_violation!(owner:, reflection:) # :nodoc:
293
- case action_on_strict_loading_violation
245
+ case ActiveRecord.action_on_strict_loading_violation
294
246
  when :raise
295
247
  message = "`#{owner}` is marked for strict_loading. The `#{reflection.klass}` association named `:#{reflection.name}` cannot be lazily loaded."
296
248
  raise ActiveRecord::StrictLoadingViolationError.new(message)
@@ -381,7 +333,32 @@ module ActiveRecord
381
333
  end
382
334
 
383
335
  def find_by!(*args) # :nodoc:
384
- find_by(*args) || raise(RecordNotFound.new("Couldn't find #{name}", name))
336
+ find_by(*args) || where(*args).raise_record_not_found_exception!
337
+ end
338
+
339
+ %w(
340
+ reading_role writing_role legacy_connection_handling default_timezone index_nested_attribute_errors
341
+ verbose_query_logs queues warn_on_records_fetched_greater_than maintain_test_schema
342
+ application_record_class action_on_strict_loading_violation schema_format error_on_ignored_order
343
+ timestamped_migrations dump_schema_after_migration dump_schemas suppress_multiple_database_warning
344
+ ).each do |attr|
345
+ module_eval(<<~RUBY, __FILE__, __LINE__ + 1)
346
+ def #{attr}
347
+ ActiveSupport::Deprecation.warn(<<~MSG)
348
+ ActiveRecord::Base.#{attr} is deprecated and will be removed in Rails 7.1.
349
+ Use `ActiveRecord.#{attr}` instead.
350
+ MSG
351
+ ActiveRecord.#{attr}
352
+ end
353
+
354
+ def #{attr}=(value)
355
+ ActiveSupport::Deprecation.warn(<<~MSG)
356
+ ActiveRecord::Base.#{attr}= is deprecated and will be removed in Rails 7.1.
357
+ Use `ActiveRecord.#{attr}=` instead.
358
+ MSG
359
+ ActiveRecord.#{attr} = value
360
+ end
361
+ RUBY
385
362
  end
386
363
 
387
364
  def initialize_generated_modules # :nodoc:
@@ -446,10 +423,6 @@ module ActiveRecord
446
423
  end
447
424
 
448
425
  # Returns an instance of <tt>Arel::Table</tt> loaded with the current table name.
449
- #
450
- # class Post < ActiveRecord::Base
451
- # scope :published_and_commented, -> { published.and(arel_table[:comments_count].gt(0)) }
452
- # end
453
426
  def arel_table # :nodoc:
454
427
  @arel_table ||= Arel::Table.new(table_name, klass: self)
455
428
  end
@@ -467,10 +440,6 @@ module ActiveRecord
467
440
  TypeCaster::Map.new(self)
468
441
  end
469
442
 
470
- def _internal? # :nodoc:
471
- false
472
- end
473
-
474
443
  def cached_find_by_statement(key, &block) # :nodoc:
475
444
  cache = @find_by_statement_cache[connection.prepared_statements]
476
445
  cache.compute_if_absent(key) { StatementCache.create(connection, &block) }
@@ -630,6 +599,8 @@ module ActiveRecord
630
599
  # Delegates to id in order to allow two records of the same type and id to work with something like:
631
600
  # [ Person.find(1), Person.find(2), Person.find(3) ] & [ Person.find(1), Person.find(4) ] # => [ Person.find(1) ]
632
601
  def hash
602
+ id = self.id
603
+
633
604
  if id
634
605
  self.class.hash ^ id.hash
635
606
  else
@@ -681,11 +652,37 @@ module ActiveRecord
681
652
  # if the record tries to lazily load an association.
682
653
  #
683
654
  # user = User.first
684
- # user.strict_loading!
685
- # user.comments.to_a
655
+ # user.strict_loading! # => true
656
+ # user.comments
686
657
  # => ActiveRecord::StrictLoadingViolationError
687
- def strict_loading!
688
- @strict_loading = true
658
+ #
659
+ # === Parameters:
660
+ #
661
+ # * value - Boolean specifying whether to enable or disable strict loading.
662
+ # * mode - Symbol specifying strict loading mode. Defaults to :all. Using
663
+ # :n_plus_one_only mode will only raise an error if an association
664
+ # that will lead to an n plus one query is lazily loaded.
665
+ #
666
+ # === Example:
667
+ #
668
+ # user = User.first
669
+ # user.strict_loading!(false) # => false
670
+ # user.comments
671
+ # => #<ActiveRecord::Associations::CollectionProxy>
672
+ def strict_loading!(value = true, mode: :all)
673
+ unless [:all, :n_plus_one_only].include?(mode)
674
+ raise ArgumentError, "The :mode option must be one of [:all, :n_plus_one_only]."
675
+ end
676
+
677
+ @strict_loading_mode = mode
678
+ @strict_loading = value
679
+ end
680
+
681
+ attr_reader :strict_loading_mode
682
+
683
+ # Returns +true+ if the record uses strict_loading with +:n_plus_one_only+ mode enabled.
684
+ def strict_loading_n_plus_one_only?
685
+ @strict_loading_mode == :n_plus_one_only
689
686
  end
690
687
 
691
688
  # Marks this record as read only.
@@ -702,11 +699,11 @@ module ActiveRecord
702
699
  # We check defined?(@attributes) not to issue warnings if the object is
703
700
  # allocated but not initialized.
704
701
  inspection = if defined?(@attributes) && @attributes
705
- self.class.attribute_names.collect do |name|
702
+ self.class.attribute_names.filter_map do |name|
706
703
  if _has_attribute?(name)
707
704
  "#{name}: #{attribute_for_inspect(name)}"
708
705
  end
709
- end.compact.join(", ")
706
+ end.join(", ")
710
707
  else
711
708
  "not initialized"
712
709
  end
@@ -763,16 +760,20 @@ module ActiveRecord
763
760
  end
764
761
 
765
762
  def init_internals
766
- @primary_key = self.class.primary_key
767
763
  @readonly = false
768
764
  @previously_new_record = false
769
765
  @destroyed = false
770
766
  @marked_for_destruction = false
771
767
  @destroyed_by_association = nil
772
768
  @_start_transaction_state = nil
773
- @strict_loading = self.class.strict_loading_by_default
774
769
 
775
- self.class.define_attribute_methods
770
+ klass = self.class
771
+
772
+ @primary_key = klass.primary_key
773
+ @strict_loading = klass.strict_loading_by_default
774
+ @strict_loading_mode = :all
775
+
776
+ klass.define_attribute_methods
776
777
  end
777
778
 
778
779
  def initialize_internals_callback
@@ -1,6 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "uri"
4
3
  require "active_support/core_ext/enumerable"
5
4
 
6
5
  module ActiveRecord
@@ -48,6 +48,18 @@ module ActiveRecord
48
48
  raise NotImplementedError
49
49
  end
50
50
 
51
+ def min_threads
52
+ raise NotImplementedError
53
+ end
54
+
55
+ def max_threads
56
+ raise NotImplementedError
57
+ end
58
+
59
+ def max_queue
60
+ raise NotImplementedError
61
+ end
62
+
51
63
  def checkout_timeout
52
64
  raise NotImplementedError
53
65
  end
@@ -26,13 +26,14 @@ module ActiveRecord
26
26
  # connections.
27
27
  class HashConfig < DatabaseConfig
28
28
  attr_reader :configuration_hash
29
+
29
30
  def initialize(env_name, name, configuration_hash)
30
31
  super(env_name, name)
31
32
  @configuration_hash = configuration_hash.symbolize_keys.freeze
32
33
  end
33
34
 
34
35
  def config
35
- ActiveSupport::Deprecation.warn("DatabaseConfig#config will be removed in 7.0.0 in favor of DatabaseConfig#configuration_hash which returns a hash with symbol keys")
36
+ ActiveSupport::Deprecation.warn("DatabaseConfig#config will be removed in 7.0.0 in favor of DatabaseConfigurations#configuration_hash which returns a hash with symbol keys")
36
37
  configuration_hash.stringify_keys
37
38
  end
38
39
 
@@ -54,6 +55,10 @@ module ActiveRecord
54
55
  configuration_hash[:host]
55
56
  end
56
57
 
58
+ def socket # :nodoc:
59
+ configuration_hash[:socket]
60
+ end
61
+
57
62
  def database
58
63
  configuration_hash[:database]
59
64
  end
@@ -66,6 +71,18 @@ module ActiveRecord
66
71
  (configuration_hash[:pool] || 5).to_i
67
72
  end
68
73
 
74
+ def min_threads
75
+ (configuration_hash[:min_threads] || 0).to_i
76
+ end
77
+
78
+ def max_threads
79
+ (configuration_hash[:max_threads] || pool).to_i
80
+ end
81
+
82
+ def max_queue
83
+ max_threads * 4
84
+ end
85
+
69
86
  def checkout_timeout
70
87
  (configuration_hash[:checkout_timeout] || 5).to_f
71
88
  end
@@ -91,6 +108,15 @@ module ActiveRecord
91
108
  def schema_cache_path
92
109
  configuration_hash[:schema_cache_path]
93
110
  end
111
+
112
+ # Determines whether to dump the schema for a database.
113
+ def schema_dump
114
+ configuration_hash.fetch(:schema_dump, true)
115
+ end
116
+
117
+ def database_tasks? # :nodoc:
118
+ !replica? && !!configuration_hash.fetch(:database_tasks, true)
119
+ end
94
120
  end
95
121
  end
96
122
  end
@@ -19,7 +19,7 @@ module ActiveRecord
19
19
  #
20
20
  # ==== Options
21
21
  #
22
- # * <tt>:env_name</tt> - The Rails environment, ie "development".
22
+ # * <tt>:env_name</tt> - The Rails environment, i.e. "development".
23
23
  # * <tt>:name</tt> - The db config name. In a standard two-tier
24
24
  # database configuration this will default to "primary". In a multiple
25
25
  # database three-tier database configuration this corresponds to the name
@@ -42,7 +42,7 @@ module ActiveRecord
42
42
  # Return a Hash that can be merged into the main config that represents
43
43
  # the passed in url
44
44
  def build_url_hash
45
- if url.nil? || %w(jdbc: http: https:).any? { |protocol| url.start_with?(protocol) }
45
+ if url.nil? || url.start_with?("jdbc:", "http:", "https:")
46
46
  { url: url }
47
47
  else
48
48
  ConnectionUrlResolver.new(url).to_hash
@@ -1,6 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "uri"
4
3
  require "active_record/database_configurations/database_config"
5
4
  require "active_record/database_configurations/hash_config"
6
5
  require "active_record/database_configurations/url_config"
@@ -21,7 +20,7 @@ module ActiveRecord
21
20
  end
22
21
 
23
22
  # Collects the configs for the environment and optionally the specification
24
- # name passed in. To include replica configurations pass <tt>include_replicas: true</tt>.
23
+ # name passed in. To include replica configurations pass <tt>include_hidden: true</tt>.
25
24
  #
26
25
  # If a name is provided a single DatabaseConfig object will be
27
26
  # returned, otherwise an array of DatabaseConfig objects will be
@@ -34,22 +33,31 @@ module ActiveRecord
34
33
  # * <tt>name:</tt> The db config name (i.e. primary, animals, etc.). Defaults
35
34
  # to +nil+. If no +env_name+ is specified the config for the default env and the
36
35
  # passed +name+ will be returned.
37
- # * <tt>include_replicas:</tt> Determines whether to include replicas in
36
+ # * <tt>include_replicas:</tt> Deprecated. Determines whether to include replicas in
38
37
  # the returned list. Most of the time we're only iterating over the write
39
38
  # connection (i.e. migrations don't need to run for the write and read connection).
40
39
  # Defaults to +false+.
41
- def configs_for(env_name: nil, spec_name: nil, name: nil, include_replicas: false)
40
+ # * <tt>include_hidden:</tte Determines whether to include replicas and configurations
41
+ # hidden by +database_tasks: false+ in the returned list. Most of the time we're only
42
+ # iterating over the primary connections (i.e. migrations don't need to run for the
43
+ # write and read connection). Defaults to +false+.
44
+ def configs_for(env_name: nil, spec_name: nil, name: nil, include_replicas: false, include_hidden: false)
42
45
  if spec_name
43
46
  name = spec_name
44
47
  ActiveSupport::Deprecation.warn("The kwarg `spec_name` is deprecated in favor of `name`. `spec_name` will be removed in Rails 7.0")
45
48
  end
46
49
 
50
+ if include_replicas
51
+ include_hidden = include_replicas
52
+ ActiveSupport::Deprecation.warn("The kwarg `include_replicas` is deprecated in favor of `include_hidden`. When `include_hidden` is passed, configurations with `replica: true` or `database_tasks: false` will be returned. `include_replicas` will be removed in Rails 7.1.")
53
+ end
54
+
47
55
  env_name ||= default_env if name
48
56
  configs = env_with_configs(env_name)
49
57
 
50
- unless include_replicas
58
+ unless include_hidden
51
59
  configs = configs.select do |db_config|
52
- !db_config.replica?
60
+ db_config.database_tasks?
53
61
  end
54
62
  end
55
63
 
@@ -167,7 +175,7 @@ module ActiveRecord
167
175
  return configs if configs.is_a?(Array)
168
176
 
169
177
  db_configs = configs.flat_map do |env_name, config|
170
- if config.is_a?(Hash) && config.all? { |_, v| v.is_a?(Hash) }
178
+ if config.is_a?(Hash) && config.values.all?(Hash)
171
179
  walk_configs(env_name.to_s, config)
172
180
  else
173
181
  build_db_config_from_raw_config(env_name.to_s, "primary", config)
@@ -194,7 +202,7 @@ module ActiveRecord
194
202
  raise AdapterNotSpecified, <<~MSG
195
203
  The `#{name}` database is not configured for the `#{default_env}` environment.
196
204
 
197
- Available databases configurations are:
205
+ Available database configurations are:
198
206
 
199
207
  #{build_configuration_sentence}
200
208
  MSG
@@ -202,7 +210,7 @@ module ActiveRecord
202
210
  end
203
211
 
204
212
  def build_configuration_sentence
205
- configs = configs_for(include_replicas: true)
213
+ configs = configs_for(include_hidden: true)
206
214
 
207
215
  configs.group_by(&:env_name).map do |env, config|
208
216
  names = config.map(&:name)
@@ -51,10 +51,9 @@ module ActiveRecord
51
51
  # end
52
52
  # end
53
53
  #
54
- # # Schema: messages[ id, subject ]
54
+ # # Schema: messages[ id, subject, body ]
55
55
  # class Message < ApplicationRecord
56
56
  # include Entryable
57
- # has_rich_text :content
58
57
  # end
59
58
  #
60
59
  # # Schema: comments[ id, content ]
@@ -66,7 +65,7 @@ module ActiveRecord
66
65
  # resides in the +Entry+ "superclass". But the +Entry+ absolutely can stand alone in terms of querying capacity
67
66
  # in particular. You can now easily do things like:
68
67
  #
69
- # Account.entries.order(created_at: :desc).limit(50)
68
+ # Account.find(1).entries.order(created_at: :desc).limit(50)
70
69
  #
71
70
  # Which is exactly what you want when displaying both comments and messages together. The entry itself can
72
71
  # be rendered as its delegated type easily, like so:
@@ -76,7 +75,9 @@ module ActiveRecord
76
75
  #
77
76
  # # entries/entryables/_message.html.erb
78
77
  # <div class="message">
79
- # Posted on <%= entry.created_at %> by <%= entry.creator.name %>: <%= entry.message.content %>
78
+ # <div class="subject"><%= entry.message.subject %></div>
79
+ # <p><%= entry.message.body %></p>
80
+ # <i>Posted on <%= entry.created_at %> by <%= entry.creator.name %></i>
80
81
  # </div>
81
82
  #
82
83
  # # entries/entryables/_comment.html.erb
@@ -156,8 +157,6 @@ module ActiveRecord
156
157
  # Entry#comment # => returns the comment record, when entryable_type == "Comment", otherwise nil
157
158
  # Entry#comment_id # => returns entryable_id, when entryable_type == "Comment", otherwise nil
158
159
  #
159
- # The +options+ are passed directly to the +belongs_to+ call, so this is where you declare +dependent+ etc.
160
- #
161
160
  # You can also declare namespaced types:
162
161
  #
163
162
  # class Entry < ApplicationRecord
@@ -167,15 +166,38 @@ module ActiveRecord
167
166
  # Entry.access_notice_messages
168
167
  # entry.access_notice_message
169
168
  # entry.access_notice_message?
169
+ #
170
+ # === Options
171
+ #
172
+ # The +options+ are passed directly to the +belongs_to+ call, so this is where you declare +dependent+ etc.
173
+ # The following options can be included to specialize the behavior of the delegated type convenience methods.
174
+ #
175
+ # [:foreign_key]
176
+ # Specify the foreign key used for the convenience methods. By default this is guessed to be the passed
177
+ # +role+ with an "_id" suffix. So a class that defines a
178
+ # <tt>delegated_type :entryable, types: %w[ Message Comment ]</tt> association will use "entryable_id" as
179
+ # the default <tt>:foreign_key</tt>.
180
+ # [:primary_key]
181
+ # Specify the method that returns the primary key of associated object used for the convenience methods.
182
+ # By default this is +id+.
183
+ #
184
+ # Option examples:
185
+ # class Entry < ApplicationRecord
186
+ # delegated_type :entryable, types: %w[ Message Comment ], primary_key: :uuid, foreign_key: :entryable_uuid
187
+ # end
188
+ #
189
+ # Entry#message_uuid # => returns entryable_uuid, when entryable_type == "Message", otherwise nil
190
+ # Entry#comment_uuid # => returns entryable_uuid, when entryable_type == "Comment", otherwise nil
170
191
  def delegated_type(role, types:, **options)
171
192
  belongs_to role, options.delete(:scope), **options.merge(polymorphic: true)
172
- define_delegated_type_methods role, types: types
193
+ define_delegated_type_methods role, types: types, options: options
173
194
  end
174
195
 
175
196
  private
176
- def define_delegated_type_methods(role, types:)
197
+ def define_delegated_type_methods(role, types:, options:)
198
+ primary_key = options[:primary_key] || "id"
177
199
  role_type = "#{role}_type"
178
- role_id = "#{role}_id"
200
+ role_id = options[:foreign_key] || "#{role}_id"
179
201
 
180
202
  define_method "#{role}_class" do
181
203
  public_send("#{role}_type").constantize
@@ -186,7 +208,7 @@ module ActiveRecord
186
208
  end
187
209
 
188
210
  types.each do |type|
189
- scope_name = type.tableize.gsub("/", "_")
211
+ scope_name = type.tableize.tr("/", "_")
190
212
  singular = scope_name.singularize
191
213
  query = "#{singular}?"
192
214
 
@@ -200,7 +222,7 @@ module ActiveRecord
200
222
  public_send(role) if public_send(query)
201
223
  end
202
224
 
203
- define_method "#{singular}_id" do
225
+ define_method "#{singular}_#{primary_key}" do
204
226
  public_send(role_id) if public_send(query)
205
227
  end
206
228
  end
@@ -6,7 +6,7 @@ module ActiveRecord
6
6
 
7
7
  # Job to destroy the records associated with a destroyed record in background.
8
8
  class DestroyAssociationAsyncJob < ActiveJob::Base
9
- queue_as { ActiveRecord::Base.queues[:destroy] }
9
+ queue_as { ActiveRecord.queues[:destroy] }
10
10
 
11
11
  discard_on ActiveJob::DeserializationError
12
12