activerecord 6.1.6 → 7.1.2

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 (309) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +1627 -983
  3. data/MIT-LICENSE +1 -1
  4. data/README.rdoc +18 -18
  5. data/lib/active_record/aggregations.rb +17 -14
  6. data/lib/active_record/association_relation.rb +1 -11
  7. data/lib/active_record/associations/association.rb +50 -19
  8. data/lib/active_record/associations/association_scope.rb +17 -12
  9. data/lib/active_record/associations/belongs_to_association.rb +28 -9
  10. data/lib/active_record/associations/belongs_to_polymorphic_association.rb +10 -2
  11. data/lib/active_record/associations/builder/association.rb +11 -5
  12. data/lib/active_record/associations/builder/belongs_to.rb +40 -14
  13. data/lib/active_record/associations/builder/collection_association.rb +10 -3
  14. data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +1 -5
  15. data/lib/active_record/associations/builder/has_many.rb +3 -2
  16. data/lib/active_record/associations/builder/has_one.rb +2 -1
  17. data/lib/active_record/associations/builder/singular_association.rb +6 -2
  18. data/lib/active_record/associations/collection_association.rb +35 -31
  19. data/lib/active_record/associations/collection_proxy.rb +30 -15
  20. data/lib/active_record/associations/disable_joins_association_scope.rb +59 -0
  21. data/lib/active_record/associations/foreign_association.rb +10 -3
  22. data/lib/active_record/associations/has_many_association.rb +28 -18
  23. data/lib/active_record/associations/has_many_through_association.rb +12 -7
  24. data/lib/active_record/associations/has_one_association.rb +20 -10
  25. data/lib/active_record/associations/has_one_through_association.rb +1 -1
  26. data/lib/active_record/associations/join_dependency.rb +26 -16
  27. data/lib/active_record/associations/preloader/association.rb +207 -52
  28. data/lib/active_record/associations/preloader/batch.rb +48 -0
  29. data/lib/active_record/associations/preloader/branch.rb +147 -0
  30. data/lib/active_record/associations/preloader/through_association.rb +50 -14
  31. data/lib/active_record/associations/preloader.rb +50 -121
  32. data/lib/active_record/associations/singular_association.rb +9 -3
  33. data/lib/active_record/associations/through_association.rb +25 -14
  34. data/lib/active_record/associations.rb +439 -305
  35. data/lib/active_record/asynchronous_queries_tracker.rb +60 -0
  36. data/lib/active_record/attribute_assignment.rb +1 -3
  37. data/lib/active_record/attribute_methods/before_type_cast.rb +24 -2
  38. data/lib/active_record/attribute_methods/dirty.rb +73 -22
  39. data/lib/active_record/attribute_methods/primary_key.rb +78 -26
  40. data/lib/active_record/attribute_methods/query.rb +31 -19
  41. data/lib/active_record/attribute_methods/read.rb +25 -10
  42. data/lib/active_record/attribute_methods/serialization.rb +194 -37
  43. data/lib/active_record/attribute_methods/time_zone_conversion.rb +4 -3
  44. data/lib/active_record/attribute_methods/write.rb +10 -13
  45. data/lib/active_record/attribute_methods.rb +121 -40
  46. data/lib/active_record/attributes.rb +27 -38
  47. data/lib/active_record/autosave_association.rb +61 -30
  48. data/lib/active_record/base.rb +25 -2
  49. data/lib/active_record/callbacks.rb +18 -34
  50. data/lib/active_record/coders/column_serializer.rb +61 -0
  51. data/lib/active_record/coders/json.rb +1 -1
  52. data/lib/active_record/coders/yaml_column.rb +70 -34
  53. data/lib/active_record/connection_adapters/abstract/connection_handler.rb +367 -0
  54. data/lib/active_record/connection_adapters/abstract/connection_pool/queue.rb +211 -0
  55. data/lib/active_record/connection_adapters/abstract/connection_pool/reaper.rb +78 -0
  56. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +96 -590
  57. data/lib/active_record/connection_adapters/abstract/database_limits.rb +5 -17
  58. data/lib/active_record/connection_adapters/abstract/database_statements.rb +172 -50
  59. data/lib/active_record/connection_adapters/abstract/query_cache.rb +77 -27
  60. data/lib/active_record/connection_adapters/abstract/quoting.rb +87 -73
  61. data/lib/active_record/connection_adapters/abstract/savepoints.rb +4 -3
  62. data/lib/active_record/connection_adapters/abstract/schema_creation.rb +21 -20
  63. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +186 -31
  64. data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +14 -1
  65. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +360 -138
  66. data/lib/active_record/connection_adapters/abstract/transaction.rb +281 -59
  67. data/lib/active_record/connection_adapters/abstract_adapter.rb +631 -149
  68. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +285 -156
  69. data/lib/active_record/connection_adapters/column.rb +13 -0
  70. data/lib/active_record/connection_adapters/mysql/column.rb +1 -0
  71. data/lib/active_record/connection_adapters/mysql/database_statements.rb +25 -134
  72. data/lib/active_record/connection_adapters/mysql/quoting.rb +56 -25
  73. data/lib/active_record/connection_adapters/mysql/schema_creation.rb +9 -0
  74. data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +10 -1
  75. data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +8 -2
  76. data/lib/active_record/connection_adapters/mysql/schema_statements.rb +38 -14
  77. data/lib/active_record/connection_adapters/mysql2/database_statements.rb +151 -0
  78. data/lib/active_record/connection_adapters/mysql2_adapter.rb +104 -53
  79. data/lib/active_record/connection_adapters/pool_config.rb +20 -11
  80. data/lib/active_record/connection_adapters/pool_manager.rb +19 -9
  81. data/lib/active_record/connection_adapters/postgresql/column.rb +30 -1
  82. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +89 -52
  83. data/lib/active_record/connection_adapters/postgresql/oid/array.rb +1 -1
  84. data/lib/active_record/connection_adapters/postgresql/oid/date.rb +8 -0
  85. data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +5 -0
  86. data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +53 -14
  87. data/lib/active_record/connection_adapters/postgresql/oid/money.rb +3 -2
  88. data/lib/active_record/connection_adapters/postgresql/oid/range.rb +12 -3
  89. data/lib/active_record/connection_adapters/postgresql/oid/timestamp.rb +15 -0
  90. data/lib/active_record/connection_adapters/postgresql/oid/timestamp_with_time_zone.rb +30 -0
  91. data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +18 -6
  92. data/lib/active_record/connection_adapters/postgresql/oid.rb +2 -0
  93. data/lib/active_record/connection_adapters/postgresql/quoting.rb +89 -56
  94. data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +28 -0
  95. data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +92 -2
  96. data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +153 -3
  97. data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +78 -0
  98. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +394 -74
  99. data/lib/active_record/connection_adapters/postgresql/utils.rb +9 -10
  100. data/lib/active_record/connection_adapters/postgresql_adapter.rb +509 -247
  101. data/lib/active_record/connection_adapters/schema_cache.rb +319 -90
  102. data/lib/active_record/connection_adapters/sqlite3/column.rb +49 -0
  103. data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +72 -53
  104. data/lib/active_record/connection_adapters/sqlite3/quoting.rb +37 -21
  105. data/lib/active_record/connection_adapters/sqlite3/schema_definitions.rb +7 -0
  106. data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +43 -22
  107. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +294 -102
  108. data/lib/active_record/connection_adapters/statement_pool.rb +7 -0
  109. data/lib/active_record/connection_adapters/trilogy/database_statements.rb +99 -0
  110. data/lib/active_record/connection_adapters/trilogy_adapter.rb +254 -0
  111. data/lib/active_record/connection_adapters.rb +9 -6
  112. data/lib/active_record/connection_handling.rb +107 -136
  113. data/lib/active_record/core.rb +202 -223
  114. data/lib/active_record/counter_cache.rb +46 -25
  115. data/lib/active_record/database_configurations/connection_url_resolver.rb +2 -1
  116. data/lib/active_record/database_configurations/database_config.rb +21 -12
  117. data/lib/active_record/database_configurations/hash_config.rb +84 -16
  118. data/lib/active_record/database_configurations/url_config.rb +18 -12
  119. data/lib/active_record/database_configurations.rb +95 -59
  120. data/lib/active_record/delegated_type.rb +61 -15
  121. data/lib/active_record/deprecator.rb +7 -0
  122. data/lib/active_record/destroy_association_async_job.rb +3 -1
  123. data/lib/active_record/disable_joins_association_relation.rb +39 -0
  124. data/lib/active_record/dynamic_matchers.rb +1 -1
  125. data/lib/active_record/encryption/auto_filtered_parameters.rb +66 -0
  126. data/lib/active_record/encryption/cipher/aes256_gcm.rb +101 -0
  127. data/lib/active_record/encryption/cipher.rb +53 -0
  128. data/lib/active_record/encryption/config.rb +68 -0
  129. data/lib/active_record/encryption/configurable.rb +60 -0
  130. data/lib/active_record/encryption/context.rb +42 -0
  131. data/lib/active_record/encryption/contexts.rb +76 -0
  132. data/lib/active_record/encryption/derived_secret_key_provider.rb +18 -0
  133. data/lib/active_record/encryption/deterministic_key_provider.rb +14 -0
  134. data/lib/active_record/encryption/encryptable_record.rb +224 -0
  135. data/lib/active_record/encryption/encrypted_attribute_type.rb +151 -0
  136. data/lib/active_record/encryption/encrypted_fixtures.rb +38 -0
  137. data/lib/active_record/encryption/encrypting_only_encryptor.rb +12 -0
  138. data/lib/active_record/encryption/encryptor.rb +155 -0
  139. data/lib/active_record/encryption/envelope_encryption_key_provider.rb +55 -0
  140. data/lib/active_record/encryption/errors.rb +15 -0
  141. data/lib/active_record/encryption/extended_deterministic_queries.rb +157 -0
  142. data/lib/active_record/encryption/extended_deterministic_uniqueness_validator.rb +28 -0
  143. data/lib/active_record/encryption/key.rb +28 -0
  144. data/lib/active_record/encryption/key_generator.rb +53 -0
  145. data/lib/active_record/encryption/key_provider.rb +46 -0
  146. data/lib/active_record/encryption/message.rb +33 -0
  147. data/lib/active_record/encryption/message_serializer.rb +92 -0
  148. data/lib/active_record/encryption/null_encryptor.rb +21 -0
  149. data/lib/active_record/encryption/properties.rb +76 -0
  150. data/lib/active_record/encryption/read_only_null_encryptor.rb +24 -0
  151. data/lib/active_record/encryption/scheme.rb +96 -0
  152. data/lib/active_record/encryption.rb +56 -0
  153. data/lib/active_record/enum.rb +154 -63
  154. data/lib/active_record/errors.rb +171 -15
  155. data/lib/active_record/explain.rb +23 -3
  156. data/lib/active_record/explain_registry.rb +11 -6
  157. data/lib/active_record/explain_subscriber.rb +1 -1
  158. data/lib/active_record/fixture_set/file.rb +15 -1
  159. data/lib/active_record/fixture_set/model_metadata.rb +14 -4
  160. data/lib/active_record/fixture_set/render_context.rb +2 -0
  161. data/lib/active_record/fixture_set/table_row.rb +70 -14
  162. data/lib/active_record/fixture_set/table_rows.rb +4 -4
  163. data/lib/active_record/fixtures.rb +131 -86
  164. data/lib/active_record/future_result.rb +164 -0
  165. data/lib/active_record/gem_version.rb +3 -3
  166. data/lib/active_record/inheritance.rb +81 -29
  167. data/lib/active_record/insert_all.rb +135 -22
  168. data/lib/active_record/integration.rb +11 -10
  169. data/lib/active_record/internal_metadata.rb +119 -33
  170. data/lib/active_record/legacy_yaml_adapter.rb +2 -39
  171. data/lib/active_record/locking/optimistic.rb +36 -21
  172. data/lib/active_record/locking/pessimistic.rb +15 -6
  173. data/lib/active_record/log_subscriber.rb +52 -19
  174. data/lib/active_record/marshalling.rb +56 -0
  175. data/lib/active_record/message_pack.rb +124 -0
  176. data/lib/active_record/middleware/database_selector/resolver.rb +10 -10
  177. data/lib/active_record/middleware/database_selector.rb +23 -13
  178. data/lib/active_record/middleware/shard_selector.rb +62 -0
  179. data/lib/active_record/migration/command_recorder.rb +112 -14
  180. data/lib/active_record/migration/compatibility.rb +221 -48
  181. data/lib/active_record/migration/default_strategy.rb +23 -0
  182. data/lib/active_record/migration/execution_strategy.rb +19 -0
  183. data/lib/active_record/migration/join_table.rb +1 -1
  184. data/lib/active_record/migration/pending_migration_connection.rb +21 -0
  185. data/lib/active_record/migration.rb +358 -171
  186. data/lib/active_record/model_schema.rb +120 -101
  187. data/lib/active_record/nested_attributes.rb +37 -18
  188. data/lib/active_record/no_touching.rb +3 -3
  189. data/lib/active_record/normalization.rb +167 -0
  190. data/lib/active_record/persistence.rb +405 -85
  191. data/lib/active_record/promise.rb +84 -0
  192. data/lib/active_record/query_cache.rb +3 -21
  193. data/lib/active_record/query_logs.rb +174 -0
  194. data/lib/active_record/query_logs_formatter.rb +41 -0
  195. data/lib/active_record/querying.rb +29 -6
  196. data/lib/active_record/railtie.rb +219 -43
  197. data/lib/active_record/railties/controller_runtime.rb +13 -9
  198. data/lib/active_record/railties/databases.rake +188 -252
  199. data/lib/active_record/railties/job_runtime.rb +23 -0
  200. data/lib/active_record/readonly_attributes.rb +41 -3
  201. data/lib/active_record/reflection.rb +241 -80
  202. data/lib/active_record/relation/batches/batch_enumerator.rb +23 -7
  203. data/lib/active_record/relation/batches.rb +192 -63
  204. data/lib/active_record/relation/calculations.rb +219 -90
  205. data/lib/active_record/relation/delegation.rb +27 -13
  206. data/lib/active_record/relation/finder_methods.rb +108 -51
  207. data/lib/active_record/relation/merger.rb +22 -13
  208. data/lib/active_record/relation/predicate_builder/association_query_value.rb +31 -3
  209. data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +4 -6
  210. data/lib/active_record/relation/predicate_builder/relation_handler.rb +5 -1
  211. data/lib/active_record/relation/predicate_builder.rb +27 -20
  212. data/lib/active_record/relation/query_attribute.rb +30 -12
  213. data/lib/active_record/relation/query_methods.rb +654 -127
  214. data/lib/active_record/relation/record_fetch_warning.rb +7 -9
  215. data/lib/active_record/relation/spawn_methods.rb +20 -3
  216. data/lib/active_record/relation/where_clause.rb +10 -19
  217. data/lib/active_record/relation.rb +262 -120
  218. data/lib/active_record/result.rb +37 -11
  219. data/lib/active_record/runtime_registry.rb +18 -13
  220. data/lib/active_record/sanitization.rb +65 -20
  221. data/lib/active_record/schema.rb +36 -22
  222. data/lib/active_record/schema_dumper.rb +73 -24
  223. data/lib/active_record/schema_migration.rb +68 -33
  224. data/lib/active_record/scoping/default.rb +72 -15
  225. data/lib/active_record/scoping/named.rb +5 -13
  226. data/lib/active_record/scoping.rb +65 -34
  227. data/lib/active_record/secure_password.rb +60 -0
  228. data/lib/active_record/secure_token.rb +21 -3
  229. data/lib/active_record/serialization.rb +6 -1
  230. data/lib/active_record/signed_id.rb +10 -8
  231. data/lib/active_record/store.rb +16 -11
  232. data/lib/active_record/suppressor.rb +13 -15
  233. data/lib/active_record/table_metadata.rb +16 -3
  234. data/lib/active_record/tasks/database_tasks.rb +225 -136
  235. data/lib/active_record/tasks/mysql_database_tasks.rb +16 -7
  236. data/lib/active_record/tasks/postgresql_database_tasks.rb +35 -26
  237. data/lib/active_record/tasks/sqlite_database_tasks.rb +15 -7
  238. data/lib/active_record/test_databases.rb +1 -1
  239. data/lib/active_record/test_fixtures.rb +123 -99
  240. data/lib/active_record/timestamp.rb +29 -18
  241. data/lib/active_record/token_for.rb +113 -0
  242. data/lib/active_record/touch_later.rb +11 -6
  243. data/lib/active_record/transactions.rb +48 -27
  244. data/lib/active_record/translation.rb +3 -3
  245. data/lib/active_record/type/adapter_specific_registry.rb +32 -14
  246. data/lib/active_record/type/hash_lookup_type_map.rb +34 -1
  247. data/lib/active_record/type/internal/timezone.rb +7 -2
  248. data/lib/active_record/type/serialized.rb +9 -5
  249. data/lib/active_record/type/time.rb +4 -0
  250. data/lib/active_record/type/type_map.rb +17 -20
  251. data/lib/active_record/type.rb +1 -2
  252. data/lib/active_record/validations/absence.rb +1 -1
  253. data/lib/active_record/validations/associated.rb +4 -4
  254. data/lib/active_record/validations/numericality.rb +5 -4
  255. data/lib/active_record/validations/presence.rb +5 -28
  256. data/lib/active_record/validations/uniqueness.rb +51 -6
  257. data/lib/active_record/validations.rb +8 -4
  258. data/lib/active_record/version.rb +1 -1
  259. data/lib/active_record.rb +335 -32
  260. data/lib/arel/attributes/attribute.rb +0 -8
  261. data/lib/arel/crud.rb +28 -22
  262. data/lib/arel/delete_manager.rb +18 -4
  263. data/lib/arel/errors.rb +10 -0
  264. data/lib/arel/factory_methods.rb +4 -0
  265. data/lib/arel/filter_predications.rb +9 -0
  266. data/lib/arel/insert_manager.rb +2 -3
  267. data/lib/arel/nodes/and.rb +4 -0
  268. data/lib/arel/nodes/binary.rb +6 -1
  269. data/lib/arel/nodes/bound_sql_literal.rb +61 -0
  270. data/lib/arel/nodes/casted.rb +1 -1
  271. data/lib/arel/nodes/cte.rb +36 -0
  272. data/lib/arel/nodes/delete_statement.rb +12 -13
  273. data/lib/arel/nodes/filter.rb +10 -0
  274. data/lib/arel/nodes/fragments.rb +35 -0
  275. data/lib/arel/nodes/function.rb +1 -0
  276. data/lib/arel/nodes/homogeneous_in.rb +1 -9
  277. data/lib/arel/nodes/insert_statement.rb +2 -2
  278. data/lib/arel/nodes/leading_join.rb +8 -0
  279. data/lib/arel/nodes/node.rb +111 -2
  280. data/lib/arel/nodes/select_core.rb +2 -2
  281. data/lib/arel/nodes/select_statement.rb +2 -2
  282. data/lib/arel/nodes/sql_literal.rb +6 -0
  283. data/lib/arel/nodes/table_alias.rb +4 -0
  284. data/lib/arel/nodes/update_statement.rb +8 -3
  285. data/lib/arel/nodes.rb +5 -0
  286. data/lib/arel/predications.rb +13 -3
  287. data/lib/arel/select_manager.rb +10 -4
  288. data/lib/arel/table.rb +9 -6
  289. data/lib/arel/tree_manager.rb +0 -12
  290. data/lib/arel/update_manager.rb +18 -4
  291. data/lib/arel/visitors/dot.rb +80 -90
  292. data/lib/arel/visitors/mysql.rb +16 -3
  293. data/lib/arel/visitors/postgresql.rb +0 -10
  294. data/lib/arel/visitors/to_sql.rb +139 -19
  295. data/lib/arel/visitors/visitor.rb +2 -2
  296. data/lib/arel.rb +18 -3
  297. data/lib/rails/generators/active_record/application_record/USAGE +8 -0
  298. data/lib/rails/generators/active_record/application_record/templates/application_record.rb.tt +1 -1
  299. data/lib/rails/generators/active_record/migration.rb +3 -1
  300. data/lib/rails/generators/active_record/model/USAGE +113 -0
  301. data/lib/rails/generators/active_record/model/model_generator.rb +15 -6
  302. data/lib/rails/generators/active_record/model/templates/abstract_base_class.rb.tt +1 -1
  303. data/lib/rails/generators/active_record/model/templates/model.rb.tt +1 -1
  304. data/lib/rails/generators/active_record/model/templates/module.rb.tt +2 -2
  305. data/lib/rails/generators/active_record/multi_db/multi_db_generator.rb +16 -0
  306. data/lib/rails/generators/active_record/multi_db/templates/multi_db.rb.tt +44 -0
  307. metadata +93 -13
  308. data/lib/active_record/connection_adapters/legacy_pool_manager.rb +0 -35
  309. data/lib/active_record/null_relation.rb +0 -67
