activerecord 4.2.9 → 6.1.4.1

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

Potentially problematic release.


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

Files changed (374) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG.md +964 -1382
  3. data/MIT-LICENSE +4 -2
  4. data/README.rdoc +15 -14
  5. data/examples/performance.rb +33 -32
  6. data/examples/simple.rb +5 -4
  7. data/lib/active_record/aggregations.rb +266 -251
  8. data/lib/active_record/association_relation.rb +40 -15
  9. data/lib/active_record/associations/alias_tracker.rb +40 -43
  10. data/lib/active_record/associations/association.rb +162 -69
  11. data/lib/active_record/associations/association_scope.rb +105 -130
  12. data/lib/active_record/associations/belongs_to_association.rb +83 -65
  13. data/lib/active_record/associations/belongs_to_polymorphic_association.rb +13 -12
  14. data/lib/active_record/associations/builder/association.rb +57 -43
  15. data/lib/active_record/associations/builder/belongs_to.rb +74 -57
  16. data/lib/active_record/associations/builder/collection_association.rb +15 -37
  17. data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +49 -66
  18. data/lib/active_record/associations/builder/has_many.rb +13 -5
  19. data/lib/active_record/associations/builder/has_one.rb +44 -6
  20. data/lib/active_record/associations/builder/singular_association.rb +16 -10
  21. data/lib/active_record/associations/collection_association.rb +148 -287
  22. data/lib/active_record/associations/collection_proxy.rb +252 -150
  23. data/lib/active_record/associations/foreign_association.rb +23 -1
  24. data/lib/active_record/associations/has_many_association.rb +56 -98
  25. data/lib/active_record/associations/has_many_through_association.rb +68 -89
  26. data/lib/active_record/associations/has_one_association.rb +73 -47
  27. data/lib/active_record/associations/has_one_through_association.rb +20 -11
  28. data/lib/active_record/associations/join_dependency/join_association.rb +54 -81
  29. data/lib/active_record/associations/join_dependency/join_base.rb +10 -9
  30. data/lib/active_record/associations/join_dependency/join_part.rb +14 -14
  31. data/lib/active_record/associations/join_dependency.rb +174 -169
  32. data/lib/active_record/associations/preloader/association.rb +108 -115
  33. data/lib/active_record/associations/preloader/through_association.rb +85 -65
  34. data/lib/active_record/associations/preloader.rb +97 -94
  35. data/lib/active_record/associations/singular_association.rb +18 -39
  36. data/lib/active_record/associations/through_association.rb +39 -19
  37. data/lib/active_record/associations.rb +1845 -1598
  38. data/lib/active_record/attribute_assignment.rb +59 -185
  39. data/lib/active_record/attribute_methods/before_type_cast.rb +18 -10
  40. data/lib/active_record/attribute_methods/dirty.rb +168 -148
  41. data/lib/active_record/attribute_methods/primary_key.rb +93 -83
  42. data/lib/active_record/attribute_methods/query.rb +8 -10
  43. data/lib/active_record/attribute_methods/read.rb +19 -79
  44. data/lib/active_record/attribute_methods/serialization.rb +49 -24
  45. data/lib/active_record/attribute_methods/time_zone_conversion.rb +55 -36
  46. data/lib/active_record/attribute_methods/write.rb +24 -55
  47. data/lib/active_record/attribute_methods.rb +149 -154
  48. data/lib/active_record/attributes.rb +234 -78
  49. data/lib/active_record/autosave_association.rb +133 -60
  50. data/lib/active_record/base.rb +46 -46
  51. data/lib/active_record/callbacks.rb +234 -79
  52. data/lib/active_record/coders/json.rb +3 -1
  53. data/lib/active_record/coders/yaml_column.rb +34 -13
  54. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +887 -323
  55. data/lib/active_record/connection_adapters/abstract/database_limits.rb +17 -41
  56. data/lib/active_record/connection_adapters/abstract/database_statements.rb +292 -124
  57. data/lib/active_record/connection_adapters/abstract/query_cache.rb +78 -24
  58. data/lib/active_record/connection_adapters/abstract/quoting.rb +177 -60
  59. data/lib/active_record/connection_adapters/abstract/savepoints.rb +8 -6
  60. data/lib/active_record/connection_adapters/abstract/schema_creation.rb +157 -93
  61. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +473 -255
  62. data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +79 -36
  63. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +869 -286
  64. data/lib/active_record/connection_adapters/abstract/transaction.rb +257 -91
  65. data/lib/active_record/connection_adapters/abstract_adapter.rb +483 -230
  66. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +557 -640
  67. data/lib/active_record/connection_adapters/column.rb +67 -40
  68. data/lib/active_record/connection_adapters/deduplicable.rb +29 -0
  69. data/lib/active_record/connection_adapters/legacy_pool_manager.rb +35 -0
  70. data/lib/active_record/connection_adapters/mysql/column.rb +27 -0
  71. data/lib/active_record/connection_adapters/mysql/database_statements.rb +194 -0
  72. data/lib/active_record/connection_adapters/mysql/explain_pretty_printer.rb +71 -0
  73. data/lib/active_record/connection_adapters/mysql/quoting.rb +96 -0
  74. data/lib/active_record/connection_adapters/mysql/schema_creation.rb +97 -0
  75. data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +103 -0
  76. data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +91 -0
  77. data/lib/active_record/connection_adapters/mysql/schema_statements.rb +268 -0
  78. data/lib/active_record/connection_adapters/mysql/type_metadata.rb +40 -0
  79. data/lib/active_record/connection_adapters/mysql2_adapter.rb +80 -192
  80. data/lib/active_record/connection_adapters/pool_config.rb +73 -0
  81. data/lib/active_record/connection_adapters/pool_manager.rb +47 -0
  82. data/lib/active_record/connection_adapters/postgresql/column.rb +44 -11
  83. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +75 -160
  84. data/lib/active_record/connection_adapters/postgresql/explain_pretty_printer.rb +44 -0
  85. data/lib/active_record/connection_adapters/postgresql/oid/array.rb +49 -58
  86. data/lib/active_record/connection_adapters/postgresql/oid/bit.rb +9 -8
  87. data/lib/active_record/connection_adapters/postgresql/oid/bit_varying.rb +2 -0
  88. data/lib/active_record/connection_adapters/postgresql/oid/bytea.rb +4 -2
  89. data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +8 -6
  90. data/lib/active_record/connection_adapters/postgresql/oid/date.rb +13 -1
  91. data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +14 -19
  92. data/lib/active_record/connection_adapters/postgresql/oid/decimal.rb +3 -1
  93. data/lib/active_record/connection_adapters/postgresql/oid/enum.rb +5 -4
  94. data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +31 -20
  95. data/lib/active_record/connection_adapters/postgresql/oid/inet.rb +2 -0
  96. data/lib/active_record/connection_adapters/postgresql/oid/interval.rb +49 -0
  97. data/lib/active_record/connection_adapters/postgresql/oid/jsonb.rb +3 -11
  98. data/lib/active_record/connection_adapters/postgresql/oid/legacy_point.rb +44 -0
  99. data/lib/active_record/connection_adapters/postgresql/oid/macaddr.rb +25 -0
  100. data/lib/active_record/connection_adapters/postgresql/oid/money.rb +7 -9
  101. data/lib/active_record/connection_adapters/postgresql/oid/{infinity.rb → oid.rb} +5 -3
  102. data/lib/active_record/connection_adapters/postgresql/oid/point.rb +32 -11
  103. data/lib/active_record/connection_adapters/postgresql/oid/range.rb +70 -34
  104. data/lib/active_record/connection_adapters/postgresql/oid/specialized_string.rb +4 -5
  105. data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +58 -54
  106. data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +18 -4
  107. data/lib/active_record/connection_adapters/postgresql/oid/vector.rb +3 -1
  108. data/lib/active_record/connection_adapters/postgresql/oid/xml.rb +3 -1
  109. data/lib/active_record/connection_adapters/postgresql/oid.rb +25 -25
  110. data/lib/active_record/connection_adapters/postgresql/quoting.rb +145 -48
  111. data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +27 -14
  112. data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +80 -0
  113. data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +178 -108
  114. data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +49 -0
  115. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +496 -298
  116. data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +44 -0
  117. data/lib/active_record/connection_adapters/postgresql/utils.rb +11 -8
  118. data/lib/active_record/connection_adapters/postgresql_adapter.rb +588 -375
  119. data/lib/active_record/connection_adapters/schema_cache.rb +167 -29
  120. data/lib/active_record/connection_adapters/sql_type_metadata.rb +45 -0
  121. data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +144 -0
  122. data/lib/active_record/connection_adapters/sqlite3/explain_pretty_printer.rb +21 -0
  123. data/lib/active_record/connection_adapters/sqlite3/quoting.rb +102 -0
  124. data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +21 -0
  125. data/lib/active_record/connection_adapters/sqlite3/schema_definitions.rb +19 -0
  126. data/lib/active_record/connection_adapters/sqlite3/schema_dumper.rb +18 -0
  127. data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +170 -0
  128. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +322 -373
  129. data/lib/active_record/connection_adapters/statement_pool.rb +33 -13
  130. data/lib/active_record/connection_adapters.rb +52 -0
  131. data/lib/active_record/connection_handling.rb +314 -41
  132. data/lib/active_record/core.rb +458 -241
  133. data/lib/active_record/counter_cache.rb +70 -49
  134. data/lib/active_record/database_configurations/connection_url_resolver.rb +98 -0
  135. data/lib/active_record/database_configurations/database_config.rb +80 -0
  136. data/lib/active_record/database_configurations/hash_config.rb +96 -0
  137. data/lib/active_record/database_configurations/url_config.rb +53 -0
  138. data/lib/active_record/database_configurations.rb +272 -0
  139. data/lib/active_record/delegated_type.rb +209 -0
  140. data/lib/active_record/destroy_association_async_job.rb +36 -0
  141. data/lib/active_record/dynamic_matchers.rb +87 -106
  142. data/lib/active_record/enum.rb +211 -92
  143. data/lib/active_record/errors.rb +224 -54
  144. data/lib/active_record/explain.rb +27 -11
  145. data/lib/active_record/explain_registry.rb +4 -2
  146. data/lib/active_record/explain_subscriber.rb +10 -5
  147. data/lib/active_record/fixture_set/file.rb +33 -14
  148. data/lib/active_record/fixture_set/model_metadata.rb +32 -0
  149. data/lib/active_record/fixture_set/render_context.rb +17 -0
  150. data/lib/active_record/fixture_set/table_row.rb +152 -0
  151. data/lib/active_record/fixture_set/table_rows.rb +46 -0
  152. data/lib/active_record/fixtures.rb +275 -500
  153. data/lib/active_record/gem_version.rb +6 -4
  154. data/lib/active_record/inheritance.rb +175 -110
  155. data/lib/active_record/insert_all.rb +212 -0
  156. data/lib/active_record/integration.rb +121 -29
  157. data/lib/active_record/internal_metadata.rb +62 -0
  158. data/lib/active_record/legacy_yaml_adapter.rb +27 -5
  159. data/lib/active_record/locale/en.yml +3 -2
  160. data/lib/active_record/locking/optimistic.rb +98 -92
  161. data/lib/active_record/locking/pessimistic.rb +22 -6
  162. data/lib/active_record/log_subscriber.rb +93 -31
  163. data/lib/active_record/middleware/database_selector/resolver/session.rb +48 -0
  164. data/lib/active_record/middleware/database_selector/resolver.rb +92 -0
  165. data/lib/active_record/middleware/database_selector.rb +77 -0
  166. data/lib/active_record/migration/command_recorder.rb +185 -90
  167. data/lib/active_record/migration/compatibility.rb +295 -0
  168. data/lib/active_record/migration/join_table.rb +8 -7
  169. data/lib/active_record/migration.rb +673 -325
  170. data/lib/active_record/model_schema.rb +418 -113
  171. data/lib/active_record/nested_attributes.rb +263 -224
  172. data/lib/active_record/no_touching.rb +15 -2
  173. data/lib/active_record/null_relation.rb +24 -38
  174. data/lib/active_record/persistence.rb +572 -136
  175. data/lib/active_record/query_cache.rb +29 -23
  176. data/lib/active_record/querying.rb +50 -31
  177. data/lib/active_record/railtie.rb +170 -51
  178. data/lib/active_record/railties/console_sandbox.rb +3 -3
  179. data/lib/active_record/railties/controller_runtime.rb +34 -33
  180. data/lib/active_record/railties/databases.rake +523 -199
  181. data/lib/active_record/readonly_attributes.rb +9 -4
  182. data/lib/active_record/reflection.rb +454 -291
  183. data/lib/active_record/relation/batches/batch_enumerator.rb +85 -0
  184. data/lib/active_record/relation/batches.rb +217 -59
  185. data/lib/active_record/relation/calculations.rb +324 -249
  186. data/lib/active_record/relation/delegation.rb +76 -84
  187. data/lib/active_record/relation/finder_methods.rb +316 -242
  188. data/lib/active_record/relation/from_clause.rb +30 -0
  189. data/lib/active_record/relation/merger.rb +95 -103
  190. data/lib/active_record/relation/predicate_builder/array_handler.rb +26 -26
  191. data/lib/active_record/relation/predicate_builder/association_query_value.rb +42 -0
  192. data/lib/active_record/relation/predicate_builder/basic_object_handler.rb +19 -0
  193. data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +57 -0
  194. data/lib/active_record/relation/predicate_builder/range_handler.rb +22 -0
  195. data/lib/active_record/relation/predicate_builder/relation_handler.rb +7 -1
  196. data/lib/active_record/relation/predicate_builder.rb +136 -122
  197. data/lib/active_record/relation/query_attribute.rb +50 -0
  198. data/lib/active_record/relation/query_methods.rb +757 -413
  199. data/lib/active_record/relation/record_fetch_warning.rb +51 -0
  200. data/lib/active_record/relation/spawn_methods.rb +18 -20
  201. data/lib/active_record/relation/where_clause.rb +239 -0
  202. data/lib/active_record/relation.rb +554 -343
  203. data/lib/active_record/result.rb +91 -47
  204. data/lib/active_record/runtime_registry.rb +6 -4
  205. data/lib/active_record/sanitization.rb +134 -122
  206. data/lib/active_record/schema.rb +21 -24
  207. data/lib/active_record/schema_dumper.rb +141 -92
  208. data/lib/active_record/schema_migration.rb +24 -23
  209. data/lib/active_record/scoping/default.rb +96 -83
  210. data/lib/active_record/scoping/named.rb +78 -36
  211. data/lib/active_record/scoping.rb +45 -27
  212. data/lib/active_record/secure_token.rb +48 -0
  213. data/lib/active_record/serialization.rb +8 -6
  214. data/lib/active_record/signed_id.rb +116 -0
  215. data/lib/active_record/statement_cache.rb +89 -36
  216. data/lib/active_record/store.rb +128 -43
  217. data/lib/active_record/suppressor.rb +61 -0
  218. data/lib/active_record/table_metadata.rb +81 -0
  219. data/lib/active_record/tasks/database_tasks.rb +364 -130
  220. data/lib/active_record/tasks/mysql_database_tasks.rb +67 -113
  221. data/lib/active_record/tasks/postgresql_database_tasks.rb +86 -49
  222. data/lib/active_record/tasks/sqlite_database_tasks.rb +44 -19
  223. data/lib/active_record/test_databases.rb +24 -0
  224. data/lib/active_record/test_fixtures.rb +287 -0
  225. data/lib/active_record/timestamp.rb +86 -43
  226. data/lib/active_record/touch_later.rb +65 -0
  227. data/lib/active_record/transactions.rb +182 -163
  228. data/lib/active_record/translation.rb +3 -1
  229. data/lib/active_record/type/adapter_specific_registry.rb +126 -0
  230. data/lib/active_record/type/date.rb +4 -45
  231. data/lib/active_record/type/date_time.rb +4 -49
  232. data/lib/active_record/type/decimal_without_scale.rb +6 -2
  233. data/lib/active_record/type/hash_lookup_type_map.rb +5 -4
  234. data/lib/active_record/type/internal/timezone.rb +17 -0
  235. data/lib/active_record/type/json.rb +30 -0
  236. data/lib/active_record/type/serialized.rb +27 -15
  237. data/lib/active_record/type/text.rb +2 -2
  238. data/lib/active_record/type/time.rb +21 -16
  239. data/lib/active_record/type/type_map.rb +16 -19
  240. data/lib/active_record/type/unsigned_integer.rb +9 -8
  241. data/lib/active_record/type.rb +84 -23
  242. data/lib/active_record/type_caster/connection.rb +33 -0
  243. data/lib/active_record/type_caster/map.rb +23 -0
  244. data/lib/active_record/type_caster.rb +9 -0
  245. data/lib/active_record/validations/absence.rb +25 -0
  246. data/lib/active_record/validations/associated.rb +12 -4
  247. data/lib/active_record/validations/length.rb +26 -0
  248. data/lib/active_record/validations/numericality.rb +35 -0
  249. data/lib/active_record/validations/presence.rb +14 -13
  250. data/lib/active_record/validations/uniqueness.rb +63 -56
  251. data/lib/active_record/validations.rb +39 -35
  252. data/lib/active_record/version.rb +3 -1
  253. data/lib/active_record.rb +42 -29
  254. data/lib/arel/alias_predication.rb +9 -0
  255. data/lib/arel/attributes/attribute.rb +41 -0
  256. data/lib/arel/collectors/bind.rb +29 -0
  257. data/lib/arel/collectors/composite.rb +39 -0
  258. data/lib/arel/collectors/plain_string.rb +20 -0
  259. data/lib/arel/collectors/sql_string.rb +27 -0
  260. data/lib/arel/collectors/substitute_binds.rb +35 -0
  261. data/lib/arel/crud.rb +42 -0
  262. data/lib/arel/delete_manager.rb +18 -0
  263. data/lib/arel/errors.rb +9 -0
  264. data/lib/arel/expressions.rb +29 -0
  265. data/lib/arel/factory_methods.rb +49 -0
  266. data/lib/arel/insert_manager.rb +49 -0
  267. data/lib/arel/math.rb +45 -0
  268. data/lib/arel/nodes/and.rb +32 -0
  269. data/lib/arel/nodes/ascending.rb +23 -0
  270. data/lib/arel/nodes/binary.rb +126 -0
  271. data/lib/arel/nodes/bind_param.rb +44 -0
  272. data/lib/arel/nodes/case.rb +55 -0
  273. data/lib/arel/nodes/casted.rb +62 -0
  274. data/lib/arel/nodes/comment.rb +29 -0
  275. data/lib/arel/nodes/count.rb +12 -0
  276. data/lib/arel/nodes/delete_statement.rb +45 -0
  277. data/lib/arel/nodes/descending.rb +23 -0
  278. data/lib/arel/nodes/equality.rb +15 -0
  279. data/lib/arel/nodes/extract.rb +24 -0
  280. data/lib/arel/nodes/false.rb +16 -0
  281. data/lib/arel/nodes/full_outer_join.rb +8 -0
  282. data/lib/arel/nodes/function.rb +44 -0
  283. data/lib/arel/nodes/grouping.rb +11 -0
  284. data/lib/arel/nodes/homogeneous_in.rb +76 -0
  285. data/lib/arel/nodes/in.rb +15 -0
  286. data/lib/arel/nodes/infix_operation.rb +92 -0
  287. data/lib/arel/nodes/inner_join.rb +8 -0
  288. data/lib/arel/nodes/insert_statement.rb +37 -0
  289. data/lib/arel/nodes/join_source.rb +20 -0
  290. data/lib/arel/nodes/matches.rb +18 -0
  291. data/lib/arel/nodes/named_function.rb +23 -0
  292. data/lib/arel/nodes/node.rb +51 -0
  293. data/lib/arel/nodes/node_expression.rb +13 -0
  294. data/lib/arel/nodes/ordering.rb +27 -0
  295. data/lib/arel/nodes/outer_join.rb +8 -0
  296. data/lib/arel/nodes/over.rb +15 -0
  297. data/lib/arel/nodes/regexp.rb +16 -0
  298. data/lib/arel/nodes/right_outer_join.rb +8 -0
  299. data/lib/arel/nodes/select_core.rb +67 -0
  300. data/lib/arel/nodes/select_statement.rb +41 -0
  301. data/lib/arel/nodes/sql_literal.rb +19 -0
  302. data/lib/arel/nodes/string_join.rb +11 -0
  303. data/lib/arel/nodes/table_alias.rb +31 -0
  304. data/lib/arel/nodes/terminal.rb +16 -0
  305. data/lib/arel/nodes/true.rb +16 -0
  306. data/lib/arel/nodes/unary.rb +44 -0
  307. data/lib/arel/nodes/unary_operation.rb +20 -0
  308. data/lib/arel/nodes/unqualified_column.rb +22 -0
  309. data/lib/arel/nodes/update_statement.rb +41 -0
  310. data/lib/arel/nodes/values_list.rb +9 -0
  311. data/lib/arel/nodes/window.rb +126 -0
  312. data/lib/arel/nodes/with.rb +11 -0
  313. data/lib/arel/nodes.rb +70 -0
  314. data/lib/arel/order_predications.rb +13 -0
  315. data/lib/arel/predications.rb +250 -0
  316. data/lib/arel/select_manager.rb +270 -0
  317. data/lib/arel/table.rb +118 -0
  318. data/lib/arel/tree_manager.rb +72 -0
  319. data/lib/arel/update_manager.rb +34 -0
  320. data/lib/arel/visitors/dot.rb +308 -0
  321. data/lib/arel/visitors/mysql.rb +93 -0
  322. data/lib/arel/visitors/postgresql.rb +120 -0
  323. data/lib/arel/visitors/sqlite.rb +38 -0
  324. data/lib/arel/visitors/to_sql.rb +899 -0
  325. data/lib/arel/visitors/visitor.rb +45 -0
  326. data/lib/arel/visitors.rb +13 -0
  327. data/lib/arel/window_predications.rb +9 -0
  328. data/lib/arel.rb +54 -0
  329. data/lib/rails/generators/active_record/application_record/application_record_generator.rb +26 -0
  330. data/lib/rails/generators/active_record/application_record/templates/application_record.rb.tt +5 -0
  331. data/lib/rails/generators/active_record/migration/migration_generator.rb +43 -37
  332. data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb.tt +26 -0
  333. data/lib/rails/generators/active_record/migration/templates/{migration.rb → migration.rb.tt} +13 -4
  334. data/lib/rails/generators/active_record/migration.rb +35 -1
  335. data/lib/rails/generators/active_record/model/model_generator.rb +55 -22
  336. data/lib/rails/generators/active_record/model/templates/abstract_base_class.rb.tt +7 -0
  337. data/lib/rails/generators/active_record/model/templates/model.rb.tt +22 -0
  338. data/lib/rails/generators/active_record/model/templates/{module.rb → module.rb.tt} +0 -0
  339. data/lib/rails/generators/active_record.rb +7 -5
  340. metadata +172 -65
  341. data/lib/active_record/associations/preloader/belongs_to.rb +0 -17
  342. data/lib/active_record/associations/preloader/collection_association.rb +0 -24
  343. data/lib/active_record/associations/preloader/has_many.rb +0 -17
  344. data/lib/active_record/associations/preloader/has_many_through.rb +0 -19
  345. data/lib/active_record/associations/preloader/has_one.rb +0 -23
  346. data/lib/active_record/associations/preloader/has_one_through.rb +0 -9
  347. data/lib/active_record/associations/preloader/singular_association.rb +0 -21
  348. data/lib/active_record/attribute.rb +0 -163
  349. data/lib/active_record/attribute_decorators.rb +0 -66
  350. data/lib/active_record/attribute_set/builder.rb +0 -106
  351. data/lib/active_record/attribute_set.rb +0 -81
  352. data/lib/active_record/connection_adapters/connection_specification.rb +0 -275
  353. data/lib/active_record/connection_adapters/mysql_adapter.rb +0 -491
  354. data/lib/active_record/connection_adapters/postgresql/array_parser.rb +0 -93
  355. data/lib/active_record/connection_adapters/postgresql/oid/float.rb +0 -21
  356. data/lib/active_record/connection_adapters/postgresql/oid/integer.rb +0 -11
  357. data/lib/active_record/connection_adapters/postgresql/oid/json.rb +0 -35
  358. data/lib/active_record/connection_adapters/postgresql/oid/time.rb +0 -11
  359. data/lib/active_record/railties/jdbcmysql_error.rb +0 -16
  360. data/lib/active_record/serializers/xml_serializer.rb +0 -193
  361. data/lib/active_record/type/big_integer.rb +0 -13
  362. data/lib/active_record/type/binary.rb +0 -50
  363. data/lib/active_record/type/boolean.rb +0 -31
  364. data/lib/active_record/type/decimal.rb +0 -64
  365. data/lib/active_record/type/decorator.rb +0 -14
  366. data/lib/active_record/type/float.rb +0 -19
  367. data/lib/active_record/type/integer.rb +0 -59
  368. data/lib/active_record/type/mutable.rb +0 -16
  369. data/lib/active_record/type/numeric.rb +0 -36
  370. data/lib/active_record/type/string.rb +0 -40
  371. data/lib/active_record/type/time_value.rb +0 -38
  372. data/lib/active_record/type/value.rb +0 -110
  373. data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb +0 -19
  374. data/lib/rails/generators/active_record/model/templates/model.rb +0 -10
