activerecord 6.1.6 → 7.0.4

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 (243) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +1314 -975
  3. data/README.rdoc +1 -1
  4. data/lib/active_record/aggregations.rb +1 -1
  5. data/lib/active_record/association_relation.rb +0 -10
  6. data/lib/active_record/associations/association.rb +33 -17
  7. data/lib/active_record/associations/association_scope.rb +1 -3
  8. data/lib/active_record/associations/belongs_to_association.rb +15 -4
  9. data/lib/active_record/associations/belongs_to_polymorphic_association.rb +10 -2
  10. data/lib/active_record/associations/builder/association.rb +8 -2
  11. data/lib/active_record/associations/builder/belongs_to.rb +19 -6
  12. data/lib/active_record/associations/builder/collection_association.rb +10 -3
  13. data/lib/active_record/associations/builder/has_many.rb +3 -2
  14. data/lib/active_record/associations/builder/has_one.rb +2 -1
  15. data/lib/active_record/associations/builder/singular_association.rb +2 -2
  16. data/lib/active_record/associations/collection_association.rb +19 -21
  17. data/lib/active_record/associations/collection_proxy.rb +10 -5
  18. data/lib/active_record/associations/disable_joins_association_scope.rb +59 -0
  19. data/lib/active_record/associations/has_many_association.rb +8 -5
  20. data/lib/active_record/associations/has_many_through_association.rb +2 -1
  21. data/lib/active_record/associations/has_one_association.rb +10 -7
  22. data/lib/active_record/associations/has_one_through_association.rb +1 -1
  23. data/lib/active_record/associations/join_dependency.rb +23 -15
  24. data/lib/active_record/associations/preloader/association.rb +186 -52
  25. data/lib/active_record/associations/preloader/batch.rb +48 -0
  26. data/lib/active_record/associations/preloader/branch.rb +147 -0
  27. data/lib/active_record/associations/preloader/through_association.rb +49 -13
  28. data/lib/active_record/associations/preloader.rb +39 -113
  29. data/lib/active_record/associations/singular_association.rb +8 -2
  30. data/lib/active_record/associations/through_association.rb +3 -3
  31. data/lib/active_record/associations.rb +124 -95
  32. data/lib/active_record/asynchronous_queries_tracker.rb +60 -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 +49 -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 +57 -19
  40. data/lib/active_record/attribute_methods/time_zone_conversion.rb +8 -3
  41. data/lib/active_record/attribute_methods/write.rb +7 -10
  42. data/lib/active_record/attribute_methods.rb +14 -15
  43. data/lib/active_record/attributes.rb +24 -35
  44. data/lib/active_record/autosave_association.rb +8 -23
  45. data/lib/active_record/base.rb +19 -1
  46. data/lib/active_record/callbacks.rb +2 -2
  47. data/lib/active_record/coders/yaml_column.rb +10 -2
  48. data/lib/active_record/connection_adapters/abstract/connection_handler.rb +292 -0
  49. data/lib/active_record/connection_adapters/abstract/connection_pool/queue.rb +209 -0
  50. data/lib/active_record/connection_adapters/abstract/connection_pool/reaper.rb +76 -0
  51. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +47 -561
  52. data/lib/active_record/connection_adapters/abstract/database_limits.rb +0 -17
  53. data/lib/active_record/connection_adapters/abstract/database_statements.rb +46 -22
  54. data/lib/active_record/connection_adapters/abstract/query_cache.rb +24 -12
  55. data/lib/active_record/connection_adapters/abstract/quoting.rb +42 -72
  56. data/lib/active_record/connection_adapters/abstract/schema_creation.rb +4 -17
  57. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +38 -13
  58. data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +14 -1
  59. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +80 -24
  60. data/lib/active_record/connection_adapters/abstract/transaction.rb +15 -22
  61. data/lib/active_record/connection_adapters/abstract_adapter.rb +149 -74
  62. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +105 -81
  63. data/lib/active_record/connection_adapters/column.rb +4 -0
  64. data/lib/active_record/connection_adapters/mysql/database_statements.rb +36 -24
  65. data/lib/active_record/connection_adapters/mysql/quoting.rb +37 -21
  66. data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +7 -1
  67. data/lib/active_record/connection_adapters/mysql/schema_statements.rb +20 -1
  68. data/lib/active_record/connection_adapters/mysql2_adapter.rb +12 -6
  69. data/lib/active_record/connection_adapters/pool_config.rb +7 -7
  70. data/lib/active_record/connection_adapters/postgresql/column.rb +17 -1
  71. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +19 -12
  72. data/lib/active_record/connection_adapters/postgresql/oid/date.rb +8 -0
  73. data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +5 -0
  74. data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +53 -14
  75. data/lib/active_record/connection_adapters/postgresql/oid/range.rb +1 -1
  76. data/lib/active_record/connection_adapters/postgresql/oid/timestamp.rb +15 -0
  77. data/lib/active_record/connection_adapters/postgresql/oid/timestamp_with_time_zone.rb +30 -0
  78. data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +18 -6
  79. data/lib/active_record/connection_adapters/postgresql/oid.rb +2 -0
  80. data/lib/active_record/connection_adapters/postgresql/quoting.rb +51 -51
  81. data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +34 -0
  82. data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +21 -1
  83. data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +22 -1
  84. data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +25 -0
  85. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +37 -19
  86. data/lib/active_record/connection_adapters/postgresql_adapter.rb +208 -107
  87. data/lib/active_record/connection_adapters/schema_cache.rb +39 -38
  88. data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +25 -19
  89. data/lib/active_record/connection_adapters/sqlite3/quoting.rb +28 -16
  90. data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +17 -15
  91. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +96 -32
  92. data/lib/active_record/connection_adapters.rb +6 -5
  93. data/lib/active_record/connection_handling.rb +49 -55
  94. data/lib/active_record/core.rb +124 -134
  95. data/lib/active_record/database_configurations/connection_url_resolver.rb +2 -1
  96. data/lib/active_record/database_configurations/database_config.rb +12 -9
  97. data/lib/active_record/database_configurations/hash_config.rb +63 -5
  98. data/lib/active_record/database_configurations/url_config.rb +2 -2
  99. data/lib/active_record/database_configurations.rb +15 -32
  100. data/lib/active_record/delegated_type.rb +53 -12
  101. data/lib/active_record/destroy_association_async_job.rb +1 -1
  102. data/lib/active_record/disable_joins_association_relation.rb +39 -0
  103. data/lib/active_record/dynamic_matchers.rb +1 -1
  104. data/lib/active_record/encryption/cipher/aes256_gcm.rb +98 -0
  105. data/lib/active_record/encryption/cipher.rb +53 -0
  106. data/lib/active_record/encryption/config.rb +44 -0
  107. data/lib/active_record/encryption/configurable.rb +67 -0
  108. data/lib/active_record/encryption/context.rb +35 -0
  109. data/lib/active_record/encryption/contexts.rb +72 -0
  110. data/lib/active_record/encryption/derived_secret_key_provider.rb +12 -0
  111. data/lib/active_record/encryption/deterministic_key_provider.rb +14 -0
  112. data/lib/active_record/encryption/encryptable_record.rb +206 -0
  113. data/lib/active_record/encryption/encrypted_attribute_type.rb +140 -0
  114. data/lib/active_record/encryption/encrypted_fixtures.rb +38 -0
  115. data/lib/active_record/encryption/encrypting_only_encryptor.rb +12 -0
  116. data/lib/active_record/encryption/encryptor.rb +155 -0
  117. data/lib/active_record/encryption/envelope_encryption_key_provider.rb +55 -0
  118. data/lib/active_record/encryption/errors.rb +15 -0
  119. data/lib/active_record/encryption/extended_deterministic_queries.rb +160 -0
  120. data/lib/active_record/encryption/extended_deterministic_uniqueness_validator.rb +28 -0
  121. data/lib/active_record/encryption/key.rb +28 -0
  122. data/lib/active_record/encryption/key_generator.rb +42 -0
  123. data/lib/active_record/encryption/key_provider.rb +46 -0
  124. data/lib/active_record/encryption/message.rb +33 -0
  125. data/lib/active_record/encryption/message_serializer.rb +90 -0
  126. data/lib/active_record/encryption/null_encryptor.rb +21 -0
  127. data/lib/active_record/encryption/properties.rb +76 -0
  128. data/lib/active_record/encryption/read_only_null_encryptor.rb +24 -0
  129. data/lib/active_record/encryption/scheme.rb +99 -0
  130. data/lib/active_record/encryption.rb +55 -0
  131. data/lib/active_record/enum.rb +50 -43
  132. data/lib/active_record/errors.rb +67 -4
  133. data/lib/active_record/explain_registry.rb +11 -6
  134. data/lib/active_record/fixture_set/file.rb +15 -1
  135. data/lib/active_record/fixture_set/table_row.rb +41 -6
  136. data/lib/active_record/fixture_set/table_rows.rb +4 -4
  137. data/lib/active_record/fixtures.rb +20 -23
  138. data/lib/active_record/future_result.rb +139 -0
  139. data/lib/active_record/gem_version.rb +4 -4
  140. data/lib/active_record/inheritance.rb +55 -17
  141. data/lib/active_record/insert_all.rb +80 -14
  142. data/lib/active_record/integration.rb +4 -3
  143. data/lib/active_record/internal_metadata.rb +1 -5
  144. data/lib/active_record/legacy_yaml_adapter.rb +2 -39
  145. data/lib/active_record/locking/optimistic.rb +10 -9
  146. data/lib/active_record/locking/pessimistic.rb +10 -4
  147. data/lib/active_record/log_subscriber.rb +23 -7
  148. data/lib/active_record/middleware/database_selector/resolver.rb +6 -10
  149. data/lib/active_record/middleware/database_selector.rb +18 -6
  150. data/lib/active_record/middleware/shard_selector.rb +60 -0
  151. data/lib/active_record/migration/command_recorder.rb +7 -7
  152. data/lib/active_record/migration/compatibility.rb +84 -2
  153. data/lib/active_record/migration/join_table.rb +1 -1
  154. data/lib/active_record/migration.rb +114 -83
  155. data/lib/active_record/model_schema.rb +58 -59
  156. data/lib/active_record/nested_attributes.rb +13 -12
  157. data/lib/active_record/no_touching.rb +3 -3
  158. data/lib/active_record/null_relation.rb +2 -6
  159. data/lib/active_record/persistence.rb +228 -60
  160. data/lib/active_record/query_cache.rb +2 -2
  161. data/lib/active_record/query_logs.rb +138 -0
  162. data/lib/active_record/querying.rb +16 -6
  163. data/lib/active_record/railtie.rb +136 -22
  164. data/lib/active_record/railties/controller_runtime.rb +1 -1
  165. data/lib/active_record/railties/databases.rake +78 -136
  166. data/lib/active_record/readonly_attributes.rb +11 -0
  167. data/lib/active_record/reflection.rb +73 -50
  168. data/lib/active_record/relation/batches/batch_enumerator.rb +19 -5
  169. data/lib/active_record/relation/batches.rb +6 -6
  170. data/lib/active_record/relation/calculations.rb +43 -38
  171. data/lib/active_record/relation/delegation.rb +7 -7
  172. data/lib/active_record/relation/finder_methods.rb +31 -35
  173. data/lib/active_record/relation/merger.rb +20 -13
  174. data/lib/active_record/relation/predicate_builder.rb +1 -6
  175. data/lib/active_record/relation/query_attribute.rb +5 -11
  176. data/lib/active_record/relation/query_methods.rb +276 -67
  177. data/lib/active_record/relation/record_fetch_warning.rb +7 -9
  178. data/lib/active_record/relation/spawn_methods.rb +2 -2
  179. data/lib/active_record/relation/where_clause.rb +10 -19
  180. data/lib/active_record/relation.rb +189 -88
  181. data/lib/active_record/result.rb +17 -7
  182. data/lib/active_record/runtime_registry.rb +9 -13
  183. data/lib/active_record/sanitization.rb +17 -12
  184. data/lib/active_record/schema.rb +38 -23
  185. data/lib/active_record/schema_dumper.rb +25 -19
  186. data/lib/active_record/schema_migration.rb +4 -4
  187. data/lib/active_record/scoping/default.rb +60 -13
  188. data/lib/active_record/scoping/named.rb +3 -11
  189. data/lib/active_record/scoping.rb +64 -34
  190. data/lib/active_record/serialization.rb +6 -1
  191. data/lib/active_record/signed_id.rb +3 -3
  192. data/lib/active_record/store.rb +7 -2
  193. data/lib/active_record/suppressor.rb +11 -15
  194. data/lib/active_record/tasks/database_tasks.rb +127 -60
  195. data/lib/active_record/tasks/mysql_database_tasks.rb +1 -1
  196. data/lib/active_record/tasks/postgresql_database_tasks.rb +19 -13
  197. data/lib/active_record/test_databases.rb +1 -1
  198. data/lib/active_record/test_fixtures.rb +16 -9
  199. data/lib/active_record/timestamp.rb +3 -4
  200. data/lib/active_record/transactions.rb +9 -14
  201. data/lib/active_record/translation.rb +3 -3
  202. data/lib/active_record/type/adapter_specific_registry.rb +32 -7
  203. data/lib/active_record/type/hash_lookup_type_map.rb +34 -1
  204. data/lib/active_record/type/internal/timezone.rb +2 -2
  205. data/lib/active_record/type/serialized.rb +1 -1
  206. data/lib/active_record/type/type_map.rb +17 -20
  207. data/lib/active_record/type.rb +1 -2
  208. data/lib/active_record/validations/associated.rb +4 -4
  209. data/lib/active_record/validations/presence.rb +2 -2
  210. data/lib/active_record/validations/uniqueness.rb +4 -4
  211. data/lib/active_record/version.rb +1 -1
  212. data/lib/active_record.rb +217 -27
  213. data/lib/arel/attributes/attribute.rb +0 -8
  214. data/lib/arel/crud.rb +28 -22
  215. data/lib/arel/delete_manager.rb +18 -4
  216. data/lib/arel/filter_predications.rb +9 -0
  217. data/lib/arel/insert_manager.rb +2 -3
  218. data/lib/arel/nodes/casted.rb +1 -1
  219. data/lib/arel/nodes/delete_statement.rb +12 -13
  220. data/lib/arel/nodes/filter.rb +10 -0
  221. data/lib/arel/nodes/function.rb +1 -0
  222. data/lib/arel/nodes/insert_statement.rb +2 -2
  223. data/lib/arel/nodes/select_core.rb +2 -2
  224. data/lib/arel/nodes/select_statement.rb +2 -2
  225. data/lib/arel/nodes/update_statement.rb +8 -3
  226. data/lib/arel/nodes.rb +1 -0
  227. data/lib/arel/predications.rb +11 -3
  228. data/lib/arel/select_manager.rb +10 -4
  229. data/lib/arel/table.rb +0 -1
  230. data/lib/arel/tree_manager.rb +0 -12
  231. data/lib/arel/update_manager.rb +18 -4
  232. data/lib/arel/visitors/dot.rb +80 -90
  233. data/lib/arel/visitors/mysql.rb +8 -2
  234. data/lib/arel/visitors/postgresql.rb +0 -10
  235. data/lib/arel/visitors/to_sql.rb +58 -2
  236. data/lib/arel.rb +2 -1
  237. data/lib/rails/generators/active_record/application_record/templates/application_record.rb.tt +1 -1
  238. data/lib/rails/generators/active_record/model/templates/abstract_base_class.rb.tt +1 -1
  239. data/lib/rails/generators/active_record/model/templates/model.rb.tt +1 -1
  240. data/lib/rails/generators/active_record/model/templates/module.rb.tt +2 -2
  241. data/lib/rails/generators/active_record/multi_db/multi_db_generator.rb +16 -0
  242. data/lib/rails/generators/active_record/multi_db/templates/multi_db.rb.tt +44 -0
  243. metadata +55 -11
