activerecord 6.1.7 → 7.1.5

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