@@ -1,52 +1,221 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "benchmark"
4
+ require "set"
5
+ require "zlib"
6
+ require "active_support/core_ext/array/access"
7
+ require "active_support/core_ext/enumerable"
1
8
  require "active_support/core_ext/module/attribute_accessors"
2
- require 'set'
9
+ require "active_support/actionable_error"
3
10
 
4
11
  module ActiveRecord
5
- class MigrationError < ActiveRecordError#:nodoc:
12
+ class MigrationError < ActiveRecordError #:nodoc:
6
13
  def initialize(message = nil)
7
14
  message = "\n\n#{message}\n\n" if message
8
15
  super
9
16
  end
10
17
  end
11
18
 
12
- # Exception that can be raised to stop migrations from going backwards.
19
+ # Exception that can be raised to stop migrations from being rolled back.
20
+ # For example the following migration is not reversible.
21
+ # Rolling back this migration will raise an ActiveRecord::IrreversibleMigration error.
22
+ #
23
+ # class IrreversibleMigrationExample < ActiveRecord::Migration[6.0]
24
+ # def change
25
+ # create_table :distributors do |t|
26
+ # t.string :zipcode
27
+ # end
28
+ #
29
+ # execute <<~SQL
30
+ # ALTER TABLE distributors
31
+ # ADD CONSTRAINT zipchk
32
+ # CHECK (char_length(zipcode) = 5) NO INHERIT;
33
+ # SQL
34
+ # end
35
+ # end
36
+ #
37
+ # There are two ways to mitigate this problem.
38
+ #
39
+ # 1. Define <tt>#up</tt> and <tt>#down</tt> methods instead of <tt>#change</tt>:
40
+ #
41
+ # class ReversibleMigrationExample < ActiveRecord::Migration[6.0]
42
+ # def up
43
+ # create_table :distributors do |t|
44
+ # t.string :zipcode
45
+ # end
46
+ #
47
+ # execute <<~SQL
48
+ # ALTER TABLE distributors
49
+ # ADD CONSTRAINT zipchk
50
+ # CHECK (char_length(zipcode) = 5) NO INHERIT;
51
+ # SQL
52
+ # end
53
+ #
54
+ # def down
55
+ # execute <<~SQL
56
+ # ALTER TABLE distributors
57
+ # DROP CONSTRAINT zipchk
58
+ # SQL
59
+ #
60
+ # drop_table :distributors
61
+ # end
62
+ # end
63
+ #
64
+ # 2. Use the #reversible method in <tt>#change</tt> method:
65
+ #
66
+ # class ReversibleMigrationExample < ActiveRecord::Migration[6.0]
67
+ # def change
68
+ # create_table :distributors do |t|
69
+ # t.string :zipcode
70
+ # end
71
+ #
72
+ # reversible do |dir|
73
+ # dir.up do
74
+ # execute <<~SQL
75
+ # ALTER TABLE distributors
76
+ # ADD CONSTRAINT zipchk
77
+ # CHECK (char_length(zipcode) = 5) NO INHERIT;
78
+ # SQL
79
+ # end
80
+ #
81
+ # dir.down do
82
+ # execute <<~SQL
83
+ # ALTER TABLE distributors
84
+ # DROP CONSTRAINT zipchk
85
+ # SQL
86
+ # end
87
+ # end
88
+ # end
89
+ # end
13
90
  class IrreversibleMigration < MigrationError