@@ -7,9 +7,10 @@ require "active_support/core_ext/array/access"
7
7
  require "active_support/core_ext/enumerable"
8
8
  require "active_support/core_ext/module/attribute_accessors"
9
9
  require "active_support/actionable_error"
10
+ require "active_record/migration/pending_migration_connection"
10
11
 
11
12
  module ActiveRecord
12
- class MigrationError < ActiveRecordError #:nodoc:
13
+ class MigrationError < ActiveRecordError # :nodoc:
13
14
  def initialize(message = nil)
14
15
  message = "\n\n#{message}\n\n" if message
15
16
  super
@@ -20,7 +21,7 @@ module ActiveRecord
20
21
  # For example the following migration is not reversible.
21
22
  # Rolling back this migration will raise an ActiveRecord::IrreversibleMigration error.
22
23
  #
23
- # class IrreversibleMigrationExample < ActiveRecord::Migration[6.0]
24
+ # class IrreversibleMigrationExample < ActiveRecord::Migration[7.1]
24
25
  # def change
25
26
  # create_table :distributors do |t|
26
27
  # t.string :zipcode
@@ -38,7 +39,7 @@ module ActiveRecord
38
39
  #
39
40
  # 1. Define <tt>#up</tt> and <tt>#down</tt> methods instead of <tt>#change</tt>:
40
41
  #
41
- # class ReversibleMigrationExample < ActiveRecord::Migration[6.0]
42
+ # class ReversibleMigrationExample < ActiveRecord::Migration[7.1]
42
43
  # def up
43
44
  # create_table :distributors do |t|
44
45
  # t.string :zipcode
@@ -63,7 +64,7 @@ module ActiveRecord
63
64
  #
64
65
  # 2. Use the #reversible method in <tt>#change</tt> method:
65
66
  #
66
- # class ReversibleMigrationExample < ActiveRecord::Migration[6.0]
67
+ # class ReversibleMigrationExample < ActiveRecord::Migration[7.1]
67
68
  # def change
68
69
  # create_table :distributors do |t|
69
70
  # t.string :zipcode
@@ -90,7 +91,7 @@ module ActiveRecord
90
91
  class IrreversibleMigration < MigrationError
91
92
  end
92
93
 
93
- class DuplicateMigrationVersionError < MigrationError #:nodoc:
94
+ class DuplicateMigrationVersionError < MigrationError # :nodoc:
94
95
  def initialize(version = nil)
95
96
  if version
96
97
  super("Multiple migrations have the version number #{version}.")
@@ -100,7 +101,7 @@ module ActiveRecord
100
101
  end
101
102
  end
102
103
 
103
- class DuplicateMigrationNameError < MigrationError #:nodoc:
104
+ class DuplicateMigrationNameError < MigrationError # :nodoc:
104
105
  def initialize(name = nil)
105
106
  if name
106
107
  super("Multiple migrations have the name #{name}.")
@@ -110,7 +111,7 @@ module ActiveRecord
110
111
  end
111
112
  end
112
113
 
113
- class UnknownMigrationVersionError < MigrationError #:nodoc:
114
+ class UnknownMigrationVersionError < MigrationError # :nodoc:
114
115
  def initialize(version = nil)
115
116
  if version
116
117
  super("No migration with version number #{version}.")
@@ -120,7 +121,7 @@ module ActiveRecord
120
121
  end
121
122
  end
122
123
 
123
- class IllegalMigrationNameError < MigrationError #:nodoc:
124
+ class IllegalMigrationNameError < MigrationError # :nodoc:
124
125
  def initialize(name = nil)
125
126
  if name
126
127
  super("Illegal name for migration file: #{name}\n\t(only lower case letters, numbers, and '_' allowed).")
@@ -130,42 +131,48 @@ module ActiveRecord
130
131
  end
131
132
  end
132
133
 
133
- class PendingMigrationError < MigrationError #:nodoc:
134
+ class PendingMigrationError < MigrationError # :nodoc:
134
135
  include ActiveSupport::ActionableError
135
136
 
136
137
  action "Run pending migrations" do
137
138
  ActiveRecord::Tasks::DatabaseTasks.migrate
138
139
 
139
- if ActiveRecord::Base.dump_schema_after_migration
140
- ActiveRecord::Tasks::DatabaseTasks.dump_schema(
141
- ActiveRecord::Base.connection_db_config
142
- )
140
+ if ActiveRecord.dump_schema_after_migration
141
+ connection = ActiveRecord::Tasks::DatabaseTasks.migration_connection
142
+ ActiveRecord::Tasks::DatabaseTasks.dump_schema(connection.pool.db_config)
143
143
  end
144
144
  end
145
145
 
146
- def initialize(message = nil)
147
- super(message || detailed_migration_message)
146
+ def initialize(message = nil, pending_migrations: nil)
147
+ if pending_migrations.nil?
148
+ connection = ActiveRecord::Tasks::DatabaseTasks.migration_connection
149
+ pending_migrations = connection.migration_context.open.pending_migrations
150
+ end
151
+
152
+ super(message || detailed_migration_message(pending_migrations))
148
153
  end
149
154
 
150
155
  private
151
- def detailed_migration_message
156
+ def detailed_migration_message(pending_migrations)
152
157
  message = "Migrations are pending. To resolve this issue, run:\n\n bin/rails db:migrate"
153
- message += " RAILS_ENV=#{::Rails.env}" if defined?(Rails.env)
158
+ message += " RAILS_ENV=#{::Rails.env}" if defined?(Rails.env) && !Rails.env.local?
154
159
  message += "\n\n"
155
160
 
156
- pending_migrations = ActiveRecord::Base.connection.migration_context.open.pending_migrations
157
-
158
161
  message += "You have #{pending_migrations.size} pending #{pending_migrations.size > 1 ? 'migrations:' : 'migration:'}\n\n"
159
162
 
160
163
  pending_migrations.each do |pending_migration|
161
- message += "#{pending_migration.basename}\n"
164
+ message += "#{pending_migration.filename}\n"
162
165
  end
163
166
 
164
167
  message
165
168
  end