@@ -30,32 +30,28 @@ module ActiveRecord
30
30
  module Suppressor
31
31
  extend ActiveSupport::Concern
32
32
 
33
+ class << self
34
+ def registry # :nodoc:
35
+ ActiveSupport::IsolatedExecutionState[:active_record_suppresor_registry] ||= {}
36
+ end
37
+ end
38
+
33
39
  module ClassMethods
34
40
  def suppress(&block)
35
- previous_state = SuppressorRegistry.suppressed[name]
36
- SuppressorRegistry.suppressed[name] = true
41
+ previous_state = Suppressor.registry[name]
42
+ Suppressor.registry[name] = true
37
43
  yield
38
44
  ensure
39
- SuppressorRegistry.suppressed[name] = previous_state
45
+ Suppressor.registry[name] = previous_state
40
46
  end
41
47
  end
42
48
 
43
49
  def save(**) # :nodoc:
44
- SuppressorRegistry.suppressed[self.class.name] ? true : super
50
+ Suppressor.registry[self.class.name] ? true : super
45
51
  end
46
52
 
47
53
  def save!(**) # :nodoc:
48
- SuppressorRegistry.suppressed[self.class.name] ? true : super
49
- end
50
- end
51
-
52
- class SuppressorRegistry # :nodoc:
53
- extend ActiveSupport::PerThreadRegistry
54
-
55
- attr_reader :suppressed
56
-
57
- def initialize
58
- @suppressed = {}
54
+ Suppressor.registry[self.class.name] ? true : super
59
55
  end