14
91
  end
15
92
 
16
- class DuplicateMigrationVersionError < MigrationError#:nodoc:
17
- def initialize(version)
18
- super("Multiple migrations have the version number #{version}")
93
+ class DuplicateMigrationVersionError < MigrationError #:nodoc:
94
+ def initialize(version = nil)
95
+ if version
96
+ super("Multiple migrations have the version number #{version}.")
97
+ else
98
+ super("Duplicate migration version error.")
99
+ end
19
100
  end
20
101
  end
21
102
 
22
- class DuplicateMigrationNameError < MigrationError#:nodoc:
23
- def initialize(name)
24
- super("Multiple migrations have the name #{name}")
103
+ class DuplicateMigrationNameError < MigrationError #:nodoc:
104
+ def initialize(name = nil)
105
+ if name
106
+ super("Multiple migrations have the name #{name}.")
107
+ else
108
+ super("Duplicate migration name.")
109
+ end
25
110
  end
26
111
  end
27
112
 
28
113
  class UnknownMigrationVersionError < MigrationError #:nodoc:
29
- def initialize(version)
30
- super("No migration with version number #{version}")
114
+ def initialize(version = nil)
115
+ if version
116
+ super("No migration with version number #{version}.")
117
+ else
118
+ super("Unknown migration version.")
119
+ end
120
+ end
121
+ end
122
+
123
+ class IllegalMigrationNameError < MigrationError #:nodoc:
124
+ def initialize(name = nil)
125
+ if name
126
+ super("Illegal name for migration file: #{name}\n\t(only lower case letters, numbers, and '_' allowed).")
127
+ else
128
+ super("Illegal name for migration.")
129
+ end
130
+ end
131
+ end
132
+
133
+ class PendingMigrationError < MigrationError #:nodoc:
134
+ include ActiveSupport::ActionableError
135
+
136
+ action "Run pending migrations" do
137
+ ActiveRecord::Tasks::DatabaseTasks.migrate
138
+
139
+ if ActiveRecord::Base.dump_schema_after_migration
140
+ ActiveRecord::Tasks::DatabaseTasks.dump_schema(
141
+ ActiveRecord::Base.connection_db_config
142
+ )
143
+ end
31
144
  end
145
+
146
+ def initialize(message = nil)
147
+ super(message || detailed_migration_message)
148
+ end
149
+
150
+ private
151
+ def detailed_migration_message
152
+ 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)
154
+ message += "\n\n"
155
+
156
+ pending_migrations = ActiveRecord::Base.connection.migration_context.open.pending_migrations
157
+
158
+ message += "You have #{pending_migrations.size} pending #{pending_migrations.size > 1 ? 'migrations:' : 'migration:'}\n\n"
159
+
160
+ pending_migrations.each do |pending_migration|
161
+ message += "#{pending_migration.basename}\n"
162
+ end
163
+
164
+ message
165
+ end
32
166
  end
33
167
 