169
+
170
+ def connection
171
+ ActiveRecord::Tasks::DatabaseTasks.migration_connection
172
+ end
166
173
  end
167
174
 
168
- class ConcurrentMigrationError < MigrationError #:nodoc:
175
+ class ConcurrentMigrationError < MigrationError # :nodoc:
169
176
  DEFAULT_MESSAGE = "Cannot run migrations because another migration process is currently running."
170
177
  RELEASE_LOCK_FAILED_MESSAGE = "Failed to release advisory lock"
171
178
 
@@ -174,7 +181,7 @@ module ActiveRecord
174
181
  end
175
182
  end
176
183
 
177
- class NoEnvironmentInSchemaError < MigrationError #:nodoc:
184
+ class NoEnvironmentInSchemaError < MigrationError # :nodoc:
178
185
  def initialize
179
186
  msg = "Environment data not found in the schema. To resolve this issue, run: \n\n bin/rails db:environment:set"
180
187
  if defined?(Rails.env)
@@ -185,7 +192,7 @@ module ActiveRecord
185
192
  end
186
193
  end
187
194
 
188
- class ProtectedEnvironmentError < ActiveRecordError #:nodoc:
195
+ class ProtectedEnvironmentError < ActiveRecordError # :nodoc:
189
196
  def initialize(env = "production")
190
197
  msg = +"You are attempting to run a destructive action against your '#{env}' database.\n"
191
198
  msg << "If you are sure you want to continue, run the same command with the environment variable:\n"
@@ -228,7 +235,7 @@ module ActiveRecord
228
235
  #
229
236
  # Example of a simple migration:
230
237
  #
231
- # class AddSsl < ActiveRecord::Migration[6.0]
238
+ # class AddSsl < ActiveRecord::Migration[7.1]
232
239
  # def up
233
240
  # add_column :accounts, :ssl_enabled, :boolean, default: true
234
241
  # end
@@ -248,7 +255,7 @@ module ActiveRecord
248
255
  #
249
256
  # Example of a more complex migration that also needs to initialize data:
250
257
  #
251
- # class AddSystemSettings < ActiveRecord::Migration[6.0]
258
+ # class AddSystemSettings < ActiveRecord::Migration[7.1]
252
259
  # def up
253
260
  # create_table :system_settings do |t|
254
261
  # t.string :name
@@ -326,7 +333,7 @@ module ActiveRecord
326
333
  # details.
327
334
  # * <tt>change_table(name, options)</tt>: Allows to make column alterations to
328
335
  # the table called +name+. It makes the table object available to a block that
329
- # can then add/remove columns, indexes or foreign keys to it.
336
+ # can then add/remove columns, indexes, or foreign keys to it.
330
337
  # * <tt>rename_column(table_name, column_name, new_column_name)</tt>: Renames
331
338
  # a column but keeps the type and content.
332
339
  # * <tt>rename_index(table_name, old_name, new_name)</tt>: Renames an index.
@@ -356,12 +363,12 @@ module ActiveRecord
356
363
  # == Irreversible transformations
357
364
  #
358
365
  # Some transformations are destructive in a manner that cannot be reversed.
359
- # Migrations of that kind should raise an <tt>ActiveRecord::IrreversibleMigration</tt>
366
+ # Migrations of that kind should raise an ActiveRecord::IrreversibleMigration
360
367
  # exception in their +down+ method.
361
368
  #
362
- # == Running migrations from within Rails
369
+ # == Running migrations from within \Rails
363
370
  #
364
- # The Rails package has several tools to help create and apply migrations.
371
+ # The \Rails package has several tools to help create and apply migrations.
365
372
  #
366
373
  # To generate a new migration, you can use
367
374
  # bin/rails generate migration MyNewMigration
@@ -376,7 +383,7 @@ module ActiveRecord
376
383
  # bin/rails generate migration add_fieldname_to_tablename fieldname:string
377
384
  #
378
385
  # This will generate the file <tt>timestamp_add_fieldname_to_tablename.rb</tt>, which will look like this:
379
- # class AddFieldnameToTablename < ActiveRecord::Migration[6.0]
386
+ # class AddFieldnameToTablename < ActiveRecord::Migration[7.1]
380
387
  # def change
381
388
  # add_column :tablenames, :fieldname, :string
382
389
  # end
@@ -395,14 +402,14 @@ module ActiveRecord
395
402
  # wish to rollback last few migrations. <tt>bin/rails db:rollback STEP=2</tt> will rollback
396
403
  # the latest two migrations.
397
404
  #
398
- # If any of the migrations throw an <tt>ActiveRecord::IrreversibleMigration</tt> exception,
405
+ # If any of the migrations throw an ActiveRecord::IrreversibleMigration exception,
399
406
  # that step will fail and you'll have some manual work to do.
400
407
  #
401
408
  # == More examples
402
409
  #
403
410
  # Not all migrations change the schema. Some just fix the data:
404
411
  #
405
- # class RemoveEmptyTags < ActiveRecord::Migration[6.0]
412
+ # class RemoveEmptyTags < ActiveRecord::Migration[7.1]
406
413
  # def up
407
414
  # Tag.all.each { |tag| tag.destroy if tag.pages.empty? }
408
415
  # end
@@ -415,7 +422,7 @@ module ActiveRecord
415
422
  #
416
423
  # Others remove columns when they migrate up instead of down:
417
424
  #
418
- # class RemoveUnnecessaryItemAttributes < ActiveRecord::Migration[6.0]
425
+ # class RemoveUnnecessaryItemAttributes < ActiveRecord::Migration[7.1]
419
426
  # def up
420
427
  # remove_column :items, :incomplete_items_count
421
428
  # remove_column :items, :completed_items_count
@@ -429,7 +436,7 @@ module ActiveRecord
429
436
  #
430
437
  # And sometimes you need to do something in SQL not abstracted directly by migrations:
431
438
  #
432
- # class MakeJoinUnique < ActiveRecord::Migration[6.0]
439
+ # class MakeJoinUnique < ActiveRecord::Migration[7.1]
433
440
  # def up
434
441
  # execute "ALTER TABLE `pages_linked_pages` ADD UNIQUE `page_id_linked_page_id` (`page_id`,`linked_page_id`)"
435
442
  # end
@@ -446,7 +453,7 @@ module ActiveRecord
446
453
  # <tt>Base#reset_column_information</tt> in order to ensure that the model has the
447
454
  # latest column data from after the new column was added. Example:
448
455
  #
449
- # class AddPeopleSalary < ActiveRecord::Migration[6.0]
456
+ # class AddPeopleSalary < ActiveRecord::Migration[7.1]
450
457
  # def up
451
458
  # add_column :people, :salary, :integer
452
459
  # Person.reset_column_information
@@ -482,7 +489,7 @@ module ActiveRecord
482
489
  #
483
490
  # == Timestamped Migrations
484
491
  #
485
- # By default, Rails generates migrations that look like:
492
+ # By default, \Rails generates migrations that look like:
486
493
  #
487
494
  # 20080717013526_your_migration_name.rb
488
495
  #
@@ -504,7 +511,7 @@ module ActiveRecord
504
511
  # To define a reversible migration, define the +change+ method in your
505
512
  # migration like this:
506
513
  #
507
- # class TenderloveMigration < ActiveRecord::Migration[6.0]
514
+ # class TenderloveMigration < ActiveRecord::Migration[7.1]
508
515
  # def change
509
516
  # create_table(:horses) do |t|
510
517
  # t.column :content, :text
@@ -521,11 +528,11 @@ module ActiveRecord
521
528
  # as before.
522
529
  #
523
530
  # If a command cannot be reversed, an
524
- # <tt>ActiveRecord::IrreversibleMigration</tt> exception will be raised when
531
+ # ActiveRecord::IrreversibleMigration exception will be raised when
525
532
  # the migration is moving down.
526
533
  #
527
534
  # For a list of commands that are reversible, please see
528
- # <tt>ActiveRecord::Migration::CommandRecorder</tt>.
535
+ # +ActiveRecord::Migration::CommandRecorder+.
529
536
  #
530
537
  # == Transactional Migrations
531
538
  #
@@ -534,7 +541,7 @@ module ActiveRecord
534
541
  # can't execute inside a transaction though, and for these situations
535
542
  # you can turn the automatic transactions off.
536
543
  #
537
- # class ChangeEnum < ActiveRecord::Migration[6.0]
544
+ # class ChangeEnum < ActiveRecord::Migration[7.1]
538
545
  # disable_ddl_transaction!
539
546
  #
540
547
  # def up
@@ -548,18 +555,57 @@ module ActiveRecord
548
555
  autoload :CommandRecorder, "active_record/migration/command_recorder"
549
556
  autoload :Compatibility, "active_record/migration/compatibility"
550
557
  autoload :JoinTable, "active_record/migration/join_table"
558
+ autoload :ExecutionStrategy, "active_record/migration/execution_strategy"
559
+ autoload :DefaultStrategy, "active_record/migration/default_strategy"
551
560
 
552
561
  # This must be defined before the inherited hook, below