60
56
  end
61
57
  end
@@ -39,17 +39,23 @@ module ActiveRecord
39
39
  ##
40
40
  # :singleton-method:
41
41
  # Extra flags passed to database CLI tool (mysqldump/pg_dump) when calling db:schema:dump
42
+ # It can be used as a string/array (the typical case) or a hash (when you use multiple adapters)
43
+ # Example:
44
+ # ActiveRecord::Tasks::DatabaseTasks.structure_dump_flags = {
45
+ # mysql2: ['--no-defaults', '--skip-add-drop-table'],
46
+ # postgres: '--no-tablespaces'
47
+ # }
42
48
  mattr_accessor :structure_dump_flags, instance_accessor: false
43
49
 
44
50
  ##
45
51
  # :singleton-method:
46
52
  # Extra flags passed to database CLI tool when calling db:schema:load
53
+ # It can be used as a string/array (the typical case) or a hash (when you use multiple adapters)
47
54
  mattr_accessor :structure_load_flags, instance_accessor: false
48
55
 
49
56
  extend self
50
57
 
51
- attr_writer :current_config, :db_dir, :migrations_paths, :fixtures_path, :root, :env, :seed_loader
52
- deprecate :current_config=
58
+ attr_writer :db_dir, :migrations_paths, :fixtures_path, :root, :env, :seed_loader
53
59
  attr_accessor :database_configuration