34
- class IllegalMigrationNameError < MigrationError#:nodoc:
35
- def initialize(name)
36
- super("Illegal name for migration file: #{name}\n\t(only lower case letters, numbers, and '_' allowed)")
168
+ class ConcurrentMigrationError < MigrationError #:nodoc:
169
+ DEFAULT_MESSAGE = "Cannot run migrations because another migration process is currently running."
170
+ RELEASE_LOCK_FAILED_MESSAGE = "Failed to release advisory lock"
171
+
172
+ def initialize(message = DEFAULT_MESSAGE)
173
+ super
37
174
  end
38
175
  end
39
176
 
40
- class PendingMigrationError < MigrationError#:nodoc:
177
+ class NoEnvironmentInSchemaError < MigrationError #:nodoc:
41
178
  def initialize
179
+ msg = "Environment data not found in the schema. To resolve this issue, run: \n\n bin/rails db:environment:set"
180
+ if defined?(Rails.env)
181
+ super("#{msg} RAILS_ENV=#{::Rails.env}")
182
+ else
183
+ super(msg)
184
+ end
185
+ end
186
+ end
187
+
188
+ class ProtectedEnvironmentError < ActiveRecordError #:nodoc:
189
+ def initialize(env = "production")
190
+ msg = +"You are attempting to run a destructive action against your '#{env}' database.\n"
191
+ msg << "If you are sure you want to continue, run the same command with the environment variable:\n"
192
+ msg << "DISABLE_DATABASE_ENVIRONMENT_CHECK=1"
193
+ super(msg)
194
+ end
195
+ end
196
+
197
+ class EnvironmentMismatchError < ActiveRecordError
198
+ def initialize(current: nil, stored: nil)
199
+ msg = +"You are attempting to modify a database that was last run in `#{ stored }` environment.\n"
200
+ msg << "You are running in `#{ current }` environment. "
201
+ msg << "If you are sure you want to continue, first set the environment using:\n\n"
202
+ msg << " bin/rails db:environment:set"
42
203
  if defined?(Rails.env)
43
- super("Migrations are pending. To resolve this issue, run:\n\n\tbin/rake db:migrate RAILS_ENV=#{::Rails.env}")
204
+ super("#{msg} RAILS_ENV=#{::Rails.env}\n\n")
44
205
  else
45
- super("Migrations are pending. To resolve this issue, run:\n\n\tbin/rake db:migrate")
206
+ super("#{msg}\n\n")
46
207
  end
47
208
  end
48
209
  end
49
210
 
211
+ class EnvironmentStorageError < ActiveRecordError # :nodoc:
212
+ def initialize
213
+ msg = +"You are attempting to store the environment in a database where metadata is disabled.\n"
214
+ msg << "Check your database configuration to see if this is intended."
215
+ super(msg)
216
+ end
217
+ end
218
+
50
219
  # = Active Record Migrations
51
220
  #
52
221
  # Migrations can manage the evolution of a schema used by several physical
@@ -59,7 +228,7 @@ module ActiveRecord
59
228
  #
60
229
  # Example of a simple migration:
61
230
  #
62
- # class AddSsl < ActiveRecord::Migration
231
+ # class AddSsl < ActiveRecord::Migration[6.0]
63
232
  # def up
64
233
  # add_column :accounts, :ssl_enabled, :boolean, default: true
65
234
  # end
@@ -79,7 +248,7 @@ module ActiveRecord
79
248
  #
80
249
  # Example of a more complex migration that also needs to initialize data:
81
250
  #
82
- # class AddSystemSettings < ActiveRecord::Migration
251
+ # class AddSystemSettings < ActiveRecord::Migration[6.0]
83
252
  # def up
84
253
  # create_table :system_settings do |t|
85
254
  # t.string :name
@@ -106,17 +275,18 @@ module ActiveRecord
106
275
  #
107
276
  # == Available transformations
108
277
  #
278
+ # === Creation
279
+ #
280
+ # * <tt>create_join_table(table_1, table_2, options)</tt>: Creates a join
281
+ # table having its name as the lexical order of the first two
282
+ # arguments. See
283
+ # ActiveRecord::ConnectionAdapters::SchemaStatements#create_join_table for
284
+ # details.
109
285
  # * <tt>create_table(name, options)</tt>: Creates a table called +name+ and
110
286
  # makes the table object available to a block that can then add columns to it,
111
287
  # following the same format as +add_column+. See example above. The options hash
112
288
  # is for fragments like "DEFAULT CHARSET=UTF-8" that are appended to the create
113
289
  # table definition.
114
- # * <tt>drop_table(name)</tt>: Drops the table called +name+.
115
- # * <tt>change_table(name, options)</tt>: Allows to make column alterations to
116
- # the table called +name+. It makes the table object available to a block that
117
- # can then add/remove columns, indexes or foreign keys to it.
118
- # * <tt>rename_table(old_name, new_name)</tt>: Renames the table called +old_name+
119
- # to +new_name+.
120
290
  # * <tt>add_column(table_name, column_name, type, options)</tt>: Adds a new column
121
291
  # to the table called +table_name+
122
292
  # named +column_name+ specified to be one of the following types:
@@ -127,21 +297,61 @@ module ActiveRecord
127
297
  # Other options include <tt>:limit</tt> and <tt>:null</tt> (e.g.
128
298
  # <tt>{ limit: 50, null: false }</tt>) -- see
129
299
  # ActiveRecord::ConnectionAdapters::TableDefinition#column for details.
130
- # * <tt>rename_column(table_name, column_name, new_column_name)</tt>: Renames
131
- # a column but keeps the type and content.
132
- # * <tt>change_column(table_name, column_name, type, options)</tt>: Changes
133
- # the column to a different type using the same parameters as add_column.
134
- # * <tt>remove_column(table_name, column_name, type, options)</tt>: Removes the column
135
- # named +column_name+ from the table called +table_name+.
300
+ # * <tt>add_foreign_key(from_table, to_table, options)</tt>: Adds a new
301
+ # foreign key. +from_table+ is the table with the key column, +to_table+ contains
302
+ # the referenced primary key.
136
303
  # * <tt>add_index(table_name, column_names, options)</tt>: Adds a new index
137
304
  # with the name of the column. Other options include
138
305
  # <tt>:name</tt>, <tt>:unique</tt> (e.g.
139
306
  # <tt>{ name: 'users_name_index', unique: true }</tt>) and <tt>:order</tt>
140
307
  # (e.g. <tt>{ order: { name: :desc } }</tt>).
141
- # * <tt>remove_index(table_name, column: column_name)</tt>: Removes the index
142
- # specified by +column_name+.
308
+ # * <tt>add_reference(:table_name, :reference_name)</tt>: Adds a new column
309
+ # +reference_name_id+ by default an integer. See
310
+ # ActiveRecord::ConnectionAdapters::SchemaStatements#add_reference for details.
311
+ # * <tt>add_timestamps(table_name, options)</tt>: Adds timestamps (+created_at+
312
+ # and +updated_at+) columns to +table_name+.
313
+ #
314
+ # === Modification
315
+ #
316
+ # * <tt>change_column(table_name, column_name, type, options)</tt>: Changes
317
+ # the column to a different type using the same parameters as add_column.
318
+ # * <tt>change_column_default(table_name, column_name, default_or_changes)</tt>:
319
+ # Sets a default value for +column_name+ defined by +default_or_changes+ on
320
+ # +table_name+. Passing a hash containing <tt>:from</tt> and <tt>:to</tt>
321
+ # as +default_or_changes+ will make this change reversible in the migration.
322
+ # * <tt>change_column_null(table_name, column_name, null, default = nil)</tt>:
323
+ # Sets or removes a <tt>NOT NULL</tt> constraint on +column_name+. The +null+ flag
324
+ # indicates whether the value can be +NULL+. See
325
+ # ActiveRecord::ConnectionAdapters::SchemaStatements#change_column_null for
326
+ # details.
327
+ # * <tt>change_table(name, options)</tt>: Allows to make column alterations to
328
+ # 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.
330
+ # * <tt>rename_column(table_name, column_name, new_column_name)</tt>: Renames
331
+ # a column but keeps the type and content.
332
+ # * <tt>rename_index(table_name, old_name, new_name)</tt>: Renames an index.
333
+ # * <tt>rename_table(old_name, new_name)</tt>: Renames the table called +old_name+
334
+ # to +new_name+.
335
+ #
336
+ # === Deletion
337
+ #
338
+ # * <tt>drop_table(name)</tt>: Drops the table called +name+.
339
+ # * <tt>drop_join_table(table_1, table_2, options)</tt>: Drops the join table
340
+ # specified by the given arguments.
341
+ # * <tt>remove_column(table_name, column_name, type, options)</tt>: Removes the column
342
+ # named +column_name+ from the table called +table_name+.
343
+ # * <tt>remove_columns(table_name, *column_names)</tt>: Removes the given
344
+ # columns from the table definition.
345
+ # * <tt>remove_foreign_key(from_table, to_table = nil, **options)</tt>: Removes the
346
+ # given foreign key from the table called +table_name+.
347
+ # * <tt>remove_index(table_name, column: column_names)</tt>: Removes the index
348
+ # specified by +column_names+.
143
349
  # * <tt>remove_index(table_name, name: index_name)</tt>: Removes the index
144
350
  # specified by +index_name+.
351
+ # * <tt>remove_reference(table_name, ref_name, options)</tt>: Removes the
352
+ # reference(s) on +table_name+ specified by +ref_name+.
353
+ # * <tt>remove_timestamps(table_name, options)</tt>: Removes the timestamp
354
+ # columns (+created_at+ and +updated_at+) from the table definition.
145
355
  #
146
356
  # == Irreversible transformations
147
357
  #
@@ -154,7 +364,7 @@ module ActiveRecord
154
364
  # The Rails package has several tools to help create and apply migrations.
155
365
  #
156
366
  # To generate a new migration, you can use
157
- # rails generate migration MyNewMigration
367
+ # bin/rails generate migration MyNewMigration
158
368
  #
159
369
  # where MyNewMigration is the name of your migration. The generator will
160
370
  # create an empty migration file <tt>timestamp_my_new_migration.rb</tt>
@@ -163,41 +373,36 @@ module ActiveRecord
163
373
  #
164
374
  # There is a special syntactic shortcut to generate migrations that add fields to a table.
165
375
  #
166
- # rails generate migration add_fieldname_to_tablename fieldname:string
376
+ # bin/rails generate migration add_fieldname_to_tablename fieldname:string
167
377
  #
168
- # This will generate the file <tt>timestamp_add_fieldname_to_tablename</tt>, which will look like this:
169
- # class AddFieldnameToTablename < ActiveRecord::Migration
378
+ # 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]
170
380
  # def change
171
- # add_column :tablenames, :field, :string
381
+ # add_column :tablenames, :fieldname, :string
172
382
  # end