553
- class Current < Migration #:nodoc:
562
+ class Current < Migration # :nodoc:
563
+ def create_table(table_name, **options)
564
+ if block_given?
565
+ super { |t| yield compatible_table_definition(t) }
566
+ else
567
+ super
568
+ end
569
+ end
570
+
571
+ def change_table(table_name, **options)
572
+ if block_given?
573
+ super { |t| yield compatible_table_definition(t) }
574
+ else
575
+ super
576
+ end
577
+ end
578
+
579
+ def create_join_table(table_1, table_2, **options)
580
+ if block_given?
581
+ super { |t| yield compatible_table_definition(t) }
582
+ else
583
+ super
584
+ end
585
+ end
586
+
587
+ def drop_table(table_name, **options)
588
+ if block_given?
589
+ super { |t| yield compatible_table_definition(t) }
590
+ else
591
+ super
592
+ end
593
+ end
594
+
595
+ def compatible_table_definition(t)
596
+ t
597
+ end
554
598
  end
555
599
 
556
- def self.inherited(subclass) #:nodoc:
600
+ def self.inherited(subclass) # :nodoc:
557
601
  super
558
602
  if subclass.superclass == Migration
603
+ major = ActiveRecord::VERSION::MAJOR
604
+ minor = ActiveRecord::VERSION::MINOR
559
605
  raise StandardError, "Directly inheriting from ActiveRecord::Migration is not supported. " \
560
- "Please specify the Rails release the migration was written for:\n" \
606
+ "Please specify the Active Record release the migration was written for:\n" \
561
607
  "\n" \
562
- " class #{subclass} < ActiveRecord::Migration[4.2]"
608
+ " class #{subclass} < ActiveRecord::Migration[#{major}.#{minor}]"
563
609
  end
564
610
  end
565
611
 
@@ -571,10 +617,17 @@ module ActiveRecord
571
617
  ActiveRecord::VERSION::STRING.to_f
572
618
  end
573
619
 
574
- MigrationFilenameRegexp = /\A([0-9]+)_([_a-z0-9]*)\.?([_a-z0-9]*)?\.rb\z/ #:nodoc:
620
+ MigrationFilenameRegexp = /\A([0-9]+)_([_a-z0-9]*)\.?([_a-z0-9]*)?\.rb\z/ # :nodoc:
621
+
622
+ def self.valid_version_format?(version_string) # :nodoc:
623
+ [
624
+ MigrationFilenameRegexp,
625
+ /\A\d(_?\d)*\z/ # integer with optional underscores
626
+ ].any? { |pattern| pattern.match?(version_string) }
627
+ end
575
628
 
576
629
  # This class is used to verify that all migrations have been run before
577
- # loading a web page if <tt>config.active_record.migration_error</tt> is set to :page_load
630
+ # loading a web page if <tt>config.active_record.migration_error</tt> is set to +:page_load+.
578
631
  class CheckPending
579
632
  def initialize(app, file_watcher: ActiveSupport::FileUpdateChecker)
580
633
  @app = app
@@ -587,7 +640,7 @@ module ActiveRecord
587
640
  @mutex.synchronize do
588
641
  @watcher ||= build_watcher do
589
642
  @needs_check = true
590
- ActiveRecord::Migration.check_pending!(connection)
643
+ ActiveRecord::Migration.check_pending_migrations
591
644
  @needs_check = false
592
645
  end
593
646
 
@@ -603,61 +656,84 @@ module ActiveRecord
603
656
 
604
657
  private
605
658
  def build_watcher(&block)
606
- paths = Array(connection.migration_context.migrations_paths)
659
+ current_environment = ActiveRecord::ConnectionHandling::DEFAULT_ENV.call
660
+ all_configs = ActiveRecord::Base.configurations.configs_for(env_name: current_environment)
661
+ paths = all_configs.flat_map { |config| config.migrations_paths || Migrator.migrations_paths }.uniq
607
662
  @file_watcher.new([], paths.index_with(["rb"]), &block)
608
663
  end
609
664
 
610
665
  def connection
611
- ActiveRecord::Base.connection
666
+ ActiveRecord::Tasks::DatabaseTasks.migration_connection
612
667
  end
613
668
  end
614
669
 
615
670
  class << self
616
- attr_accessor :delegate #:nodoc:
617
- attr_accessor :disable_ddl_transaction #:nodoc:
671
+ attr_accessor :delegate # :nodoc:
672
+ attr_accessor :disable_ddl_transaction # :nodoc:
618
673
 
619
- def nearest_delegate #:nodoc:
674
+ def nearest_delegate # :nodoc:
620
675
  delegate || superclass.nearest_delegate
621
676
  end
622
677
 
623
- # Raises <tt>ActiveRecord::PendingMigrationError</tt> error if any migrations are pending.
624
- def check_pending!(connection = Base.connection)
625
- raise ActiveRecord::PendingMigrationError if connection.migration_context.needs_migration?
678
+ # Raises ActiveRecord::PendingMigrationError error if any migrations are pending.
679
+ #
680
+ # This is deprecated in favor of +check_all_pending!+
681
+ def check_pending!(connection = ActiveRecord::Tasks::DatabaseTasks.migration_connection)
682
+ ActiveRecord.deprecator.warn(<<-MSG.squish)
683
+ The `check_pending!` method is deprecated in favor of `check_all_pending!`. The
684
+ new implementation will loop through all available database configurations and find
685
+ pending migrations. The prior implementation did not permit this.
686
+ MSG
687
+
688
+ pending_migrations = connection.migration_context.open.pending_migrations
689
+
690
+ if pending_migrations.any?
691
+ raise ActiveRecord::PendingMigrationError.new(pending_migrations: pending_migrations)
692
+ end
626
693
  end
627
694
 
628
- def load_schema_if_pending!
629
- current_db_config = Base.connection_db_config
630
- all_configs = ActiveRecord::Base.configurations.configs_for(env_name: Rails.env)
695
+ # Raises ActiveRecord::PendingMigrationError error if any migrations are pending
696
+ # for all database configurations in an environment.
697
+ def check_all_pending!
698
+ pending_migrations = []
699
+
700
+ ActiveRecord::Tasks::DatabaseTasks.with_temporary_connection_for_each(env: env) do |connection|
701
+ if pending = connection.migration_context.open.pending_migrations
702
+ pending_migrations << pending
703
+ end
704
+ end
705
+
706
+ migrations = pending_migrations.flatten
631
707
 
632
- needs_update = !all_configs.all? do |db_config|
633
- Tasks::DatabaseTasks.schema_up_to_date?(db_config, ActiveRecord::Base.schema_format)
708
+ if migrations.any?
709
+ raise ActiveRecord::PendingMigrationError.new(pending_migrations: migrations)
634
710
  end
711
+ end
635
712
 
636
- if needs_update
713
+ def load_schema_if_pending!
714
+ if any_schema_needs_update?
637
715
  # Roundtrip to Rake to allow plugins to hook into database initialization.
638
716
  root = defined?(ENGINE_ROOT) ? ENGINE_ROOT : Rails.root
717
+
639
718
  FileUtils.cd(root) do
640
- Base.clear_all_connections!
719
+ Base.connection_handler.clear_all_connections!(:all)
641
720
  system("bin/rails db:test:prepare")
642
721
  end
643
722
  end
644
723
 
645
- # Establish a new connection, the old database may be gone (db:test:prepare uses purge)
646
- Base.establish_connection(current_db_config)
647
-
648
- check_pending!
724
+ check_pending_migrations
649
725
  end
650
726
 
651
- def maintain_test_schema! #:nodoc:
652
- if ActiveRecord::Base.maintain_test_schema
727
+ def maintain_test_schema! # :nodoc:
728
+ if ActiveRecord.maintain_test_schema
653
729
  suppress_messages { load_schema_if_pending! }
654
730
  end
655
731
  end
656
732
 
657
- def method_missing(name, *args, &block) #:nodoc:
733
+ def method_missing(name, *args, &block) # :nodoc:
658
734
  nearest_delegate.send(name, *args, &block)
659
735
  end
660
- ruby2_keywords(:method_missing) if respond_to?(:ruby2_keywords, true)
736
+ ruby2_keywords(:method_missing)
661
737
 
662
738
  def migrate(direction)
663
739
  new.migrate direction
@@ -670,9 +746,46 @@ module ActiveRecord
670
746
  def disable_ddl_transaction!
671
747
  @disable_ddl_transaction = true
672
748
  end
749
+
750
+ def check_pending_migrations # :nodoc:
751
+ migrations = pending_migrations
752
+
753
+ if migrations.any?
754
+ raise ActiveRecord::PendingMigrationError.new(pending_migrations: migrations)
755
+ end
756
+ end
757
+
758
+ private
759
+ def any_schema_needs_update?
760
+ !db_configs_in_current_env.all? do |db_config|
761
+ Tasks::DatabaseTasks.schema_up_to_date?(db_config, ActiveRecord.schema_format)
762
+ end
763
+ end
764
+
765
+ def db_configs_in_current_env
766
+ ActiveRecord::Base.configurations.configs_for(env_name: env)
767
+ end
768
+
769
+ def pending_migrations
770
+ pending_migrations = []
771
+
772
+ ActiveRecord::Base.configurations.configs_for(env_name: env).each do |db_config|
773
+ ActiveRecord::PendingMigrationConnection.establish_temporary_connection(db_config) do |conn|
774
+ if pending = conn.migration_context.open.pending_migrations
775
+ pending_migrations << pending
776
+ end
777
+ end
778
+ end
779
+
780
+ pending_migrations.flatten
781
+ end
782
+
783
+ def env
784
+ ActiveRecord::ConnectionHandling::DEFAULT_ENV.call
785
+ end
673
786
  end