54
60
 
55
61
  LOCAL_HOSTS = ["127.0.0.1", "localhost"]
@@ -103,11 +109,6 @@ module ActiveRecord
103
109
  @env ||= Rails.env
104
110
  end
105
111
 
106
- def spec
107
- @spec ||= "primary"
108
- end
109
- deprecate spec: "please use name instead"
110
-
111
112
  def name
112
113
  @name ||= "primary"
113
114
  end
@@ -116,18 +117,6 @@ module ActiveRecord
116
117
  @seed_loader ||= Rails.application
117
118
  end
118
119
 
119
- def current_config(options = {})
120
- if options.has_key?(:config)
121
- @current_config = options[:config]
122
- else
123
- env_name = options[:env] || env
124
- name = options[:spec] || "primary"
125
-
126
- @current_config ||= ActiveRecord::Base.configurations.configs_for(env_name: env_name, name: name)&.configuration_hash
127
- end
128
- end
129
- deprecate :current_config
130
-
131
120
  def create(configuration, *arguments)
132
121
  db_config = resolve_configuration(configuration)
133
122
  database_adapter_for(db_config, *arguments).create
@@ -154,7 +143,7 @@ module ActiveRecord
154
143
  begin
155
144
  Rails.application.config.load_database_yaml
156
145
  rescue
157
- unless ActiveRecord::Base.suppress_multiple_database_warning
146
+ unless ActiveRecord.suppress_multiple_database_warning
158
147
  $stderr.puts "Rails couldn't infer whether you are using multiple databases from your database.yml and can't generate the tasks for the non-primary databases. If you'd like to use this feature, please simplify your ERB."
159
148
  end
160
149
 
@@ -171,12 +160,14 @@ module ActiveRecord
171
160
  return if database_configs.count == 1
172
161
 
173
162
  database_configs.each do |db_config|
163
+ next unless db_config.database_tasks?
164
+
174
165
  yield db_config.name
175
166
  end
176
167
  end
177
168
 
178
169
  def raise_for_multi_db(environment = env, command:)
179
- db_configs = ActiveRecord::Base.configurations.configs_for(env_name: environment)
170
+ db_configs = configs_for(env_name: environment)
180
171
 
181
172
  if db_configs.count > 1
182
173
  dbs_list = []
@@ -194,6 +185,40 @@ module ActiveRecord
194
185
  ActiveRecord::Base.establish_connection(environment.to_sym)
195
186
  end
196
187
 
188
+ def prepare_all
189
+ seed = false
190
+
191
+ each_current_configuration(env) do |db_config|
192
+ ActiveRecord::Base.establish_connection(db_config)
193
+
194
+ begin
195
+ # Skipped when no database
196
+ migrate
197
+
198
+ if ActiveRecord.dump_schema_after_migration
199
+ dump_schema(db_config, ActiveRecord.schema_format)
200
+ end
201
+ rescue ActiveRecord::NoDatabaseError
202
+ create(db_config)
203
+
204
+ if File.exist?(schema_dump_path(db_config))
205
+ load_schema(
206
+ db_config,
207
+ ActiveRecord.schema_format,
208
+ nil
209
+ )
210
+ else
211
+ migrate
212
+ end
213
+
214
+ seed = true
215
+ end
216
+ end
217
+
218
+ ActiveRecord::Base.establish_connection
219
+ load_seed if seed
220
+ end
221
+
197
222
  def drop(configuration, *arguments)
198
223
  db_config = resolve_configuration(configuration)
199
224
  database_adapter_for(db_config, *arguments).drop
@@ -223,19 +248,25 @@ module ActiveRecord
223
248
  private :truncate_tables
224
249
 
225
250
  def truncate_all(environment = env)
226
- ActiveRecord::Base.configurations.configs_for(env_name: environment).each do |db_config|
251
+ configs_for(env_name: environment).each do |db_config|
227
252
  truncate_tables(db_config)
228
253
  end
229
254
  end
230
255
 
231
- def migrate
256
+ def migrate(version = nil)
232
257
  check_target_version
233
258
 
234
259
  scope = ENV["SCOPE"]
235
260
  verbose_was, Migration.verbose = Migration.verbose, verbose?
236
261
 
237
262
  Base.connection.migration_context.migrate(target_version) do |migration|
238
- scope.blank? || scope == migration.scope
263
+ if version.blank?
264
+ scope.blank? || scope == migration.scope
265
+ else
266
+ migration.version == version
267
+ end
268
+ end.tap do |migrations_ran|
269
+ Migration.write("No migrations ran. (using #{scope} scope)") if scope.present? && migrations_ran.empty?
239
270
  end