173
383
  # end
174
384
  #
175
385
  # To run migrations against the currently configured database, use
176
- # <tt>rake db:migrate</tt>. This will update the database by running all of the
386
+ # <tt>bin/rails db:migrate</tt>. This will update the database by running all of the
177
387
  # pending migrations, creating the <tt>schema_migrations</tt> table
178
388
  # (see "About the schema_migrations table" section below) if missing. It will also
179
- # invoke the db:schema:dump task, which will update your db/schema.rb file
389
+ # invoke the db:schema:dump command, which will update your db/schema.rb file
180
390
  # to match the structure of your database.
181
391
  #
182
392
  # To roll the database back to a previous migration version, use
183
- # <tt>rake db:migrate VERSION=X</tt> where <tt>X</tt> is the version to which
393
+ # <tt>bin/rails db:rollback VERSION=X</tt> where <tt>X</tt> is the version to which
184
394
  # you wish to downgrade. Alternatively, you can also use the STEP option if you
185
- # wish to rollback last few migrations. <tt>rake db:migrate STEP=2</tt> will rollback
395
+ # wish to rollback last few migrations. <tt>bin/rails db:rollback STEP=2</tt> will rollback
186
396
  # the latest two migrations.
187
397
  #
188
398
  # If any of the migrations throw an <tt>ActiveRecord::IrreversibleMigration</tt> exception,
189
399
  # that step will fail and you'll have some manual work to do.
190
400
  #
191
- # == Database support
192
- #
193
- # Migrations are currently supported in MySQL, PostgreSQL, SQLite,
194
- # SQL Server, and Oracle (all supported databases except DB2).
195
- #
196
401
  # == More examples
197
402
  #
198
403
  # Not all migrations change the schema. Some just fix the data:
199
404
  #
200
- # class RemoveEmptyTags < ActiveRecord::Migration
405
+ # class RemoveEmptyTags < ActiveRecord::Migration[6.0]
201
406
  # def up
202
407
  # Tag.all.each { |tag| tag.destroy if tag.pages.empty? }
203
408
  # end
@@ -210,7 +415,7 @@ module ActiveRecord
210
415
  #
211
416
  # Others remove columns when they migrate up instead of down:
212
417
  #
213
- # class RemoveUnnecessaryItemAttributes < ActiveRecord::Migration
418
+ # class RemoveUnnecessaryItemAttributes < ActiveRecord::Migration[6.0]
214
419
  # def up
215
420
  # remove_column :items, :incomplete_items_count
216
421
  # remove_column :items, :completed_items_count
@@ -224,7 +429,7 @@ module ActiveRecord
224
429
  #
225
430
  # And sometimes you need to do something in SQL not abstracted directly by migrations:
226
431
  #
227
- # class MakeJoinUnique < ActiveRecord::Migration
432
+ # class MakeJoinUnique < ActiveRecord::Migration[6.0]
228
433
  # def up
229
434
  # execute "ALTER TABLE `pages_linked_pages` ADD UNIQUE `page_id_linked_page_id` (`page_id`,`linked_page_id`)"
230
435
  # end
@@ -241,7 +446,7 @@ module ActiveRecord
241
446
  # <tt>Base#reset_column_information</tt> in order to ensure that the model has the
242
447
  # latest column data from after the new column was added. Example:
243
448
  #
244
- # class AddPeopleSalary < ActiveRecord::Migration
449
+ # class AddPeopleSalary < ActiveRecord::Migration[6.0]
245
450
  # def up
246
451
  # add_column :people, :salary, :integer
247
452
  # Person.reset_column_information
@@ -275,21 +480,6 @@ module ActiveRecord
275
480
  # The phrase "Updating salaries..." would then be printed, along with the
276
481
  # benchmark for the block when the block completes.
277
482
  #
278
- # == About the schema_migrations table
279
- #
280
- # Rails versions 2.0 and prior used to create a table called
281
- # <tt>schema_info</tt> when using migrations. This table contained the
282
- # version of the schema as of the last applied migration.
283
- #
284
- # Starting with Rails 2.1, the <tt>schema_info</tt> table is
285
- # (automatically) replaced by the <tt>schema_migrations</tt> table, which
286
- # contains the version numbers of all the migrations applied.
287
- #
288
- # As a result, it is now possible to add migration files that are numbered
289
- # lower than the current schema version: when migrating up, those
290
- # never-applied "interleaved" migrations will be automatically applied, and
291
- # when migrating down, never-applied "interleaved" migrations will be skipped.
292
- #
293
483
  # == Timestamped Migrations
294
484
  #
295
485
  # By default, Rails generates migrations that look like:
@@ -314,7 +504,7 @@ module ActiveRecord
314
504
  # To define a reversible migration, define the +change+ method in your
315
505
  # migration like this:
316
506
  #
317
- # class TenderloveMigration < ActiveRecord::Migration
507
+ # class TenderloveMigration < ActiveRecord::Migration[6.0]
318
508
  # def change
319
509
  # create_table(:horses) do |t|
320
510
  # t.column :content, :text
@@ -326,9 +516,9 @@ module ActiveRecord
326
516
  # This migration will create the horses table for you on the way up, and
327
517
  # automatically figure out how to drop the table on the way down.
328
518
  #
329
- # Some commands like +remove_column+ cannot be reversed. If you care to
330
- # define how to move up and down in these cases, you should define the +up+
331
- # and +down+ methods as before.
519
+ # Some commands cannot be reversed. If you care to define how to move up
520
+ # and down in these cases, you should define the +up+ and +down+ methods
521
+ # as before.
332
522
  #
333
523
  # If a command cannot be reversed, an
334
524
  # <tt>ActiveRecord::IrreversibleMigration</tt> exception will be raised when
@@ -344,7 +534,7 @@ module ActiveRecord
344
534
  # can't execute inside a transaction though, and for these situations
345
535
  # you can turn the automatic transactions off.
346
536
  #
347
- # class ChangeEnum < ActiveRecord::Migration
537
+ # class ChangeEnum < ActiveRecord::Migration[6.0]
348
538
  # disable_ddl_transaction!
349
539
  #
350
540
  # def up
@@ -355,66 +545,119 @@ module ActiveRecord
355
545
  # Remember that you can still open your own transactions, even if you
356
546
  # are in a Migration with <tt>self.disable_ddl_transaction!</tt>.
357
547
  class Migration
358
- autoload :CommandRecorder, 'active_record/migration/command_recorder'
548
+ autoload :CommandRecorder, "active_record/migration/command_recorder"
549
+ autoload :Compatibility, "active_record/migration/compatibility"
550
+ autoload :JoinTable, "active_record/migration/join_table"
359
551
 
552
+ # This must be defined before the inherited hook, below
553
+ class Current < Migration #:nodoc:
554
+ end
555
+
556
+ def self.inherited(subclass) #:nodoc:
557
+ super
558
+ if subclass.superclass == Migration
559
+ raise StandardError, "Directly inheriting from ActiveRecord::Migration is not supported. " \
560
+ "Please specify the Rails release the migration was written for:\n" \
561
+ "\n" \
562
+ " class #{subclass} < ActiveRecord::Migration[4.2]"
563
+ end
564
+ end
565
+
566
+ def self.[](version)
567
+ Compatibility.find(version)
568
+ end
569
+
570
+ def self.current_version
571
+ ActiveRecord::VERSION::STRING.to_f
572
+ end
573
+
574
+ MigrationFilenameRegexp = /\A([0-9]+)_([_a-z0-9]*)\.?([_a-z0-9]*)?\.rb\z/ #:nodoc:
360
575
 
361
576
  # This class is used to verify that all migrations have been run before
362
- # loading a web page if config.active_record.migration_error is set to :page_load
577
+ # loading a web page if <tt>config.active_record.migration_error</tt> is set to :page_load
363
578
  class CheckPending
364
- def initialize(app)
579
+ def initialize(app, file_watcher: ActiveSupport::FileUpdateChecker)
365
580
  @app = app
366
- @last_check = 0
581
+ @needs_check = true
582
+ @mutex = Mutex.new
583
+ @file_watcher = file_watcher
367
584
  end
368
585
 
369
586
  def call(env)
370
- if connection.supports_migrations?
371
- mtime = ActiveRecord::Migrator.last_migration.mtime.to_i
372
- if @last_check < mtime
587
+ @mutex.synchronize do
588
+ @watcher ||= build_watcher do
589
+ @needs_check = true
373
590
  ActiveRecord::Migration.check_pending!(connection)
374
- @last_check = mtime
591
+ @needs_check = false
592
+ end
593
+
594
+ if @needs_check
595
+ @watcher.execute
596
+ else
597
+ @watcher.execute_if_updated
375
598
  end
376
599
  end
600
+
377
601
  @app.call(env)
378
602
  end
379
603
 
380
604
  private
605
+ def build_watcher(&block)
606
+ paths = Array(connection.migration_context.migrations_paths)
607
+ @file_watcher.new([], paths.index_with(["rb"]), &block)
608
+ end
381
609
 
382
- def connection
383
- ActiveRecord::Base.connection
384
- end
610
+ def connection
611
+ ActiveRecord::Base.connection
612
+ end
385
613
  end
386
614
 
387
615
  class << self
388
- attr_accessor :delegate # :nodoc:
389
- attr_accessor :disable_ddl_transaction # :nodoc:
616
+ attr_accessor :delegate #:nodoc:
617
+ attr_accessor :disable_ddl_transaction #:nodoc:
618
+
619
+ def nearest_delegate #:nodoc:
620
+ delegate || superclass.nearest_delegate
621
+ end
390
622
 
623
+ # Raises <tt>ActiveRecord::PendingMigrationError</tt> error if any migrations are pending.
391
624
  def check_pending!(connection = Base.connection)
392
- raise ActiveRecord::PendingMigrationError if ActiveRecord::Migrator.needs_migration?(connection)
625
+ raise ActiveRecord::PendingMigrationError if connection.migration_context.needs_migration?
393
626
  end
394
627
 
395
628
  def load_schema_if_pending!
396
- if ActiveRecord::Migrator.needs_migration? || !ActiveRecord::Migrator.any_migrations?
397
- # Roundrip to Rake to allow plugins to hook into database initialization.
398
- FileUtils.cd Rails.root do
399
- current_config = Base.connection_config
629
+ current_db_config = Base.connection_db_config
630
+ all_configs = ActiveRecord::Base.configurations.configs_for(env_name: Rails.env)
631
+
632
+ needs_update = !all_configs.all? do |db_config|
633
+ Tasks::DatabaseTasks.schema_up_to_date?(db_config, ActiveRecord::Base.schema_format)
634
+ end
635
+
636
+ if needs_update
637
+ # Roundtrip to Rake to allow plugins to hook into database initialization.
638
+ root = defined?(ENGINE_ROOT) ? ENGINE_ROOT : Rails.root
639
+ FileUtils.cd(root) do
400
640
  Base.clear_all_connections!