674
787
 
675
- def disable_ddl_transaction #:nodoc:
788
+ def disable_ddl_transaction # :nodoc:
676
789
  self.class.disable_ddl_transaction
677
790
  end
678
791
 
@@ -685,6 +798,10 @@ module ActiveRecord
685
798
  @connection = nil
686
799
  end
687
800
 
801
+ def execution_strategy
802
+ @execution_strategy ||= ActiveRecord.migration_strategy.new(self)
803
+ end
804
+
688
805
  self.verbose = true
689
806
  # instantiate the delegate object after initialize is defined
690
807
  self.delegate = new
@@ -696,7 +813,7 @@ module ActiveRecord
696
813
  # and create the table 'apples' on the way up, and the reverse
697
814
  # on the way down.
698
815
  #
699
- # class FixTLMigration < ActiveRecord::Migration[6.0]
816
+ # class FixTLMigration < ActiveRecord::Migration[7.1]
700
817
  # def change
701
818
  # revert do
702
819
  # create_table(:horses) do |t|
@@ -715,7 +832,7 @@ module ActiveRecord
715
832
  #
716
833
  # require_relative "20121212123456_tenderlove_migration"
717
834
  #
718
- # class FixupTLMigration < ActiveRecord::Migration[6.0]
835
+ # class FixupTLMigration < ActiveRecord::Migration[7.1]
719
836
  # def change
720
837
  # revert TenderloveMigration
721
838
  #
@@ -726,16 +843,16 @@ module ActiveRecord
726
843
  # end
727
844
  #
728
845
  # This command can be nested.
729
- def revert(*migration_classes)
846
+ def revert(*migration_classes, &block)
730
847
  run(*migration_classes.reverse, revert: true) unless migration_classes.empty?
731
848
  if block_given?
732
849
  if connection.respond_to? :revert
733
- connection.revert { yield }
850
+ connection.revert(&block)
734
851
  else
735
852
  recorder = command_recorder
736
853
  @connection = recorder
737
854
  suppress_messages do
738
- connection.revert { yield }
855
+ connection.revert(&block)
739
856
  end
740
857
  @connection = recorder.delegate
741
858
  recorder.replay(self)
@@ -747,7 +864,7 @@ module ActiveRecord
747
864
  connection.respond_to?(:reverting) && connection.reverting
748
865
  end
749
866
 
750
- ReversibleBlockHelper = Struct.new(:reverting) do #:nodoc:
867
+ ReversibleBlockHelper = Struct.new(:reverting) do # :nodoc:
751
868
  def up
752
869
  yield unless reverting
753
870
  end
@@ -766,7 +883,7 @@ module ActiveRecord
766
883
  # when the three columns 'first_name', 'last_name' and 'full_name' exist,
767
884
  # even when migrating down:
768
885
  #
769
- # class SplitNameMigration < ActiveRecord::Migration[6.0]
886
+ # class SplitNameMigration < ActiveRecord::Migration[7.1]
770
887
  # def change
771
888
  # add_column :users, :first_name, :string
772
889
  # add_column :users, :last_name, :string
@@ -794,7 +911,7 @@ module ActiveRecord
794
911
  # In the following example, the new column +published+ will be given
795
912
  # the value +true+ for all existing records.
796
913
  #
797
- # class AddPublishedToPosts < ActiveRecord::Migration[6.0]
914
+ # class AddPublishedToPosts < ActiveRecord::Migration[7.1]
798
915
  # def change
799
916
  # add_column :posts, :published, :boolean, default: false
800
917
  # up_only do
@@ -802,14 +919,15 @@ module ActiveRecord
802
919
  # end
803
920
  # end
804
921
  # end
805
- def up_only
806
- execute_block { yield } unless reverting?
922
+ def up_only(&block)
923
+ execute_block(&block) unless reverting?
807
924
  end
808
925
 
809
926
  # Runs the given migration classes.
810
927
  # Last argument can specify options:
811
- # - :direction (default is :up)
812
- # - :revert (default is false)
928
+ #
929
+ # - +:direction+ - Default is +:up+.
930
+ # - +:revert+ - Default is +false+.
813
931
  def run(*migration_classes)
814
932
  opts = migration_classes.extract_options!
815
933
  dir = opts[:direction] || :up
@@ -846,7 +964,7 @@ module ActiveRecord
846
964
  end
847
965
 
848
966
  time = nil
849
- ActiveRecord::Base.connection_pool.with_connection do |conn|
967
+ ActiveRecord::Tasks::DatabaseTasks.migration_connection.pool.with_connection do |conn|
850
968
  time = Benchmark.measure do
851
969
  exec_migration(conn, direction)
852
970
  end
@@ -871,6 +989,7 @@ module ActiveRecord
871
989
  end
872
990
  ensure
873
991
  @connection = nil
992
+ @execution_strategy = nil
874
993
  end
875
994
 
876
995
  def write(text = "")
@@ -909,38 +1028,37 @@ module ActiveRecord
909
1028
  end
910
1029
 
911
1030
  def connection
912
- @connection || ActiveRecord::Base.connection
1031
+ @connection || ActiveRecord::Tasks::DatabaseTasks.migration_connection
913
1032
  end
914
1033
 
915
1034
  def method_missing(method, *arguments, &block)
916
- arg_list = arguments.map(&:inspect) * ", "
917
-
918
- say_with_time "#{method}(#{arg_list})" do
1035
+ say_with_time "#{method}(#{format_arguments(arguments)})" do
919
1036
  unless connection.respond_to? :revert
920
1037
  unless arguments.empty? || [:execute, :enable_extension, :disable_extension].include?(method)
921
1038
  arguments[0] = proper_table_name(arguments.first, table_name_options)
922
- if [:rename_table, :add_foreign_key].include?(method) ||
1039
+ if method == :rename_table ||
923
1040
  (method == :remove_foreign_key && !arguments.second.is_a?(Hash))
924
1041
  arguments[1] = proper_table_name(arguments.second, table_name_options)
925
1042
  end
926
1043
  end
927
1044
  end
928
- return super unless connection.respond_to?(method)
929
- connection.send(method, *arguments, &block)
1045
+ return super unless execution_strategy.respond_to?(method)
1046
+ execution_strategy.send(method, *arguments, &block)
930
1047
  end
931
1048
  end
932
- ruby2_keywords(:method_missing) if respond_to?(:ruby2_keywords, true)
1049
+ ruby2_keywords(:method_missing)
933
1050
 
934
1051
  def copy(destination, sources, options = {})
935
1052
  copied = []
936
- schema_migration = options[:schema_migration] || ActiveRecord::SchemaMigration
937
1053
 
938
1054
  FileUtils.mkdir_p(destination) unless File.exist?(destination)
1055
+ schema_migration = SchemaMigration::NullSchemaMigration.new
1056
+ internal_metadata = InternalMetadata::NullInternalMetadata.new
939
1057
 
940
- destination_migrations = ActiveRecord::MigrationContext.new(destination, schema_migration).migrations
1058
+ destination_migrations = ActiveRecord::MigrationContext.new(destination, schema_migration, internal_metadata).migrations
941
1059
  last = destination_migrations.last
942
1060
  sources.each do |scope, path|
943
- source_migrations = ActiveRecord::MigrationContext.new(path, schema_migration).migrations
1061
+ source_migrations = ActiveRecord::MigrationContext.new(path, schema_migration, internal_metadata).migrations
944
1062
 
945
1063
  source_migrations.each do |migration|
946
1064
  source = File.binread(migration.filename)
@@ -955,6 +1073,12 @@ module ActiveRecord
955
1073
  magic_comments << magic_comment; ""
956
1074
  end || break
957
1075
  end
1076
+
1077
+ if !magic_comments.empty? && source.start_with?("\n")
1078
+ magic_comments << "\n"
1079
+ source = source[1..-1]
1080
+ end
1081
+
958
1082
  source = "#{magic_comments}#{inserted_comment}#{source}"
959
1083
 
960
1084
  if duplicate = destination_migrations.detect { |m| m.name == migration.name }
@@ -992,16 +1116,16 @@ module ActiveRecord
992
1116
 
993
1117
  # Determines the version number of the next migration.
994
1118
  def next_migration_number(number)
995
- if ActiveRecord::Base.timestamped_migrations
1119
+ if ActiveRecord.timestamped_migrations
996
1120
  [Time.now.utc.strftime("%Y%m%d%H%M%S"), "%.14d" % number].max
997
1121
  else
998
- SchemaMigration.normalize_migration_number(number)
1122
+ "%.3d" % number.to_i
999
1123
  end