240
271
 
241
272
  ActiveRecord::Base.clear_cache!
@@ -243,6 +274,23 @@ module ActiveRecord
243
274
  Migration.verbose = verbose_was
244
275
  end
245
276
 
277
+ def db_configs_with_versions(db_configs) # :nodoc:
278
+ db_configs_with_versions = Hash.new { |h, k| h[k] = [] }
279
+
280
+ db_configs.each do |db_config|
281
+ ActiveRecord::Base.establish_connection(db_config)
282
+ versions_to_run = ActiveRecord::Base.connection.migration_context.pending_migration_versions
283
+ target_version = ActiveRecord::Tasks::DatabaseTasks.target_version
284
+
285
+ versions_to_run.each do |version|
286
+ next if target_version && target_version != version
287
+ db_configs_with_versions[version] << db_config
288
+ end
289
+ end
290
+
291
+ db_configs_with_versions
292
+ end
293
+
246
294
  def migrate_status
247
295
  unless ActiveRecord::Base.connection.schema_migration.table_exists?
248
296
  Kernel.abort "Schema migrations table does not exist yet."
@@ -269,7 +317,7 @@ module ActiveRecord
269
317
  end
270
318
 
271
319
  def charset_current(env_name = env, db_name = name)
272
- db_config = ActiveRecord::Base.configurations.configs_for(env_name: env_name, name: db_name)
320
+ db_config = configs_for(env_name: env_name, name: db_name)
273
321
  charset(db_config)
274
322
  end
275
323
 
@@ -279,7 +327,7 @@ module ActiveRecord
279
327
  end
280
328
 
281
329
  def collation_current(env_name = env, db_name = name)
282
- db_config = ActiveRecord::Base.configurations.configs_for(env_name: env_name, name: db_name)
330
+ db_config = configs_for(env_name: env_name, name: db_name)
283
331
  collation(db_config)
284
332
  end
285
333
 
@@ -305,17 +353,20 @@ module ActiveRecord
305
353
  def structure_dump(configuration, *arguments)
306
354
  db_config = resolve_configuration(configuration)
307
355
  filename = arguments.delete_at(0)
308
- database_adapter_for(db_config, *arguments).structure_dump(filename, structure_dump_flags)
356
+ flags = structure_dump_flags_for(db_config.adapter)
357
+ database_adapter_for(db_config, *arguments).structure_dump(filename, flags)
309
358
  end
310
359
 
311
360
  def structure_load(configuration, *arguments)
312
361
  db_config = resolve_configuration(configuration)
313
362
  filename = arguments.delete_at(0)
314
- database_adapter_for(db_config, *arguments).structure_load(filename, structure_load_flags)
363
+ flags = structure_load_flags_for(db_config.adapter)
364
+ database_adapter_for(db_config, *arguments).structure_load(filename, flags)
315
365
  end
316
366
 
317
- def load_schema(db_config, format = ActiveRecord::Base.schema_format, file = nil) # :nodoc:
318
- file ||= dump_filename(db_config.name, format)
367
+ def load_schema(db_config, format = ActiveRecord.schema_format, file = nil) # :nodoc:
368
+ file ||= schema_dump_path(db_config, format)
369
+ return unless file
319
370
 
320
371
  verbose_was, Migration.verbose = Migration.verbose, verbose? && ENV["VERBOSE"]
321
372
  check_schema_file(file)
@@ -336,18 +387,12 @@ module ActiveRecord
336
387
  Migration.verbose = verbose_was
337
388
  end
338
389
 
339
- def schema_up_to_date?(configuration, format = ActiveRecord::Base.schema_format, file = nil, environment = nil, name = nil)
390
+ def schema_up_to_date?(configuration, format = ActiveRecord.schema_format, file = nil)
340
391
  db_config = resolve_configuration(configuration)
341
392
 
342
- if environment || name
343
- ActiveSupport::Deprecation.warn("`environment` and `name` will be removed as parameters in 7.0.0, you may now pass an ActiveRecord::DatabaseConfigurations::DatabaseConfig as `configuration` instead.")
344
- end
345
-
346
- name ||= db_config.name
393
+ file ||= schema_dump_path(db_config)
347
394
 
348
- file ||= dump_filename(name, format)
349
-
350
- return true unless File.exist?(file)
395
+ return true unless file && File.exist?(file)
351
396
 
352
397
  ActiveRecord::Base.establish_connection(db_config)
353
398
 
@@ -357,10 +402,10 @@ module ActiveRecord
357
402
  ActiveRecord::InternalMetadata[:schema_sha1] == schema_sha1(file)
358
403
  end
359
404
 
360
- def reconstruct_from_schema(db_config, format = ActiveRecord::Base.schema_format, file = nil) # :nodoc:
361
- file ||= dump_filename(db_config.name, format)
405
+ def reconstruct_from_schema(db_config, format = ActiveRecord.schema_format, file = nil) # :nodoc:
406
+ file ||= schema_dump_path(db_config, format)
362
407
 
363
- check_schema_file(file)
408
+ check_schema_file(file) if file
364
409
 
365
410
  ActiveRecord::Base.establish_connection(db_config)
366
411
 
@@ -375,9 +420,11 @@ module ActiveRecord
375
420
  load_schema(db_config, format, file)
376
421
  end
377
422
 
378
- def dump_schema(db_config, format = ActiveRecord::Base.schema_format) # :nodoc:
423
+ def dump_schema(db_config, format = ActiveRecord.schema_format) # :nodoc:
379
424
  require "active_record/schema_dumper"
380
- filename = dump_filename(db_config.name, format)
425
+ filename = schema_dump_path(db_config, format)
426
+ return unless filename
427
+
381
428
  connection = ActiveRecord::Base.connection
382
429
 
383
430
  FileUtils.mkdir_p(db_dir)