401
- system("bin/rake db:test:prepare")
402
- # Establish a new connection, the old database may be gone (db:test:prepare uses purge)
403
- Base.establish_connection(current_config)
641
+ system("bin/rails db:test:prepare")
404
642
  end
405
- check_pending!
406
643
  end
644
+
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!
407
649
  end
408
650
 
409
- def maintain_test_schema! # :nodoc:
651
+ def maintain_test_schema! #:nodoc:
410
652
  if ActiveRecord::Base.maintain_test_schema
411
653
  suppress_messages { load_schema_if_pending! }
412
654
  end
413
655
  end
414
656
 
415
- def method_missing(name, *args, &block) # :nodoc:
416
- (delegate || superclass.delegate).send(name, *args, &block)
657
+ def method_missing(name, *args, &block) #:nodoc:
658
+ nearest_delegate.send(name, *args, &block)
417
659
  end
660
+ ruby2_keywords(:method_missing) if respond_to?(:ruby2_keywords, true)
418
661
 
419
662
  def migrate(direction)
420
663
  new.migrate direction
@@ -429,7 +672,7 @@ module ActiveRecord
429
672
  end
430
673
  end
431
674
 
432
- def disable_ddl_transaction # :nodoc:
675
+ def disable_ddl_transaction #:nodoc:
433
676
  self.class.disable_ddl_transaction
434
677
  end
435
678
 
@@ -453,7 +696,7 @@ module ActiveRecord
453
696
  # and create the table 'apples' on the way up, and the reverse
454
697
  # on the way down.
455
698
  #
456
- # class FixTLMigration < ActiveRecord::Migration
699
+ # class FixTLMigration < ActiveRecord::Migration[6.0]
457
700
  # def change
458
701
  # revert do
459
702
  # create_table(:horses) do |t|
@@ -470,9 +713,9 @@ module ActiveRecord
470
713
  # Or equivalently, if +TenderloveMigration+ is defined as in the
471
714
  # documentation for Migration:
472
715
  #
473
- # require_relative '2012121212_tenderlove_migration'
716
+ # require_relative "20121212123456_tenderlove_migration"
474
717
  #
475
- # class FixupTLMigration < ActiveRecord::Migration
718
+ # class FixupTLMigration < ActiveRecord::Migration[6.0]
476
719
  # def change
477
720
  # revert TenderloveMigration
478
721
  #
@@ -486,27 +729,25 @@ module ActiveRecord
486
729
  def revert(*migration_classes)
487
730
  run(*migration_classes.reverse, revert: true) unless migration_classes.empty?
488
731
  if block_given?
489
- if @connection.respond_to? :revert
490
- @connection.revert { yield }
732
+ if connection.respond_to? :revert
733
+ connection.revert { yield }
491
734
  else
492
- recorder = CommandRecorder.new(@connection)
735
+ recorder = command_recorder
493
736
  @connection = recorder
494
737
  suppress_messages do
495
- @connection.revert { yield }
738
+ connection.revert { yield }
496
739
  end
497
740
  @connection = recorder.delegate
498
- recorder.commands.each do |cmd, args, block|
499
- send(cmd, *args, &block)
500
- end
741
+ recorder.replay(self)
501
742
  end
502
743
  end
503
744
  end
504
745
 
505
746
  def reverting?
506
- @connection.respond_to?(:reverting) && @connection.reverting
747
+ connection.respond_to?(:reverting) && connection.reverting
507
748
  end
508
749
 
509
- class ReversibleBlockHelper < Struct.new(:reverting) # :nodoc:
750
+ ReversibleBlockHelper = Struct.new(:reverting) do #:nodoc:
510
751
  def up
511
752
  yield unless reverting
512
753
  end
@@ -525,7 +766,7 @@ module ActiveRecord
525
766
  # when the three columns 'first_name', 'last_name' and 'full_name' exist,
526
767
  # even when migrating down:
527
768
  #
528
- # class SplitNameMigration < ActiveRecord::Migration
769
+ # class SplitNameMigration < ActiveRecord::Migration[6.0]
529
770
  # def change
530
771
  # add_column :users, :first_name, :string
531
772
  # add_column :users, :last_name, :string
@@ -544,7 +785,25 @@ module ActiveRecord
544
785
  # end
545
786
  def reversible
546
787
  helper = ReversibleBlockHelper.new(reverting?)
547
- execute_block{ yield helper }
788
+ execute_block { yield helper }
789
+ end
790
+
791
+ # Used to specify an operation that is only run when migrating up
792
+ # (for example, populating a new column with its initial values).
793
+ #
794
+ # In the following example, the new column +published+ will be given
795
+ # the value +true+ for all existing records.
796
+ #
797
+ # class AddPublishedToPosts < ActiveRecord::Migration[6.0]
798
+ # def change
799
+ # add_column :posts, :published, :boolean, default: false
800
+ # up_only do
801
+ # execute "update posts set published = 'true'"
802
+ # end
803
+ # end
804
+ # end
805
+ def up_only
806
+ execute_block { yield } unless reverting?
548
807
  end
549
808
 
550
809
  # Runs the given migration classes.
@@ -560,7 +819,7 @@ module ActiveRecord
560
819
  revert { run(*migration_classes, direction: dir, revert: true) }
561
820
  else
562
821
  migration_classes.each do |migration_class|
563
- migration_class.new.exec_migration(@connection, dir)
822
+ migration_class.new.exec_migration(connection, dir)
564
823
  end
565
824
  end
566
825
  end
@@ -586,7 +845,7 @@ module ActiveRecord
586
845
  when :down then announce "reverting"
587
846
  end
588
847
 
589
- time = nil
848
+ time = nil
590
849
  ActiveRecord::Base.connection_pool.with_connection do |conn|
591
850
  time = Benchmark.measure do
592
851
  exec_migration(conn, direction)
@@ -608,13 +867,13 @@ module ActiveRecord
608
867
  change
609
868
  end
610
869
  else
611
- send(direction)
870
+ public_send(direction)
612
871
  end
613
872
  ensure
614
873
  @connection = nil
615
874
  end
616
875
 
617
- def write(text="")
876
+ def write(text = "")
618
877
  puts(text) if verbose
619
878
  end
620
879
 
@@ -624,10 +883,14 @@ module ActiveRecord
624
883
  write "== %s %s" % [text, "=" * length]
625
884
  end
626
885
 
627
- def say(message, subitem=false)
886
+ # Takes a message argument and outputs it as is.
887
+ # A second boolean argument can be passed to specify whether to indent or not.
888
+ def say(message, subitem = false)
628
889
  write "#{subitem ? " ->" : "--"} #{message}"
629
890
  end
630
891
 
892
+ # Outputs text along with how long it took to run its block.
893
+ # If the block returns an integer it assumes it is the number of rows affected.
631
894
  def say_with_time(message)
632
895
  say(message)
633
896
  result = nil
@@ -637,6 +900,7 @@ module ActiveRecord
637
900
  result
638
901
  end
639
902
 
903
+ # Takes a block as an argument and suppresses any output generated by the block.
640
904
  def suppress_messages
641
905
  save, self.verbose = verbose, false
642
906
  yield
@@ -649,10 +913,10 @@ module ActiveRecord
649
913
  end
650
914
 
651
915
  def method_missing(method, *arguments, &block)
652
- arg_list = arguments.map{ |a| a.inspect } * ', '
916
+ arg_list = arguments.map(&:inspect) * ", "
653
917
 
654
918
  say_with_time "#{method}(#{arg_list})" do
655
- unless @connection.respond_to? :revert
919
+ unless connection.respond_to? :revert
656
920
  unless arguments.empty? || [:execute, :enable_extension, :disable_extension].include?(method)
657
921
  arguments[0] = proper_table_name(arguments.first, table_name_options)
658
922
  if [:rename_table, :add_foreign_key].include?(method) ||
@@ -665,29 +929,33 @@ module ActiveRecord
665
929
  connection.send(method, *arguments, &block)
666
930
  end
667
931
  end
932
+ ruby2_keywords(:method_missing) if respond_to?(:ruby2_keywords, true)
668
933
 
669
934
  def copy(destination, sources, options = {})
670
935
  copied = []
936
+ schema_migration = options[:schema_migration] || ActiveRecord::SchemaMigration
671
937
 
672
938
  FileUtils.mkdir_p(destination) unless File.exist?(destination)
673
939
 
674
- destination_migrations = ActiveRecord::Migrator.migrations(destination)
940
+ destination_migrations = ActiveRecord::MigrationContext.new(destination, schema_migration).migrations
675
941
  last = destination_migrations.last
676
942
  sources.each do |scope, path|
677
- source_migrations = ActiveRecord::Migrator.migrations(path)
943
+ source_migrations = ActiveRecord::MigrationContext.new(path, schema_migration).migrations
678
944
 
679
945
  source_migrations.each do |migration|
680
946
  source = File.binread(migration.filename)
681
947
  inserted_comment = "# This migration comes from #{scope} (originally #{migration.version})\n"
682
- if /\A#.*\b(?:en)?coding:\s*\S+/ =~ source
948
+ magic_comments = +""
949
+ loop do
683
950
  # If we have a magic comment in the original migration,
684
951
  # insert our comment after the first newline(end of the magic comment line)
685
952
  # so the magic keep working.
686
953
  # Note that magic comments must be at the first line(except sh-bang).