1000
1124
  end
1001
1125
 
1002
1126
  # Builds a hash for use in ActiveRecord::Migration#proper_table_name using
1003
1127
  # the Active Record object's table_name prefix and suffix
1004
- def table_name_options(config = ActiveRecord::Base) #:nodoc:
1128
+ def table_name_options(config = ActiveRecord::Base) # :nodoc:
1005
1129
  {
1006
1130
  table_name_prefix: config.table_name_prefix,
1007
1131
  table_name_suffix: config.table_name_suffix
@@ -1017,6 +1141,22 @@ module ActiveRecord
1017
1141
  end
1018
1142
  end
1019
1143
 
1144
+ def format_arguments(arguments)
1145
+ arg_list = arguments[0...-1].map(&:inspect)
1146
+ last_arg = arguments.last
1147
+ if last_arg.is_a?(Hash)
1148
+ last_arg = last_arg.reject { |k, _v| internal_option?(k) }
1149
+ arg_list << last_arg.inspect unless last_arg.empty?
1150
+ else
1151
+ arg_list << last_arg.inspect
1152
+ end
1153
+ arg_list.join(", ")
1154
+ end
1155
+
1156
+ def internal_option?(option_name)
1157
+ option_name.start_with?("_")
1158
+ end
1159
+
1020
1160
  def command_recorder
1021
1161
  CommandRecorder.new(connection)
1022
1162
  end
@@ -1042,19 +1182,66 @@ module ActiveRecord
1042
1182
  end
1043
1183
 
1044
1184
  def load_migration
1045
- require(File.expand_path(filename))
1185
+ Object.send(:remove_const, name) rescue nil
1186
+
1187
+ load(File.expand_path(filename))
1046
1188
  name.constantize.new(name, version)
1047
1189
  end
1048
1190
  end
1049
1191
 
1050
- class MigrationContext #:nodoc:
1051
- attr_reader :migrations_paths, :schema_migration
1192
+ # = \Migration \Context
1193
+ #
1194
+ # MigrationContext sets the context in which a migration is run.
1195
+ #
1196
+ # A migration context requires the path to the migrations is set
1197
+ # in the +migrations_paths+ parameter. Optionally a +schema_migration+
1198
+ # class can be provided. Multiple database applications will instantiate
1199
+ # a +SchemaMigration+ object per database. From the Rake tasks, \Rails will
1200
+ # handle this for you.
1201
+ class MigrationContext
1202
+ attr_reader :migrations_paths, :schema_migration, :internal_metadata
1203
+
1204
+ def initialize(migrations_paths, schema_migration = nil, internal_metadata = nil)
1205
+ if schema_migration == SchemaMigration
1206
+ ActiveRecord.deprecator.warn(<<-MSG.squish)
1207
+ SchemaMigration no longer inherits from ActiveRecord::Base. If you want
1208
+ to use the default connection, remove this argument. If you want to use a
1209
+ specific connection, instantiate MigrationContext with the connection's schema
1210
+ migration, for example `MigrationContext.new(path, Dog.connection.schema_migration)`.
1211
+ MSG
1212
+
1213
+ schema_migration = nil
1214
+ end
1215
+
1216
+ if internal_metadata == InternalMetadata
1217
+ ActiveRecord.deprecator.warn(<<-MSG.squish)
1218
+ SchemaMigration no longer inherits from ActiveRecord::Base. If you want
1219
+ to use the default connection, remove this argument. If you want to use a
1220
+ specific connection, instantiate MigrationContext with the connection's internal
1221
+ metadata, for example `MigrationContext.new(path, nil, Dog.connection.internal_metadata)`.
1222
+ MSG
1223
+
1224
+ internal_metadata = nil
1225
+ end
1052
1226
 
1053
- def initialize(migrations_paths, schema_migration)
1054
1227
  @migrations_paths = migrations_paths
1055
- @schema_migration = schema_migration
1228
+ @schema_migration = schema_migration || SchemaMigration.new(connection)
1229
+ @internal_metadata = internal_metadata || InternalMetadata.new(connection)
1056
1230
  end
1057
1231
 
1232
+ # Runs the migrations in the +migrations_path+.
1233
+ #
1234
+ # If +target_version+ is +nil+, +migrate+ will run +up+.
1235
+ #
1236
+ # If the +current_version+ and +target_version+ are both
1237
+ # 0 then an empty array will be returned and no migrations
1238
+ # will be run.
1239
+ #
1240
+ # If the +current_version+ in the schema is greater than
1241
+ # the +target_version+, then +down+ will be run.
1242
+ #
1243
+ # If none of the conditions are met, +up+ will be run with
1244
+ # the +target_version+.
1058
1245
  def migrate(target_version = nil, &block)
1059
1246
  case
1060
1247
  when target_version.nil?
@@ -1068,64 +1255,64 @@ module ActiveRecord
1068
1255
  end
1069
1256
  end
1070
1257
 
1071
- def rollback(steps = 1)
1258
+ def rollback(steps = 1) # :nodoc:
1072
1259
  move(:down, steps)
1073
1260
  end
1074
1261
 
1075
- def forward(steps = 1)
1262
+ def forward(steps = 1) # :nodoc:
1076
1263
  move(:up, steps)
1077
1264
  end
1078
1265
 
1079
- def up(target_version = nil)
1266
+ def up(target_version = nil, &block) # :nodoc:
1080
1267
  selected_migrations = if block_given?
1081
- migrations.select { |m| yield m }
1268
+ migrations.select(&block)
1082
1269
  else
1083
1270
  migrations
1084
1271
  end
1085
1272
 
1086
- Migrator.new(:up, selected_migrations, schema_migration, target_version).migrate
1273
+ Migrator.new(:up, selected_migrations, schema_migration, internal_metadata, target_version).migrate
1087
1274
  end
1088
1275
 
1089
- def down(target_version = nil)
1276
+ def down(target_version = nil, &block) # :nodoc:
1090
1277
  selected_migrations = if block_given?
1091
- migrations.select { |m| yield m }
1278
+ migrations.select(&block)
1092
1279
  else
1093
1280
  migrations
1094
1281
  end
1095
1282
 
1096
- Migrator.new(:down, selected_migrations, schema_migration, target_version).migrate
1283
+ Migrator.new(:down, selected_migrations, schema_migration, internal_metadata, target_version).migrate
1097
1284
  end
1098
1285
 
1099
- def run(direction, target_version)
1100
- Migrator.new(direction, migrations, schema_migration, target_version).run
1286
+ def run(direction, target_version) # :nodoc:
1287
+ Migrator.new(direction, migrations, schema_migration, internal_metadata, target_version).run
1101
1288
  end
1102
1289
 
1103
- def open
1104
- Migrator.new(:up, migrations, schema_migration)
1290
+ def open # :nodoc:
1291
+ Migrator.new(:up, migrations, schema_migration, internal_metadata)
1105
1292
  end
1106
1293
 
1107
- def get_all_versions
1294
+ def get_all_versions # :nodoc:
1108
1295
  if schema_migration.table_exists?
1109
- schema_migration.all_versions.map(&:to_i)
1296
+ schema_migration.integer_versions
1110
1297
  else
1111
1298
  []
1112
1299
  end
1113
1300
  end
1114
1301
 
1115
- def current_version
1302
+ def current_version # :nodoc:
1116
1303
  get_all_versions.max || 0
1117
1304
  rescue ActiveRecord::NoDatabaseError
1118
1305
  end
1119
1306
 
1120
- def needs_migration?
1121
- (migrations.collect(&:version) - get_all_versions).size > 0
1307
+ def needs_migration? # :nodoc:
1308
+ pending_migration_versions.size > 0
1122
1309
  end
1123
1310
 
1124
- def any_migrations?
1125
- migrations.any?
1311
+ def pending_migration_versions # :nodoc:
1312
+ migrations.collect(&:version) - get_all_versions
1126
1313
  end
1127
1314
 
1128
- def migrations
1315
+ def migrations # :nodoc:
1129
1316
  migrations = migration_files.map do |file|
1130
1317
  version, name, scope = parse_migration_filename(file)
1131
1318
  raise IllegalMigrationNameError.new(file) unless version
@@ -1138,43 +1325,47 @@ module ActiveRecord
1138
1325
  migrations.sort_by(&:version)
1139
1326
  end
1140
1327
 
1141
- def migrations_status
1328
+ def migrations_status # :nodoc:
1142
1329
  db_list = schema_migration.normalized_versions
1143
1330
 
1144
- file_list = migration_files.map do |file|
1331
+ file_list = migration_files.filter_map do |file|
1145
1332
  version, name, scope = parse_migration_filename(file)
1146
1333
  raise IllegalMigrationNameError.new(file) unless version
1147
1334
  version = schema_migration.normalize_migration_number(version)
1148
1335
  status = db_list.delete(version) ? "up" : "down"
1149
1336
  [status, version, (name + scope).humanize]
1150
- end.compact
1337
+ end
1151
1338
 
1152
1339
  db_list.map! do |version|
1153
1340
  ["up", version, "********** NO FILE **********"]
1154
1341
  end
1155
1342
 
1156
- (db_list + file_list).sort_by { |_, version, _| version }
1343
+ (db_list + file_list).sort_by { |_, version, _| version.to_i }
1157
1344
  end
1158
1345
 
1159
- def current_environment
1346
+ def current_environment # :nodoc:
1160
1347
  ActiveRecord::ConnectionHandling::DEFAULT_ENV.call
1161
1348
  end
1162
1349
 
1163
- def protected_environment?
1350
+ def protected_environment? # :nodoc:
1164
1351
  ActiveRecord::Base.protected_environments.include?(last_stored_environment) if last_stored_environment
1165
1352
  end
1166
1353
 
1167
- def last_stored_environment
1168
- return nil unless ActiveRecord::InternalMetadata.enabled?
1354
+ def last_stored_environment # :nodoc:
1355
+ return nil unless connection.internal_metadata.enabled?
1169
1356
  return nil if current_version == 0
1170
- raise NoEnvironmentInSchemaError unless ActiveRecord::InternalMetadata.table_exists?
1357
+ raise NoEnvironmentInSchemaError unless connection.internal_metadata.table_exists?
1171
1358
 
1172
- environment = ActiveRecord::InternalMetadata[:environment]
1359
+ environment = connection.internal_metadata[:environment]
1173
1360
  raise NoEnvironmentInSchemaError unless environment
1174
1361
  environment
1175
1362
  end
1176
1363
 
1177
1364
  private
1365
+ def connection
1366
+ ActiveRecord::Tasks::DatabaseTasks.migration_connection
1367
+ end
1368
+
1178
1369
  def migration_files
1179
1370
  paths = Array(migrations_paths)
1180
1371
  Dir[*paths.flat_map { |path| "#{path}/**/[0-9]*_*.rb" }]
@@ -1185,7 +1376,7 @@ module ActiveRecord
1185
1376
  end
1186
1377
 
1187
1378
  def move(direction, steps)
1188
- migrator = Migrator.new(direction, migrations, schema_migration)
1379
+ migrator = Migrator.new(direction, migrations, schema_migration, internal_metadata)
1189
1380
 
1190
1381
  if current_version != 0 && !migrator.current_migration
1191
1382
  raise UnknownMigrationVersionError.new(current_version)
@@ -1210,23 +1401,28 @@ module ActiveRecord
1210
1401
 
1211
1402
  # For cases where a table doesn't exist like loading from schema cache
1212
1403
  def current_version
1213
- MigrationContext.new(migrations_paths, SchemaMigration).current_version
1404
+ connection = ActiveRecord::Tasks::DatabaseTasks.migration_connection
1405
+ schema_migration = SchemaMigration.new(connection)
1406
+ internal_metadata = InternalMetadata.new(connection)
1407
+
1408
+ MigrationContext.new(migrations_paths, schema_migration, internal_metadata).current_version
1214
1409
  end
1215
1410
  end
1216
1411
 
1217
1412
  self.migrations_paths = ["db/migrate"]
1218
1413
 
1219
- def initialize(direction, migrations, schema_migration, target_version = nil)
1414
+ def initialize(direction, migrations, schema_migration, internal_metadata, target_version = nil)
1220
1415
  @direction = direction
1221
1416
  @target_version = target_version
1222
1417
  @migrated_versions = nil
1223
1418
  @migrations = migrations
1224
1419
  @schema_migration = schema_migration
1420
+ @internal_metadata = internal_metadata
1225
1421
 
1226
1422
  validate(@migrations)
1227
1423
 
1228
1424
  @schema_migration.create_table
1229
- ActiveRecord::InternalMetadata.create_table
1425
+ @internal_metadata.create_table
1230
1426
  end
1231
1427
 
1232
1428
  def current_version
@@ -1279,18 +1475,21 @@ module ActiveRecord
1279
1475
  end
1280
1476
 
1281
1477
  def load_migrated
1282
- @migrated_versions = Set.new(@schema_migration.all_versions.map(&:to_i))
1478
+ @migrated_versions = Set.new(@schema_migration.integer_versions)
1283
1479
  end
1284
1480
 
1285
1481
  private
1482
+ def connection
1483
+ ActiveRecord::Tasks::DatabaseTasks.migration_connection
1484
+ end
1485
+
1286
1486
  # Used for running a specific migration.
1287
1487
  def run_without_lock
1288
1488
  migration = migrations.detect { |m| m.version == @target_version }
1289
1489
  raise UnknownMigrationVersionError.new(@target_version) if migration.nil?
1290
- result = execute_migration_in_transaction(migration)
1291
1490
 
1292
1491
  record_environment
1293
- result
1492
+ execute_migration_in_transaction(migration)
1294
1493
  end
1295
1494
 
1296
1495
  # Used for running multiple migrations up to or down to a certain value.
@@ -1299,15 +1498,15 @@ module ActiveRecord
1299
1498
  raise UnknownMigrationVersionError.new(@target_version)
1300
1499
  end
1301
1500
 
1302
- result = runnable.each(&method(:execute_migration_in_transaction))
1303
1501
  record_environment
1304
- result
1502
+ runnable.each(&method(:execute_migration_in_transaction))
1305
1503
  end
1306
1504
 
1307
1505
  # Stores the current environment in the database.
1308
1506
  def record_environment
1309
1507
  return if down?
1310
- ActiveRecord::InternalMetadata[:environment] = ActiveRecord::Base.connection.migration_context.current_environment
1508
+
1509
+ @internal_metadata[:environment] = connection.pool.db_config.env_name
1311
1510
  end
1312
1511
 
1313
1512
  def ran?(migration)
@@ -1359,10 +1558,10 @@ module ActiveRecord
1359
1558
  def record_version_state_after_migrating(version)
1360
1559
  if down?
1361
1560
  migrated.delete(version)
1362
- @schema_migration.delete_by(version: version.to_s)
1561
+ @schema_migration.delete_version(version.to_s)
1363
1562
  else
1364
1563
  migrated << version
1365
- @schema_migration.create!(version: version.to_s)
1564
+ @schema_migration.create_version(version.to_s)
1366
1565
  end
1367
1566
  end
1368
1567
 
@@ -1375,52 +1574,40 @@ module ActiveRecord
1375
1574
  end
1376
1575
 
1377
1576
  # Wrap the migration in a transaction only if supported by the adapter.
1378
- def ddl_transaction(migration)
1577
+ def ddl_transaction(migration, &block)
1379
1578
  if use_transaction?(migration)
1380
- Base.transaction { yield }
1579
+ connection.transaction(&block)
1381
1580
  else
1382
1581
  yield
1383
1582
  end
1384
1583
  end
1385
1584
 
1386
1585
  def use_transaction?(migration)
1387
- !migration.disable_ddl_transaction && Base.connection.supports_ddl_transactions?
1586
+ !migration.disable_ddl_transaction && connection.supports_ddl_transactions?
1388
1587
  end
1389
1588
 
1390
1589
  def use_advisory_lock?
1391
- Base.connection.advisory_locks_enabled?
1590
+ connection.advisory_locks_enabled?
1392
1591
  end
1393
1592
 
1394
1593
  def with_advisory_lock
1395
1594
  lock_id = generate_migrator_advisory_lock_id
1396
1595
 
1397
- with_advisory_lock_connection do |connection|
1398
- got_lock = connection.get_advisory_lock(lock_id)
1399
- raise ConcurrentMigrationError unless got_lock
1400
- load_migrated # reload schema_migrations to be sure it wasn't changed by another process before we got the lock
1401
- yield
1402
- ensure
1403
- if got_lock && !connection.release_advisory_lock(lock_id)
1404
- raise ConcurrentMigrationError.new(
1405
- ConcurrentMigrationError::RELEASE_LOCK_FAILED_MESSAGE
1406
- )
1407
- end
1408
- end
1409
- end
1410
-
1411
- def with_advisory_lock_connection
1412
- pool = ActiveRecord::ConnectionAdapters::ConnectionHandler.new.establish_connection(
1413
- ActiveRecord::Base.connection_db_config
1414
- )
1415
-
1416
- pool.with_connection { |connection| yield(connection) }
1596
+ got_lock = connection.get_advisory_lock(lock_id)
1597
+ raise ConcurrentMigrationError unless got_lock
1598
+ load_migrated # reload schema_migrations to be sure it wasn't changed by another process before we got the lock
1599
+ yield
1417
1600
  ensure
1418
- pool&.disconnect!
1601
+ if got_lock && !connection.release_advisory_lock(lock_id)
1602
+ raise ConcurrentMigrationError.new(
1603
+ ConcurrentMigrationError::RELEASE_LOCK_FAILED_MESSAGE
1604
+ )
1605
+ end
1419
1606
  end
1420
1607
 
1421
1608
  MIGRATOR_SALT = 2053462845
1422
1609
  def generate_migrator_advisory_lock_id
1423
- db_name_hash = Zlib.crc32(Base.connection.current_database)
1610
+ db_name_hash = Zlib.crc32(connection.current_database)
1424
1611
  MIGRATOR_SALT * db_name_hash
1425
1612
  end
1426
1613
  end