@@ -397,11 +444,7 @@ module ActiveRecord
397
444
  end
398
445
  end
399
446
 
400
- def schema_file(format = ActiveRecord::Base.schema_format)
401
- File.join(db_dir, schema_file_type(format))
402
- end
403
-
404
- def schema_file_type(format = ActiveRecord::Base.schema_format)
447
+ def schema_file_type(format = ActiveRecord.schema_format)
405
448
  case format
406
449
  when :ruby
407
450
  "schema.rb"
@@ -409,15 +452,19 @@ module ActiveRecord
409
452
  "structure.sql"
410
453
  end
411
454
  end
455
+ deprecate :schema_file_type
412
456
 
413
- def dump_filename(db_config_name, format = ActiveRecord::Base.schema_format)
414
- filename = if ActiveRecord::Base.configurations.primary?(db_config_name)
415
- schema_file_type(format)
457
+ def schema_dump_path(db_config, format = ActiveRecord.schema_format)
458
+ return ENV["SCHEMA"] if ENV["SCHEMA"]
459
+
460
+ filename = db_config.schema_dump(format)
461
+ return unless filename
462
+
463
+ if File.dirname(filename) == ActiveRecord::Tasks::DatabaseTasks.db_dir
464
+ filename
416
465
  else
417
- "#{db_config_name}_#{schema_file_type(format)}"
466
+ File.join(ActiveRecord::Tasks::DatabaseTasks.db_dir, filename)
418
467
  end
419
-
420
- ENV["SCHEMA"] || File.join(ActiveRecord::Tasks::DatabaseTasks.db_dir, filename)
421
468
  end
422
469
 
423
470
  def cache_dump_filename(db_config_name, schema_cache_path: nil)
@@ -430,7 +477,7 @@ module ActiveRecord
430
477
  schema_cache_path || ENV["SCHEMA_CACHE"] || File.join(ActiveRecord::Tasks::DatabaseTasks.db_dir, filename)
431
478
  end
432
479
 
433
- def load_schema_current(format = ActiveRecord::Base.schema_format, file = nil, environment = env)
480
+ def load_schema_current(format = ActiveRecord.schema_format, file = nil, environment = env)
434
481
  each_current_configuration(environment) do |db_config|
435
482
  load_schema(db_config, format, file)
436
483
  end
@@ -468,6 +515,10 @@ module ActiveRecord
468
515
  end
469
516
 
470
517
  private
518
+ def configs_for(**options)
519
+ Base.configurations.configs_for(**options)
520
+ end
521
+
471
522
  def resolve_configuration(configuration)
472
523
  Base.configurations.resolve(configuration)
473
524
  end
@@ -488,7 +539,7 @@ module ActiveRecord
488
539
  end
489
540
 
490
541
  def class_for_adapter(adapter)
491
- _key, task = @tasks.each_pair.detect { |pattern, _task| adapter[pattern] }
542
+ _key, task = @tasks.reverse_each.detect { |pattern, _task| adapter[pattern] }
492
543
  unless task
493
544
  raise DatabaseNotSupported, "Rake tasks not supported by '#{adapter}' adapter"
494
545
  end
@@ -500,7 +551,7 @@ module ActiveRecord
500
551
  environments << "test" if environment == "development" && !ENV["SKIP_TEST_DATABASE"] && !ENV["DATABASE_URL"]
501
552
 
502
553
  environments.each do |env|
503
- ActiveRecord::Base.configurations.configs_for(env_name: env).each do |db_config|
554
+ configs_for(env_name: env).each do |db_config|
504
555
  next if name && name != db_config.name
505
556
 
506
557
  yield db_config
@@ -509,7 +560,7 @@ module ActiveRecord
509
560
  end
510
561
 
511
562
  def each_local_configuration
512
- ActiveRecord::Base.configurations.configs_for.each do |db_config|
563
+ configs_for.each do |db_config|
513
564
  next unless db_config.database
514
565
 
515
566
  if local_database?(db_config)
@@ -526,7 +577,23 @@ module ActiveRecord
526
577
  end
527
578
 
528
579
  def schema_sha1(file)
529
- Digest::SHA1.hexdigest(File.read(file))
580
+ OpenSSL::Digest::SHA1.hexdigest(File.read(file))
581
+ end
582
+
583
+ def structure_dump_flags_for(adapter)
584
+ if structure_dump_flags.is_a?(Hash)
585
+ structure_dump_flags[adapter.to_sym]
586
+ else
587
+ structure_dump_flags
588
+ end
589
+ end
590
+
591
+ def structure_load_flags_for(adapter)
592
+ if structure_load_flags.is_a?(Hash)
593
+ structure_load_flags[adapter.to_sym]
594
+ else
595
+ structure_load_flags
596
+ end
530
597
  end
531
598
  end
532
599
  end
@@ -94,7 +94,7 @@ module ActiveRecord
94
94
  sslcapath: "--ssl-capath",
95
95
  sslcipher: "--ssl-cipher",
96
96
  sslkey: "--ssl-key"
97
- }.map { |opt, arg| "#{arg}=#{configuration_hash[opt]}" if configuration_hash[opt] }.compact
97
+ }.filter_map { |opt, arg| "#{arg}=#{configuration_hash[opt]}" if configuration_hash[opt] }
98
98
 
99
99
  args
100
100
  end
@@ -47,20 +47,21 @@ module ActiveRecord
47
47
  end
48
48
 
49
49
  def structure_dump(filename, extra_flags)
50
- set_psql_env
51
-
52
50
  search_path = \
53
- case ActiveRecord::Base.dump_schemas
51
+ case ActiveRecord.dump_schemas
54
52
  when :schema_search_path
55
53
  configuration_hash[:schema_search_path]
56
54
  when :all
57
55
  nil
58
56
  when String
59
- ActiveRecord::Base.dump_schemas
57
+ ActiveRecord.dump_schemas
60
58
  end
61
59
 
