activerecord 6.1.6 → 7.1.2

Sign up to get free protection for your applications and to get access to all the features.
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