687
- source[/\n/] = "\n#{inserted_comment}"
688
- else
689
- source = "#{inserted_comment}#{source}"
954
+ source.sub!(/\A(?:#.*\b(?:en)?coding:\s*\S+|#\s*frozen_string_literal:\s*(?:true|false)).*\n/) do |magic_comment|
955
+ magic_comments << magic_comment; ""
956
+ end || break
690
957
  end
958
+ source = "#{magic_comments}#{inserted_comment}#{source}"
691
959
 
692
960
  if duplicate = destination_migrations.detect { |m| m.name == migration.name }
693
961
  if options[:on_skip] && duplicate.scope != scope.to_s
@@ -731,7 +999,9 @@ module ActiveRecord
731
999
  end
732
1000
  end
733
1001
 
734
- def table_name_options(config = ActiveRecord::Base)
1002
+ # Builds a hash for use in ActiveRecord::Migration#proper_table_name using
1003
+ # the Active Record object's table_name prefix and suffix
1004
+ def table_name_options(config = ActiveRecord::Base) #:nodoc:
735
1005
  {
736
1006
  table_name_prefix: config.table_name_prefix,
737
1007
  table_name_suffix: config.table_name_suffix
@@ -739,19 +1009,22 @@ module ActiveRecord
739
1009
  end
740
1010
 
741
1011
  private
742
- def execute_block
743
- if connection.respond_to? :execute_block
744
- super # use normal delegation to record the block
745
- else
746
- yield
1012
+ def execute_block
1013
+ if connection.respond_to? :execute_block
1014
+ super # use normal delegation to record the block
1015
+ else
1016
+ yield
1017
+ end
1018
+ end
1019
+
1020
+ def command_recorder
1021
+ CommandRecorder.new(connection)
747
1022
  end
748
- end
749
1023
  end
750
1024
 
751
1025
  # MigrationProxy is used to defer loading of the actual migration classes
752
1026
  # until they are needed
753
- class MigrationProxy < Struct.new(:name, :version, :filename, :scope)
754
-
1027
+ MigrationProxy = Struct.new(:name, :version, :filename, :scope) do
755
1028
  def initialize(name, version, filename, scope)
756
1029
  super
757
1030
  @migration = nil
@@ -761,14 +1034,9 @@ module ActiveRecord
761
1034
  File.basename(filename)
762
1035
  end
763
1036
 
764
- def mtime
765
- File.mtime filename
766
- end
767
-
768
1037
  delegate :migrate, :announce, :write, :disable_ddl_transaction, to: :migration
769
1038
 
770
1039
  private
771
-
772
1040
  def migration
773
1041
  @migration ||= load_migration
774
1042
  end
@@ -777,177 +1045,188 @@ module ActiveRecord
777
1045
  require(File.expand_path(filename))
778
1046
  name.constantize.new(name, version)
779
1047
  end
780
-
781
1048
  end
782
1049
 
783
- class NullMigration < MigrationProxy #:nodoc:
784
- def initialize
785
- super(nil, 0, nil, nil)
786
- end
1050
+ class MigrationContext #:nodoc:
1051
+ attr_reader :migrations_paths, :schema_migration
787
1052
 
788
- def mtime
789
- 0
1053
+ def initialize(migrations_paths, schema_migration)
1054
+ @migrations_paths = migrations_paths
1055
+ @schema_migration = schema_migration
790
1056
  end
791
- end
792
1057
 
793
- class Migrator#:nodoc:
794
- class << self
795
- attr_writer :migrations_paths
796
- alias :migrations_path= :migrations_paths=
797
-
798
- def migrate(migrations_paths, target_version = nil, &block)
799
- case
800
- when target_version.nil?
801
- up(migrations_paths, target_version, &block)
802
- when current_version == 0 && target_version == 0
803
- []
804
- when current_version > target_version
805
- down(migrations_paths, target_version, &block)
806
- else
807
- up(migrations_paths, target_version, &block)
808
- end
1058
+ def migrate(target_version = nil, &block)
1059
+ case
1060
+ when target_version.nil?
1061
+ up(target_version, &block)
1062
+ when current_version == 0 && target_version == 0
1063
+ []
1064
+ when current_version > target_version
1065
+ down(target_version, &block)
1066
+ else
1067
+ up(target_version, &block)
809
1068
  end
1069
+ end
810
1070
 
811
- def rollback(migrations_paths, steps=1)
812
- move(:down, migrations_paths, steps)
813
- end
1071
+ def rollback(steps = 1)
1072
+ move(:down, steps)
1073
+ end
1074
+
1075
+ def forward(steps = 1)
1076
+ move(:up, steps)
1077
+ end
814
1078
 
815
- def forward(migrations_paths, steps=1)
816
- move(:up, migrations_paths, steps)
1079
+ def up(target_version = nil)
1080
+ selected_migrations = if block_given?
1081
+ migrations.select { |m| yield m }
1082
+ else
1083
+ migrations
817
1084
  end
818
1085
 
819
- def up(migrations_paths, target_version = nil)
820
- migrations = migrations(migrations_paths)
821
- migrations.select! { |m| yield m } if block_given?
1086
+ Migrator.new(:up, selected_migrations, schema_migration, target_version).migrate
1087
+ end
822
1088
 
823
- new(:up, migrations, target_version).migrate
1089
+ def down(target_version = nil)
1090
+ selected_migrations = if block_given?
1091
+ migrations.select { |m| yield m }
1092
+ else
1093
+ migrations
824
1094
  end
825
1095
 
826
- def down(migrations_paths, target_version = nil, &block)
827
- migrations = migrations(migrations_paths)
828
- migrations.select! { |m| yield m } if block_given?
1096
+ Migrator.new(:down, selected_migrations, schema_migration, target_version).migrate
1097
+ end
829
1098
 
830
- new(:down, migrations, target_version).migrate
831
- end
1099
+ def run(direction, target_version)
1100
+ Migrator.new(direction, migrations, schema_migration, target_version).run
1101
+ end
832
1102
 
833
- def run(direction, migrations_paths, target_version)
834
- new(direction, migrations(migrations_paths), target_version).run
835
- end
1103
+ def open
1104
+ Migrator.new(:up, migrations, schema_migration)
1105
+ end
836
1106
 
837
- def open(migrations_paths)
838
- new(:up, migrations(migrations_paths), nil)
1107
+ def get_all_versions
1108
+ if schema_migration.table_exists?
1109
+ schema_migration.all_versions.map(&:to_i)
1110
+ else
1111
+ []
839
1112
  end
1113
+ end
840
1114
 
841
- def schema_migrations_table_name
842
- SchemaMigration.table_name
843
- end
1115
+ def current_version
1116
+ get_all_versions.max || 0
1117
+ rescue ActiveRecord::NoDatabaseError
1118
+ end
844
1119
 
845
- def get_all_versions(connection = Base.connection)
846
- if connection.table_exists?(schema_migrations_table_name)
847
- SchemaMigration.all.map { |x| x.version.to_i }.sort
848
- else
849
- []
850
- end
851
- end
1120
+ def needs_migration?
1121
+ (migrations.collect(&:version) - get_all_versions).size > 0
1122
+ end
852
1123
 
853
- def current_version(connection = Base.connection)
854
- get_all_versions(connection).max || 0
855
- end
1124
+ def any_migrations?
1125
+ migrations.any?
1126
+ end
856
1127
 
857
- def needs_migration?(connection = Base.connection)
858
- (migrations(migrations_paths).collect(&:version) - get_all_versions(connection)).size > 0
859
- end
1128
+ def migrations
1129
+ migrations = migration_files.map do |file|
1130
+ version, name, scope = parse_migration_filename(file)
1131
+ raise IllegalMigrationNameError.new(file) unless version
1132
+ version = version.to_i
1133
+ name = name.camelize
860
1134
 
861
- def any_migrations?
862
- migrations(migrations_paths).any?
1135
+ MigrationProxy.new(name, version, file, scope)
863
1136
  end
864
1137
 
865
- def last_version
866
- last_migration.version
867
- end
1138
+ migrations.sort_by(&:version)
1139
+ end
868
1140
 
869
- def last_migration #:nodoc:
870
- migrations(migrations_paths).last || NullMigration.new
871
- end
1141
+ def migrations_status
1142
+ db_list = schema_migration.normalized_versions
872
1143
 
873
- def migrations_paths
874
- @migrations_paths ||= ['db/migrate']
875
- # just to not break things if someone uses: migration_path = some_string
876
- Array(@migrations_paths)
877
- end
1144
+ file_list = migration_files.map do |file|
1145
+ version, name, scope = parse_migration_filename(file)
1146
+ raise IllegalMigrationNameError.new(file) unless version
1147
+ version = schema_migration.normalize_migration_number(version)
1148
+ status = db_list.delete(version) ? "up" : "down"
1149
+ [status, version, (name + scope).humanize]
1150
+ end.compact
878
1151
 
879
- def migrations_path
880
- migrations_paths.first
1152
+ db_list.map! do |version|
1153
+ ["up", version, "********** NO FILE **********"]
881
1154
  end
882
1155
 
883
- def parse_migration_filename(filename) # :nodoc:
884
- File.basename(filename).scan(/\A([0-9]+)_([_a-z0-9]*)\.?([_a-z0-9]*)?\.rb\z/).first
885
- end
1156
+ (db_list + file_list).sort_by { |_, version, _| version }
1157
+ end
886
1158
 
887
- def migrations(paths)
888
- paths = Array(paths)
1159
+ def current_environment
1160
+ ActiveRecord::ConnectionHandling::DEFAULT_ENV.call
1161
+ end
889
1162
 
890
- migrations = migration_files(paths).map do |file|
891
- version, name, scope = parse_migration_filename(file)
892
- raise IllegalMigrationNameError.new(file) unless version
893
- version = version.to_i
894
- name = name.camelize
1163
+ def protected_environment?
1164
+ ActiveRecord::Base.protected_environments.include?(last_stored_environment) if last_stored_environment
1165
+ end
895
1166
 
896
- MigrationProxy.new(name, version, file, scope)
897
- end
1167
+ def last_stored_environment
1168
+ return nil unless ActiveRecord::InternalMetadata.enabled?
1169
+ return nil if current_version == 0
1170
+ raise NoEnvironmentInSchemaError unless ActiveRecord::InternalMetadata.table_exists?
898
1171
 
899
- migrations.sort_by(&:version)
900
- end
1172
+ environment = ActiveRecord::InternalMetadata[:environment]
1173
+ raise NoEnvironmentInSchemaError unless environment
1174
+ environment
1175
+ end
901
1176
 
902
- def migrations_status(paths)
903
- paths = Array(paths)
1177
+ private
1178
+ def migration_files
1179
+ paths = Array(migrations_paths)
1180
+ Dir[*paths.flat_map { |path| "#{path}/**/[0-9]*_*.rb" }]
1181
+ end
904
1182
 
905
- db_list = ActiveRecord::SchemaMigration.normalized_versions
1183
+ def parse_migration_filename(filename)
1184
+ File.basename(filename).scan(Migration::MigrationFilenameRegexp).first
1185
+ end
906
1186
 
907
- file_list = migration_files(paths).map do |file|
908
- version, name, scope = parse_migration_filename(file)
909
- raise IllegalMigrationNameError.new(file) unless version
910
- version = ActiveRecord::SchemaMigration.normalize_migration_number(version)
911
- status = db_list.delete(version) ? "up" : "down"
912
- [status, version, (name + scope).humanize]
913
- end.compact
1187
+ def move(direction, steps)
1188
+ migrator = Migrator.new(direction, migrations, schema_migration)
914
1189
 
915
- db_list.map! do |version|
916
- ["up", version, "********** NO FILE **********"]
1190
+ if current_version != 0 && !migrator.current_migration
1191
+ raise UnknownMigrationVersionError.new(current_version)
917
1192
  end
918
1193
 
919
- (db_list + file_list).sort_by { |_, version, _| version }
920
- end
1194
+ start_index =
1195
+ if current_version == 0
1196
+ 0
1197
+ else
1198
+ migrator.migrations.index(migrator.current_migration)
1199
+ end
921
1200
 
922
- def migration_files(paths)
923
- Dir[*paths.flat_map { |path| "#{path}/**/[0-9]*_*.rb" }]
1201
+ finish = migrator.migrations[start_index + steps]
1202
+ version = finish ? finish.version : 0
1203
+ public_send(direction, version)
924
1204
  end
1205
+ end
925
1206
 
926
- private
927
-
928
- def move(direction, migrations_paths, steps)
929
- migrator = new(direction, migrations(migrations_paths))
930
- start_index = migrator.migrations.index(migrator.current_migration)
1207
+ class Migrator # :nodoc:
1208
+ class << self
1209
+ attr_accessor :migrations_paths
931
1210
 
932
- if start_index
933
- finish = migrator.migrations[start_index + steps]
934
- version = finish ? finish.version : 0
935
- send(direction, migrations_paths, version)
936
- end
1211
+ # For cases where a table doesn't exist like loading from schema cache
1212
+ def current_version
1213
+ MigrationContext.new(migrations_paths, SchemaMigration).current_version
937
1214
  end
938
1215
  end
939
1216
 
940
- def initialize(direction, migrations, target_version = nil)
941
- raise StandardError.new("This database does not yet support migrations") unless Base.connection.supports_migrations?
1217
+ self.migrations_paths = ["db/migrate"]
942
1218
 
1219
+ def initialize(direction, migrations, schema_migration, target_version = nil)
943
1220
  @direction = direction
944
1221
  @target_version = target_version
945
1222
  @migrated_versions = nil
946
1223
  @migrations = migrations
1224
+ @schema_migration = schema_migration
947
1225
 
948
1226
  validate(@migrations)
949
1227
 
950
- Base.connection.initialize_schema_migrations_table
1228
+ @schema_migration.create_table
1229
+ ActiveRecord::InternalMetadata.create_table
951
1230
  end
952
1231
 
953
1232
  def current_version
@@ -960,32 +1239,18 @@ module ActiveRecord
960
1239
  alias :current :current_migration
961
1240
 
962
1241
  def run
963
- migration = migrations.detect { |m| m.version == @target_version }
964
- raise UnknownMigrationVersionError.new(@target_version) if migration.nil?
965
- unless (up? && migrated.include?(migration.version.to_i)) || (down? && !migrated.include?(migration.version.to_i))
966
- begin
967
- execute_migration_in_transaction(migration, @direction)
968
- rescue => e
969
- canceled_msg = use_transaction?(migration) ? ", this migration was canceled" : ""
970
- raise StandardError, "An error has occurred#{canceled_msg}:\n\n#{e}", e.backtrace
971
- end
1242
+ if use_advisory_lock?
1243
+ with_advisory_lock { run_without_lock }
1244
+ else
1245
+ run_without_lock
972
1246
  end
973
1247
  end
974
1248
 
975
1249
  def migrate
976
- if !target && @target_version && @target_version > 0
977
- raise UnknownMigrationVersionError.new(@target_version)
978
- end
979
-
980
- runnable.each do |migration|
981
- Base.logger.info "Migrating to #{migration.name} (#{migration.version})" if Base.logger
982
-
983
- begin
984
- execute_migration_in_transaction(migration, @direction)
985
- rescue => e
986
- canceled_msg = use_transaction?(migration) ? "this and " : ""
987
- raise StandardError, "An error has occurred, #{canceled_msg}all later migrations canceled:\n\n#{e}", e.backtrace
988
- end
1250
+ if use_advisory_lock?
1251
+ with_advisory_lock { migrate_without_lock }
1252
+ else
1253
+ migrate_without_lock
989
1254
  end
990
1255
  end
991
1256
 
@@ -1010,70 +1275,153 @@ module ActiveRecord
1010
1275
  end
1011
1276
 
1012
1277
  def migrated
1013
- @migrated_versions ||= Set.new(self.class.get_all_versions)
1278
+ @migrated_versions || load_migrated
1014
1279
  end
1015
1280
 
1016
- private
1017
- def ran?(migration)
1018
- migrated.include?(migration.version.to_i)
1281
+ def load_migrated
1282
+ @migrated_versions = Set.new(@schema_migration.all_versions.map(&:to_i))
1019
1283
  end
1020
1284
 
1021
- def execute_migration_in_transaction(migration, direction)
1022
- ddl_transaction(migration) do
1023
- migration.migrate(direction)
1024
- record_version_state_after_migrating(migration.version)
1285
+ private
1286
+ # Used for running a specific migration.
1287
+ def run_without_lock
1288
+ migration = migrations.detect { |m| m.version == @target_version }
1289
+ raise UnknownMigrationVersionError.new(@target_version) if migration.nil?
1290
+ result = execute_migration_in_transaction(migration)
1291
+
1292
+ record_environment
1293
+ result
1025
1294
  end
1026
- end
1027
1295
 
1028
- def target
1029
- migrations.detect { |m| m.version == @target_version }
1030
- end
1296
+ # Used for running multiple migrations up to or down to a certain value.
1297
+ def migrate_without_lock
1298
+ if invalid_target?
1299
+ raise UnknownMigrationVersionError.new(@target_version)
1300
+ end
1031
1301
 
1032
- def finish
1033
- migrations.index(target) || migrations.size - 1
1034
- end
1302
+ result = runnable.each(&method(:execute_migration_in_transaction))
1303
+ record_environment
1304
+ result
1305
+ end
1035
1306
 
1036
- def start
1037
- up? ? 0 : (migrations.index(current) || 0)
1038
- end
1307
+ # Stores the current environment in the database.
1308
+ def record_environment
1309
+ return if down?
1310
+ ActiveRecord::InternalMetadata[:environment] = ActiveRecord::Base.connection.migration_context.current_environment
1311
+ end
1039
1312
 
1040
- def validate(migrations)
1041
- name ,= migrations.group_by(&:name).find { |_,v| v.length > 1 }
1042
- raise DuplicateMigrationNameError.new(name) if name
1313
+ def ran?(migration)
1314
+ migrated.include?(migration.version.to_i)
1315
+ end
1043
1316
 
1044
- version ,= migrations.group_by(&:version).find { |_,v| v.length > 1 }
1045
- raise DuplicateMigrationVersionError.new(version) if version
1046
- end
1317
+ # Return true if a valid version is not provided.
1318
+ def invalid_target?
1319
+ @target_version && @target_version != 0 && !target
1320
+ end
1047
1321
 
1048
- def record_version_state_after_migrating(version)
1049
- if down?
1050
- migrated.delete(version)
1051
- ActiveRecord::SchemaMigration.where(:version => version.to_s).delete_all
1052
- else
1053
- migrated << version
1054
- ActiveRecord::SchemaMigration.create!(:version => version.to_s)
1322
+ def execute_migration_in_transaction(migration)
1323
+ return if down? && !migrated.include?(migration.version.to_i)
1324
+ return if up? && migrated.include?(migration.version.to_i)
1325
+
1326
+ Base.logger.info "Migrating to #{migration.name} (#{migration.version})" if Base.logger
1327
+
1328
+ ddl_transaction(migration) do
1329
+ migration.migrate(@direction)
1330
+ record_version_state_after_migrating(migration.version)
1331
+ end
1332
+ rescue => e
1333
+ msg = +"An error has occurred, "
1334
+ msg << "this and " if use_transaction?(migration)
1335
+ msg << "all later migrations canceled:\n\n#{e}"
1336
+ raise StandardError, msg, e.backtrace
1055
1337
  end
1056
- end
1057
1338
 
1058
- def up?
1059
- @direction == :up
1060
- end
1339
+ def target
1340
+ migrations.detect { |m| m.version == @target_version }
1341
+ end
1061
1342
 
1062
- def down?
1063
- @direction == :down
1064
- end
1343
+ def finish
1344
+ migrations.index(target) || migrations.size - 1
1345
+ end
1065
1346
 
1066
- # Wrap the migration in a transaction only if supported by the adapter.
1067
- def ddl_transaction(migration)
1068
- if use_transaction?(migration)
1069
- Base.transaction { yield }
1070
- else
1071
- yield
1347
+ def start
1348
+ up? ? 0 : (migrations.index(current) || 0)
1072
1349
  end
1073
- end
1074
1350
 
1075
- def use_transaction?(migration)
1076
- !migration.disable_ddl_transaction && Base.connection.supports_ddl_transactions?
1077
- end
1351
+ def validate(migrations)
1352
+ name, = migrations.group_by(&:name).find { |_, v| v.length > 1 }
1353
+ raise DuplicateMigrationNameError.new(name) if name
1354
+
1355
+ version, = migrations.group_by(&:version).find { |_, v| v.length > 1 }
1356
+ raise DuplicateMigrationVersionError.new(version) if version
1357
+ end
1358
+
1359
+ def record_version_state_after_migrating(version)
1360
+ if down?
1361
+ migrated.delete(version)
1362
+ @schema_migration.delete_by(version: version.to_s)
1363
+ else
1364
+ migrated << version
1365
+ @schema_migration.create!(version: version.to_s)
1366
+ end
1367
+ end
1368
+
1369
+ def up?
1370
+ @direction == :up
1371
+ end
1372
+
1373
+ def down?
1374
+ @direction == :down
1375
+ end
1376
+
1377
+ # Wrap the migration in a transaction only if supported by the adapter.
1378
+ def ddl_transaction(migration)
1379
+ if use_transaction?(migration)
1380
+ Base.transaction { yield }
1381
+ else
1382
+ yield
1383
+ end
1384
+ end
1385
+
1386
+ def use_transaction?(migration)
1387
+ !migration.disable_ddl_transaction && Base.connection.supports_ddl_transactions?
1388
+ end
1389
+
1390
+ def use_advisory_lock?
1391
+ Base.connection.advisory_locks_enabled?
1392
+ end
1393
+
1394
+ def with_advisory_lock
1395
+ lock_id = generate_migrator_advisory_lock_id
1396
+
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) }
1417
+ ensure
1418
+ pool&.disconnect!
1419
+ end
1420
+
1421
+ MIGRATOR_SALT = 2053462845
1422
+ def generate_migrator_advisory_lock_id
1423
+ db_name_hash = Zlib.crc32(Base.connection.current_database)
1424
+ MIGRATOR_SALT * db_name_hash
1425
+ end
1078
1426
  end
1079
1427
  end