62
- args = ["--schema-only", "--no-privileges", "--no-owner", "--file", filename]
60
+ args = ["--schema-only", "--no-privileges", "--no-owner"]
61
+ args.concat(["--file", filename])
62
+
63
63
  args.concat(Array(extra_flags)) if extra_flags
64
+
64
65
  unless search_path.blank?
65
66
  args += search_path.split(",").map do |part|
66
67
  "--schema=#{part.strip}"
@@ -79,8 +80,7 @@ module ActiveRecord
79
80
  end
80
81
 
81
82
  def structure_load(filename, extra_flags)
82
- set_psql_env
83
- args = ["--set", ON_ERROR_STOP_1, "--quiet", "--no-psqlrc", "--file", filename]
83
+ args = ["--set", ON_ERROR_STOP_1, "--quiet", "--no-psqlrc", "--output", File::NULL, "--file", filename]
84
84
  args.concat(Array(extra_flags)) if extra_flags
85
85
  args << db_config.database
86
86
  run_cmd("psql", args, "loading")
@@ -100,15 +100,21 @@ module ActiveRecord
100
100
  )
101
101
  end
102
102
 
103
- def set_psql_env
104
- ENV["PGHOST"] = db_config.host if db_config.host
105
- ENV["PGPORT"] = configuration_hash[:port].to_s if configuration_hash[:port]
106
- ENV["PGPASSWORD"] = configuration_hash[:password].to_s if configuration_hash[:password]
107
- ENV["PGUSER"] = configuration_hash[:username].to_s if configuration_hash[:username]
103
+ def psql_env
104
+ {}.tap do |env|
105
+ env["PGHOST"] = db_config.host if db_config.host
106
+ env["PGPORT"] = configuration_hash[:port].to_s if configuration_hash[:port]
107
+ env["PGPASSWORD"] = configuration_hash[:password].to_s if configuration_hash[:password]
108
+ env["PGUSER"] = configuration_hash[:username].to_s if configuration_hash[:username]
109
+ env["PGSSLMODE"] = configuration_hash[:sslmode].to_s if configuration_hash[:sslmode]
110
+ env["PGSSLCERT"] = configuration_hash[:sslcert].to_s if configuration_hash[:sslcert]
111
+ env["PGSSLKEY"] = configuration_hash[:sslkey].to_s if configuration_hash[:sslkey]
112
+ env["PGSSLROOTCERT"] = configuration_hash[:sslrootcert].to_s if configuration_hash[:sslrootcert]
113
+ end
108
114
  end
109
115
 
110
116
  def run_cmd(cmd, args, action)
111
- fail run_cmd_error(cmd, args, action) unless Kernel.system(cmd, *args)
117
+ fail run_cmd_error(cmd, args, action) unless Kernel.system(psql_env, cmd, *args)
112
118
  end
113
119
 
114
120
  def run_cmd_error(cmd, args, action)
@@ -14,7 +14,7 @@ module ActiveRecord
14
14
  ActiveRecord::Base.configurations.configs_for(env_name: env_name).each do |db_config|
15
15
  db_config._database = "#{db_config.database}-#{i}"
16
16
 
17
- ActiveRecord::Tasks::DatabaseTasks.reconstruct_from_schema(db_config, ActiveRecord::Base.schema_format, nil)
17
+ ActiveRecord::Tasks::DatabaseTasks.reconstruct_from_schema(db_config, ActiveRecord.schema_format, nil)
18
18
  end
19
19
  ensure
20
20
  ActiveRecord::Base.establish_connection
@@ -86,6 +86,9 @@ module ActiveRecord
86
86
  include methods
87
87
  end
88
88
 
89
+ # Prevents automatically wrapping each specified test in a transaction,
90
+ # to allow application logic transactions to be tested in a top-level
91
+ # (non-nested) context.
89
92
  def uses_transaction(*methods)
90
93
  @uses_transaction = [] unless defined?(@uses_transaction)
91
94
  @uses_transaction.concat methods.map(&:to_s)
@@ -134,7 +137,7 @@ module ActiveRecord
134
137
  @connection_subscriber = ActiveSupport::Notifications.subscribe("!connection.active_record") do |_, _, _, _, payload|
135
138
  spec_name = payload[:spec_name] if payload.key?(:spec_name)
136
139
  shard = payload[:shard] if payload.key?(:shard)
137
- setup_shared_connection_pool
140
+ setup_shared_connection_pool if ActiveRecord.legacy_connection_handling
138
141
 
139
142
  if spec_name
140
143
  begin
@@ -143,10 +146,14 @@ module ActiveRecord
143
146
  connection = nil
144
147
  end
145
148
 
146
- if connection && !@fixture_connections.include?(connection)
147
- connection.begin_transaction joinable: false, _lazy: false
148
- connection.pool.lock_thread = true if lock_threads
149
- @fixture_connections << connection
149
+ if connection
150
+ setup_shared_connection_pool unless ActiveRecord.legacy_connection_handling
151
+
152
+ if !@fixture_connections.include?(connection)
153
+ connection.begin_transaction joinable: false, _lazy: false
154
+ connection.pool.lock_thread = true if lock_threads
155
+ @fixture_connections << connection
156
+ end
150
157
  end
151
158
  end
152
159
  end
@@ -193,8 +200,8 @@ module ActiveRecord
193
200
  # need to share a connection pool so that the reading connection
194
201
  # can see data in the open transaction on the writing connection.
195
202
  def setup_shared_connection_pool
196
- if ActiveRecord::Base.legacy_connection_handling
197
- writing_handler = ActiveRecord::Base.connection_handlers[ActiveRecord::Base.writing_role]
203
+ if ActiveRecord.legacy_connection_handling
204
+ writing_handler = ActiveRecord::Base.connection_handlers[ActiveRecord.writing_role]
198
205
 
199
206
  ActiveRecord::Base.connection_handlers.values.each do |handler|
200
207
  if handler != writing_handler
@@ -221,7 +228,7 @@ module ActiveRecord
221
228
  handler.connection_pool_names.each do |name|
222
229
  pool_manager = handler.send(:owner_to_pool_manager)[name]
223
230
  pool_manager.shard_names.each do |shard_name|
224
- writing_pool_config = pool_manager.get_pool_config(ActiveRecord::Base.writing_role, shard_name)
231
+ writing_pool_config = pool_manager.get_pool_config(ActiveRecord.writing_role, shard_name)
225
232
  @saved_pool_configs[name][shard_name] ||= {}
226
233
  pool_manager.role_names.each do |role|
227
234
  next unless pool_config = pool_manager.get_pool_config(role, shard_name)
@@ -236,7 +243,7 @@ module ActiveRecord
236
243
  end
237
244
 
238
245
  def teardown_shared_connection_pool
239
- if ActiveRecord::Base.legacy_connection_handling
246
+ if ActiveRecord.legacy_connection_handling
240
247
  @legacy_saved_pool_configs.each_pair do |handler, names|
241
248
  names.each_pair do |name, shards|
242
249
  shards.each_pair do |shard_name, pool_config|
@@ -75,7 +75,7 @@ module ActiveRecord
75
75
  end
76
76
 
77
77
  def current_time_from_proper_timezone
78
- default_timezone == :utc ? Time.now.utc : Time.now
78
+ ActiveRecord.default_timezone == :utc ? Time.now.utc : Time.now
79
79
  end
80
80
 
81
81
  private
@@ -127,7 +127,7 @@ module ActiveRecord
127
127
  end
128
128
 
129
129
  def should_record_timestamps?
130
- record_timestamps && (!partial_writes? || has_changes_to_save?)
130
+ record_timestamps && (!partial_updates? || has_changes_to_save?)
131
131
  end
132
132
 
133
133
  def timestamp_attributes_for_create_in_model
@@ -148,8 +148,7 @@ module ActiveRecord
148
148
 
149
149
  def max_updated_column_timestamp
150
150
  timestamp_attributes_for_update_in_model
151
- .map { |attr| self[attr]&.to_time }
152
- .compact
151
+ .filter_map { |attr| self[attr]&.to_time }
153
152
  .max
154
153
  end
155
154
 
@@ -4,7 +4,7 @@ module ActiveRecord
4
4
  # See ActiveRecord::Transactions::ClassMethods for documentation.
5
5
  module Transactions
6
6
  extend ActiveSupport::Concern
7
- #:nodoc:
7
+ # :nodoc:
8
8
  ACTIONS = [:create, :destroy, :update]
9
9
 
10
10
  included do
@@ -290,19 +290,19 @@ module ActiveRecord
290
290
  self.class.transaction(**options, &block)
291
291
  end
292
292
 
293
- def destroy #:nodoc:
293
+ def destroy # :nodoc:
294
294
  with_transaction_returning_status { super }
295
295
  end
296
296
 
297
- def save(**) #:nodoc:
297
+ def save(**) # :nodoc:
298
298
  with_transaction_returning_status { super }
299
299
  end
300
300
 
301
- def save!(**) #:nodoc:
301
+ def save!(**) # :nodoc:
302
302
  with_transaction_returning_status { super }
303
303
  end
304
304
 
305
- def touch(*, **) #:nodoc:
305
+ def touch(*, **) # :nodoc:
306
306
  with_transaction_returning_status { super }
307
307
  end
308
308
 
@@ -314,8 +314,8 @@ module ActiveRecord
314
314
  #
315
315
  # Ensure that it is not called if the object was never persisted (failed create),
316
316
  # but call it after the commit of a destroyed object.
317
- def committed!(should_run_callbacks: true) #:nodoc:
318
- force_clear_transaction_record_state
317
+ def committed!(should_run_callbacks: true) # :nodoc:
318
+ @_start_transaction_state = nil
319
319
  if should_run_callbacks
320
320
  @_committed_already_called = true
321
321
  _run_commit_callbacks
@@ -326,7 +326,7 @@ module ActiveRecord
326
326
 
327
327
  # Call the #after_rollback callbacks. The +force_restore_state+ argument indicates if the record
328
328
  # state should be rolled back to the beginning or just to the last savepoint.
329
- def rolledback!(force_restore_state: false, should_run_callbacks: true) #:nodoc:
329
+ def rolledback!(force_restore_state: false, should_run_callbacks: true) # :nodoc:
330
330
  if should_run_callbacks
331
331
  _run_rollback_callbacks
332
332
  end
@@ -389,12 +389,7 @@ module ActiveRecord
389
389
  def clear_transaction_record_state
390
390
  return unless @_start_transaction_state
391
391
  @_start_transaction_state[:level] -= 1
392
- force_clear_transaction_record_state if @_start_transaction_state[:level] < 1
393
- end
394
-
395
- # Force to clear the transaction record state.
396
- def force_clear_transaction_record_state
397
- @_start_transaction_state = nil
392
+ @_start_transaction_state = nil if @_start_transaction_state[:level] < 1
398
393
  end
399
394
 
400
395
  # Restore the new record state and id of a record that was previously saved by a call to save_record_state.
@@ -5,7 +5,7 @@ module ActiveRecord
5
5
  include ActiveModel::Translation
6
6
 
7
7
  # Set the lookup ancestors for ActiveModel.
8
- def lookup_ancestors #:nodoc:
8
+ def lookup_ancestors # :nodoc:
9
9
  klass = self
10
10
  classes = [klass]
11
11
  return classes if klass == ActiveRecord::Base
@@ -16,8 +16,8 @@ module ActiveRecord
16
16
  classes
17
17
  end
18
18
 
19
- # Set the i18n scope to overwrite ActiveModel.
20
- def i18n_scope #:nodoc:
19
+ # Set the i18n scope to override ActiveModel.
20
+ def i18n_scope # :nodoc:
21
21
  :activerecord
22
22
  end
23
23
  end