activerecord 4.2.0 → 6.1.7.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (374) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG.md +1221 -796
  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 +267 -249
  8. data/lib/active_record/association_relation.rb +45 -7
  9. data/lib/active_record/associations/alias_tracker.rb +40 -43
  10. data/lib/active_record/associations/association.rb +172 -67
  11. data/lib/active_record/associations/association_scope.rb +105 -129
  12. data/lib/active_record/associations/belongs_to_association.rb +85 -59
  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 -33
  17. data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +57 -70
  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 +168 -279
  22. data/lib/active_record/associations/collection_proxy.rb +263 -155
  23. data/lib/active_record/associations/foreign_association.rb +33 -0
  24. data/lib/active_record/associations/has_many_association.rb +57 -84
  25. data/lib/active_record/associations/has_many_through_association.rb +70 -82
  26. data/lib/active_record/associations/has_one_association.rb +74 -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 -73
  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 +175 -164
  32. data/lib/active_record/associations/preloader/association.rb +107 -112
  33. data/lib/active_record/associations/preloader/through_association.rb +85 -65
  34. data/lib/active_record/associations/preloader.rb +99 -96
  35. data/lib/active_record/associations/singular_association.rb +18 -45
  36. data/lib/active_record/associations/through_association.rb +49 -24
  37. data/lib/active_record/associations.rb +1845 -1597
  38. data/lib/active_record/attribute_assignment.rb +59 -185
  39. data/lib/active_record/attribute_methods/before_type_cast.rb +20 -7
  40. data/lib/active_record/attribute_methods/dirty.rb +168 -138
  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 +59 -36
  46. data/lib/active_record/attribute_methods/write.rb +25 -56
  47. data/lib/active_record/attribute_methods.rb +153 -162
  48. data/lib/active_record/attributes.rb +234 -70
  49. data/lib/active_record/autosave_association.rb +157 -69
  50. data/lib/active_record/base.rb +49 -50
  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 +46 -13
  54. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +887 -317
  55. data/lib/active_record/connection_adapters/abstract/database_limits.rb +17 -41
  56. data/lib/active_record/connection_adapters/abstract/database_statements.rb +301 -113
  57. data/lib/active_record/connection_adapters/abstract/query_cache.rb +78 -24
  58. data/lib/active_record/connection_adapters/abstract/quoting.rb +187 -60
  59. data/lib/active_record/connection_adapters/abstract/savepoints.rb +9 -7
  60. data/lib/active_record/connection_adapters/abstract/schema_creation.rb +157 -93
  61. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +485 -253
  62. data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +79 -36
  63. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +909 -263
  64. data/lib/active_record/connection_adapters/abstract/transaction.rb +254 -92
  65. data/lib/active_record/connection_adapters/abstract_adapter.rb +492 -221
  66. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +580 -608
  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 +196 -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 +271 -0
  78. data/lib/active_record/connection_adapters/mysql/type_metadata.rb +40 -0
  79. data/lib/active_record/connection_adapters/mysql2_adapter.rb +81 -199
  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 +78 -161
  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 -57
  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 +5 -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 +17 -13
  92. data/lib/active_record/connection_adapters/postgresql/oid/decimal.rb +3 -1
  93. data/lib/active_record/connection_adapters/postgresql/oid/enum.rb +6 -3
  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 -1
  105. data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +67 -51
  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 +171 -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 +499 -293
  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 +595 -382
  119. data/lib/active_record/connection_adapters/schema_cache.rb +191 -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 +146 -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 -389
  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 +488 -243
  133. data/lib/active_record/counter_cache.rb +71 -50
  134. data/lib/active_record/database_configurations/connection_url_resolver.rb +99 -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 +273 -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 +212 -94
  143. data/lib/active_record/errors.rb +225 -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 +11 -6
  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 +273 -496
  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 +64 -0
  158. data/lib/active_record/legacy_yaml_adapter.rb +52 -0
  159. data/lib/active_record/locale/en.yml +3 -2
  160. data/lib/active_record/locking/optimistic.rb +103 -95
  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 +298 -0
  168. data/lib/active_record/migration/join_table.rb +8 -7
  169. data/lib/active_record/migration.rb +685 -309
  170. data/lib/active_record/model_schema.rb +420 -113
  171. data/lib/active_record/nested_attributes.rb +265 -216
  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 +574 -135
  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 +175 -54
  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 +533 -216
  181. data/lib/active_record/readonly_attributes.rb +9 -4
  182. data/lib/active_record/reflection.rb +485 -310
  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 +326 -244
  186. data/lib/active_record/relation/delegation.rb +76 -84
  187. data/lib/active_record/relation/finder_methods.rb +318 -256
  188. data/lib/active_record/relation/from_clause.rb +30 -0
  189. data/lib/active_record/relation/merger.rb +99 -84
  190. data/lib/active_record/relation/predicate_builder/array_handler.rb +26 -25
  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 +139 -96
  197. data/lib/active_record/relation/query_attribute.rb +50 -0
  198. data/lib/active_record/relation/query_methods.rb +757 -409
  199. data/lib/active_record/relation/record_fetch_warning.rb +51 -0
  200. data/lib/active_record/relation/spawn_methods.rb +23 -21
  201. data/lib/active_record/relation/where_clause.rb +239 -0
  202. data/lib/active_record/relation.rb +554 -342
  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 -26
  209. data/lib/active_record/scoping/default.rb +96 -82
  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 +133 -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 +366 -129
  220. data/lib/active_record/tasks/mysql_database_tasks.rb +68 -100
  221. data/lib/active_record/tasks/postgresql_database_tasks.rb +87 -39
  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 +291 -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 +181 -152
  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 -41
  231. data/lib/active_record/type/date_time.rb +4 -38
  232. data/lib/active_record/type/decimal_without_scale.rb +6 -2
  233. data/lib/active_record/type/hash_lookup_type_map.rb +12 -5
  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 +33 -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 +65 -48
  251. data/lib/active_record/validations.rb +39 -35
  252. data/lib/active_record/version.rb +3 -1
  253. data/lib/active_record.rb +44 -28
  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 -10
  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.rb +7 -5
  339. metadata +175 -65
  340. data/lib/active_record/associations/preloader/belongs_to.rb +0 -17
  341. data/lib/active_record/associations/preloader/collection_association.rb +0 -24
  342. data/lib/active_record/associations/preloader/has_many.rb +0 -17
  343. data/lib/active_record/associations/preloader/has_many_through.rb +0 -19
  344. data/lib/active_record/associations/preloader/has_one.rb +0 -23
  345. data/lib/active_record/associations/preloader/has_one_through.rb +0 -9
  346. data/lib/active_record/associations/preloader/singular_association.rb +0 -21
  347. data/lib/active_record/attribute.rb +0 -149
  348. data/lib/active_record/attribute_decorators.rb +0 -66
  349. data/lib/active_record/attribute_set/builder.rb +0 -86
  350. data/lib/active_record/attribute_set.rb +0 -77
  351. data/lib/active_record/connection_adapters/connection_specification.rb +0 -275
  352. data/lib/active_record/connection_adapters/mysql_adapter.rb +0 -491
  353. data/lib/active_record/connection_adapters/postgresql/array_parser.rb +0 -93
  354. data/lib/active_record/connection_adapters/postgresql/oid/float.rb +0 -21
  355. data/lib/active_record/connection_adapters/postgresql/oid/integer.rb +0 -11
  356. data/lib/active_record/connection_adapters/postgresql/oid/json.rb +0 -35
  357. data/lib/active_record/connection_adapters/postgresql/oid/time.rb +0 -11
  358. data/lib/active_record/railties/jdbcmysql_error.rb +0 -16
  359. data/lib/active_record/serializers/xml_serializer.rb +0 -193
  360. data/lib/active_record/type/big_integer.rb +0 -13
  361. data/lib/active_record/type/binary.rb +0 -50
  362. data/lib/active_record/type/boolean.rb +0 -30
  363. data/lib/active_record/type/decimal.rb +0 -40
  364. data/lib/active_record/type/decorator.rb +0 -14
  365. data/lib/active_record/type/float.rb +0 -19
  366. data/lib/active_record/type/integer.rb +0 -55
  367. data/lib/active_record/type/mutable.rb +0 -16
  368. data/lib/active_record/type/numeric.rb +0 -36
  369. data/lib/active_record/type/string.rb +0 -36
  370. data/lib/active_record/type/time_value.rb +0 -38
  371. data/lib/active_record/type/value.rb +0 -101
  372. data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb +0 -22
  373. data/lib/rails/generators/active_record/model/templates/model.rb +0 -10
  374. /data/lib/rails/generators/active_record/model/templates/{module.rb → module.rb.tt} +0 -0
@@ -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
31
120
  end
32
121
  end
33
122
 
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)")
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
37
130
  end
38
131
  end
39
132
 
40
- class PendingMigrationError < MigrationError#:nodoc:
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
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
166
+ end
167
+
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
174
+ end
175
+ end
176
+
177
+ class NoEnvironmentInSchemaError < MigrationError #:nodoc:
41
178
  def initialize
42
- if defined?(Rails)
43
- super("Migrations are pending. To resolve this issue, run:\n\n\tbin/rake db:migrate RAILS_ENV=#{::Rails.env}")
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"
203
+ if defined?(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:
@@ -307,15 +497,14 @@ module ActiveRecord
307
497
  #
308
498
  # == Reversible Migrations
309
499
  #
310
- # Starting with Rails 3.1, you will be able to define reversible migrations.
311
500
  # Reversible migrations are migrations that know how to go +down+ for you.
312
- # You simply supply the +up+ logic, and the Migration system will figure out
501
+ # You simply supply the +up+ logic, and the Migration system figures out
313
502
  # how to execute the down commands for you.
314
503
  #
315
504
  # To define a reversible migration, define the +change+ method in your
316
505
  # migration like this:
317
506
  #
318
- # class TenderloveMigration < ActiveRecord::Migration
507
+ # class TenderloveMigration < ActiveRecord::Migration[6.0]
319
508
  # def change
320
509
  # create_table(:horses) do |t|
321
510
  # t.column :content, :text
@@ -327,9 +516,9 @@ module ActiveRecord
327
516
  # This migration will create the horses table for you on the way up, and
328
517
  # automatically figure out how to drop the table on the way down.
329
518
  #
330
- # Some commands like +remove_column+ cannot be reversed. If you care to
331
- # define how to move up and down in these cases, you should define the +up+
332
- # 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.
333
522
  #
334
523
  # If a command cannot be reversed, an
335
524
  # <tt>ActiveRecord::IrreversibleMigration</tt> exception will be raised when
@@ -345,7 +534,7 @@ module ActiveRecord
345
534
  # can't execute inside a transaction though, and for these situations
346
535
  # you can turn the automatic transactions off.
347
536
  #
348
- # class ChangeEnum < ActiveRecord::Migration
537
+ # class ChangeEnum < ActiveRecord::Migration[6.0]
349
538
  # disable_ddl_transaction!
350
539
  #
351
540
  # def up
@@ -356,78 +545,134 @@ module ActiveRecord
356
545
  # Remember that you can still open your own transactions, even if you
357
546
  # are in a Migration with <tt>self.disable_ddl_transaction!</tt>.
358
547
  class Migration
359
- 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"
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
360
573
 
574
+ MigrationFilenameRegexp = /\A([0-9]+)_([_a-z0-9]*)\.?([_a-z0-9]*)?\.rb\z/ #:nodoc:
361
575
 
362
576
  # This class is used to verify that all migrations have been run before
363
- # 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
364
578
  class CheckPending
365
- def initialize(app)
579
+ def initialize(app, file_watcher: ActiveSupport::FileUpdateChecker)
366
580
  @app = app
367
- @last_check = 0
581
+ @needs_check = true
582
+ @mutex = Mutex.new
583
+ @file_watcher = file_watcher
368
584
  end
369
585
 
370
586
  def call(env)
371
- if connection.supports_migrations?
372
- mtime = ActiveRecord::Migrator.last_migration.mtime.to_i
373
- if @last_check < mtime
587
+ @mutex.synchronize do
588
+ @watcher ||= build_watcher do
589
+ @needs_check = true
374
590
  ActiveRecord::Migration.check_pending!(connection)
375
- @last_check = mtime
591
+ @needs_check = false
592
+ end
593
+
594
+ if @needs_check
595
+ @watcher.execute
596
+ else
597
+ @watcher.execute_if_updated
376
598
  end
377
599
  end
600
+
378
601
  @app.call(env)
379
602
  end
380
603
 
381
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
382
609
 
383
- def connection
384
- ActiveRecord::Base.connection
385
- end
610
+ def connection
611
+ ActiveRecord::Base.connection
612
+ end
386
613
  end
387
614
 
388
615
  class << self
389
- attr_accessor :delegate # :nodoc:
390
- 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
391
622
 
623
+ # Raises <tt>ActiveRecord::PendingMigrationError</tt> error if any migrations are pending.
392
624
  def check_pending!(connection = Base.connection)
393
- raise ActiveRecord::PendingMigrationError if ActiveRecord::Migrator.needs_migration?(connection)
625
+ raise ActiveRecord::PendingMigrationError if connection.migration_context.needs_migration?
394
626
  end
395
627
 
396
628
  def load_schema_if_pending!
397
- if ActiveRecord::Migrator.needs_migration? || !ActiveRecord::Migrator.any_migrations?
398
- # Roundrip to Rake to allow plugins to hook into database initialization.
399
- FileUtils.cd Rails.root do
400
- 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
401
640
  Base.clear_all_connections!
402
- system("bin/rake db:test:prepare")
403
- # Establish a new connection, the old database may be gone (db:test:prepare uses purge)
404
- Base.establish_connection(current_config)
641
+ system("bin/rails db:test:prepare")
405
642
  end
406
- check_pending!
407
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!
408
649
  end
409
650
 
410
- def maintain_test_schema! # :nodoc:
651
+ def maintain_test_schema! #:nodoc:
411
652
  if ActiveRecord::Base.maintain_test_schema
412
653
  suppress_messages { load_schema_if_pending! }
413
654
  end
414
655
  end
415
656
 
416
- def method_missing(name, *args, &block) # :nodoc:
417
- (delegate || superclass.delegate).send(name, *args, &block)
657
+ def method_missing(name, *args, &block) #:nodoc:
658
+ nearest_delegate.send(name, *args, &block)
418
659
  end
660
+ ruby2_keywords(:method_missing) if respond_to?(:ruby2_keywords, true)
419
661
 
420
662
  def migrate(direction)
421
663
  new.migrate direction
422
664
  end
423
665
 
424
- # Disable DDL transactions for this migration.
666
+ # Disable the transaction wrapping this migration.
667
+ # You can still create your own transactions even after calling #disable_ddl_transaction!
668
+ #
669
+ # For more details read the {"Transactional Migrations" section above}[rdoc-ref:Migration].
425
670
  def disable_ddl_transaction!
426
671
  @disable_ddl_transaction = true
427
672
  end
428
673
  end
429
674
 
430
- def disable_ddl_transaction # :nodoc:
675
+ def disable_ddl_transaction #:nodoc:
431
676
  self.class.disable_ddl_transaction
432
677
  end
433
678
 
@@ -451,7 +696,7 @@ module ActiveRecord
451
696
  # and create the table 'apples' on the way up, and the reverse
452
697
  # on the way down.
453
698
  #
454
- # class FixTLMigration < ActiveRecord::Migration
699
+ # class FixTLMigration < ActiveRecord::Migration[6.0]
455
700
  # def change
456
701
  # revert do
457
702
  # create_table(:horses) do |t|
@@ -468,9 +713,9 @@ module ActiveRecord
468
713
  # Or equivalently, if +TenderloveMigration+ is defined as in the
469
714
  # documentation for Migration:
470
715
  #
471
- # require_relative '2012121212_tenderlove_migration'
716
+ # require_relative "20121212123456_tenderlove_migration"
472
717
  #
473
- # class FixupTLMigration < ActiveRecord::Migration
718
+ # class FixupTLMigration < ActiveRecord::Migration[6.0]
474
719
  # def change
475
720
  # revert TenderloveMigration
476
721
  #
@@ -484,27 +729,25 @@ module ActiveRecord
484
729
  def revert(*migration_classes)
485
730
  run(*migration_classes.reverse, revert: true) unless migration_classes.empty?
486
731
  if block_given?
487
- if @connection.respond_to? :revert
488
- @connection.revert { yield }
732
+ if connection.respond_to? :revert
733
+ connection.revert { yield }
489
734
  else
490
- recorder = CommandRecorder.new(@connection)
735
+ recorder = command_recorder
491
736
  @connection = recorder
492
737
  suppress_messages do
493
- @connection.revert { yield }
738
+ connection.revert { yield }
494
739
  end
495
740
  @connection = recorder.delegate
496
- recorder.commands.each do |cmd, args, block|
497
- send(cmd, *args, &block)
498
- end
741
+ recorder.replay(self)
499
742
  end
500
743
  end
501
744
  end
502
745
 
503
746
  def reverting?
504
- @connection.respond_to?(:reverting) && @connection.reverting
747
+ connection.respond_to?(:reverting) && connection.reverting
505
748
  end
506
749
 
507
- class ReversibleBlockHelper < Struct.new(:reverting) # :nodoc:
750
+ ReversibleBlockHelper = Struct.new(:reverting) do #:nodoc:
508
751
  def up
509
752
  yield unless reverting
510
753
  end
@@ -523,7 +766,7 @@ module ActiveRecord
523
766
  # when the three columns 'first_name', 'last_name' and 'full_name' exist,
524
767
  # even when migrating down:
525
768
  #
526
- # class SplitNameMigration < ActiveRecord::Migration
769
+ # class SplitNameMigration < ActiveRecord::Migration[6.0]
527
770
  # def change
528
771
  # add_column :users, :first_name, :string
529
772
  # add_column :users, :last_name, :string
@@ -542,7 +785,25 @@ module ActiveRecord
542
785
  # end
543
786
  def reversible
544
787
  helper = ReversibleBlockHelper.new(reverting?)
545
- 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?
546
807
  end
547
808
 
548
809
  # Runs the given migration classes.
@@ -558,7 +819,7 @@ module ActiveRecord
558
819
  revert { run(*migration_classes, direction: dir, revert: true) }
559
820
  else
560
821
  migration_classes.each do |migration_class|
561
- migration_class.new.exec_migration(@connection, dir)
822
+ migration_class.new.exec_migration(connection, dir)
562
823
  end
563
824
  end
564
825
  end
@@ -584,7 +845,7 @@ module ActiveRecord
584
845
  when :down then announce "reverting"
585
846
  end
586
847
 
587
- time = nil
848
+ time = nil
588
849
  ActiveRecord::Base.connection_pool.with_connection do |conn|
589
850
  time = Benchmark.measure do
590
851
  exec_migration(conn, direction)
@@ -606,13 +867,13 @@ module ActiveRecord
606
867
  change
607
868
  end
608
869
  else
609
- send(direction)
870
+ public_send(direction)
610
871
  end
611
872
  ensure
612
873
  @connection = nil
613
874
  end
614
875
 
615
- def write(text="")
876
+ def write(text = "")
616
877
  puts(text) if verbose
617
878
  end
618
879
 
@@ -622,10 +883,14 @@ module ActiveRecord
622
883
  write "== %s %s" % [text, "=" * length]
623
884
  end
624
885
 
625
- 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)
626
889
  write "#{subitem ? " ->" : "--"} #{message}"
627
890
  end
628
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.
629
894
  def say_with_time(message)
630
895
  say(message)
631
896
  result = nil
@@ -635,6 +900,7 @@ module ActiveRecord
635
900
  result
636
901
  end
637
902
 
903
+ # Takes a block as an argument and suppresses any output generated by the block.
638
904
  def suppress_messages
639
905
  save, self.verbose = verbose, false
640
906
  yield
@@ -647,13 +913,14 @@ module ActiveRecord
647
913
  end
648
914
 
649
915
  def method_missing(method, *arguments, &block)
650
- arg_list = arguments.map{ |a| a.inspect } * ', '
916
+ arg_list = arguments.map(&:inspect) * ", "
651
917
 
652
918
  say_with_time "#{method}(#{arg_list})" do
653
- unless @connection.respond_to? :revert
919
+ unless connection.respond_to? :revert
654
920
  unless arguments.empty? || [:execute, :enable_extension, :disable_extension].include?(method)
655
921
  arguments[0] = proper_table_name(arguments.first, table_name_options)
656
- if [:rename_table, :add_foreign_key].include?(method)
922
+ if [:rename_table, :add_foreign_key].include?(method) ||
923
+ (method == :remove_foreign_key && !arguments.second.is_a?(Hash))
657
924
  arguments[1] = proper_table_name(arguments.second, table_name_options)
658
925
  end
659
926
  end
@@ -662,29 +929,33 @@ module ActiveRecord
662
929
  connection.send(method, *arguments, &block)
663
930
  end
664
931
  end
932
+ ruby2_keywords(:method_missing) if respond_to?(:ruby2_keywords, true)
665
933
 
666
934
  def copy(destination, sources, options = {})
667
935
  copied = []
936
+ schema_migration = options[:schema_migration] || ActiveRecord::SchemaMigration
668
937
 
669
938
  FileUtils.mkdir_p(destination) unless File.exist?(destination)
670
939
 
671
- destination_migrations = ActiveRecord::Migrator.migrations(destination)
940
+ destination_migrations = ActiveRecord::MigrationContext.new(destination, schema_migration).migrations
672
941
  last = destination_migrations.last
673
942
  sources.each do |scope, path|
674
- source_migrations = ActiveRecord::Migrator.migrations(path)
943
+ source_migrations = ActiveRecord::MigrationContext.new(path, schema_migration).migrations
675
944
 
676
945
  source_migrations.each do |migration|
677
946
  source = File.binread(migration.filename)
678
947
  inserted_comment = "# This migration comes from #{scope} (originally #{migration.version})\n"
679
- if /\A#.*\b(?:en)?coding:\s*\S+/ =~ source
948
+ magic_comments = +""
949
+ loop do
680
950
  # If we have a magic comment in the original migration,
681
951
  # insert our comment after the first newline(end of the magic comment line)
682
952
  # so the magic keep working.
683
953
  # Note that magic comments must be at the first line(except sh-bang).
684
- source[/\n/] = "\n#{inserted_comment}"
685
- else
686
- 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
687
957
  end
958
+ source = "#{magic_comments}#{inserted_comment}#{source}"
688
959
 
689
960
  if duplicate = destination_migrations.detect { |m| m.name == migration.name }
690
961
  if options[:on_skip] && duplicate.scope != scope.to_s
@@ -728,7 +999,9 @@ module ActiveRecord
728
999
  end
729
1000
  end
730
1001
 
731
- 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:
732
1005
  {
733
1006
  table_name_prefix: config.table_name_prefix,
734
1007
  table_name_suffix: config.table_name_suffix
@@ -736,19 +1009,22 @@ module ActiveRecord
736
1009
  end
737
1010
 
738
1011
  private
739
- def execute_block
740
- if connection.respond_to? :execute_block
741
- super # use normal delegation to record the block
742
- else
743
- 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)
744
1022
  end
745
- end
746
1023
  end
747
1024
 
748
1025
  # MigrationProxy is used to defer loading of the actual migration classes
749
1026
  # until they are needed
750
- class MigrationProxy < Struct.new(:name, :version, :filename, :scope)
751
-
1027
+ MigrationProxy = Struct.new(:name, :version, :filename, :scope) do
752
1028
  def initialize(name, version, filename, scope)
753
1029
  super
754
1030
  @migration = nil
@@ -758,14 +1034,9 @@ module ActiveRecord
758
1034
  File.basename(filename)
759
1035
  end
760
1036
 
761
- def mtime
762
- File.mtime filename
763
- end
764
-
765
1037
  delegate :migrate, :announce, :write, :disable_ddl_transaction, to: :migration
766
1038
 
767
1039
  private
768
-
769
1040
  def migration
770
1041
  @migration ||= load_migration
771
1042
  end
@@ -774,152 +1045,188 @@ module ActiveRecord
774
1045
  require(File.expand_path(filename))
775
1046
  name.constantize.new(name, version)
776
1047
  end
777
-
778
1048
  end
779
1049
 
780
- class NullMigration < MigrationProxy #:nodoc:
781
- def initialize
782
- super(nil, 0, nil, nil)
783
- end
1050
+ class MigrationContext #:nodoc:
1051
+ attr_reader :migrations_paths, :schema_migration
784
1052
 
785
- def mtime
786
- 0
1053
+ def initialize(migrations_paths, schema_migration)
1054
+ @migrations_paths = migrations_paths
1055
+ @schema_migration = schema_migration
787
1056
  end
788
- end
789
1057
 
790
- class Migrator#:nodoc:
791
- class << self
792
- attr_writer :migrations_paths
793
- alias :migrations_path= :migrations_paths=
794
-
795
- def migrate(migrations_paths, target_version = nil, &block)
796
- case
797
- when target_version.nil?
798
- up(migrations_paths, target_version, &block)
799
- when current_version == 0 && target_version == 0
800
- []
801
- when current_version > target_version
802
- down(migrations_paths, target_version, &block)
803
- else
804
- up(migrations_paths, target_version, &block)
805
- 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)
806
1068
  end
1069
+ end
807
1070
 
808
- def rollback(migrations_paths, steps=1)
809
- move(:down, migrations_paths, steps)
810
- end
1071
+ def rollback(steps = 1)
1072
+ move(:down, steps)
1073
+ end
811
1074
 
812
- def forward(migrations_paths, steps=1)
813
- move(:up, migrations_paths, steps)
1075
+ def forward(steps = 1)
1076
+ move(:up, steps)
1077
+ end
1078
+
1079
+ def up(target_version = nil)
1080
+ selected_migrations = if block_given?
1081
+ migrations.select { |m| yield m }
1082
+ else
1083
+ migrations
814
1084
  end
815
1085
 
816
- def up(migrations_paths, target_version = nil)
817
- migrations = migrations(migrations_paths)
818
- migrations.select! { |m| yield m } if block_given?
1086
+ Migrator.new(:up, selected_migrations, schema_migration, target_version).migrate
1087
+ end
819
1088
 
820
- 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
821
1094
  end
822
1095
 
823
- def down(migrations_paths, target_version = nil, &block)
824
- migrations = migrations(migrations_paths)
825
- migrations.select! { |m| yield m } if block_given?
1096
+ Migrator.new(:down, selected_migrations, schema_migration, target_version).migrate
1097
+ end
826
1098
 
827
- new(:down, migrations, target_version).migrate
828
- end
1099
+ def run(direction, target_version)
1100
+ Migrator.new(direction, migrations, schema_migration, target_version).run
1101
+ end
829
1102
 
830
- def run(direction, migrations_paths, target_version)
831
- new(direction, migrations(migrations_paths), target_version).run
832
- end
1103
+ def open
1104
+ Migrator.new(:up, migrations, schema_migration)
1105
+ end
833
1106
 
834
- def open(migrations_paths)
835
- 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
+ []
836
1112
  end
1113
+ end
837
1114
 
838
- def schema_migrations_table_name
839
- SchemaMigration.table_name
840
- end
1115
+ def current_version
1116
+ get_all_versions.max || 0
1117
+ rescue ActiveRecord::NoDatabaseError
1118
+ end
841
1119
 
842
- def get_all_versions(connection = Base.connection)
843
- if connection.table_exists?(schema_migrations_table_name)
844
- SchemaMigration.all.map { |x| x.version.to_i }.sort
845
- else
846
- []
847
- end
848
- end
1120
+ def needs_migration?
1121
+ (migrations.collect(&:version) - get_all_versions).size > 0
1122
+ end
849
1123
 
850
- def current_version(connection = Base.connection)
851
- get_all_versions(connection).max || 0
852
- end
1124
+ def any_migrations?
1125
+ migrations.any?
1126
+ end
853
1127
 
854
- def needs_migration?(connection = Base.connection)
855
- (migrations(migrations_paths).collect(&:version) - get_all_versions(connection)).size > 0
856
- 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
857
1134
 
858
- def any_migrations?
859
- migrations(migrations_paths).any?
1135
+ MigrationProxy.new(name, version, file, scope)
860
1136
  end
861
1137
 
862
- def last_version
863
- last_migration.version
864
- end
1138
+ migrations.sort_by(&:version)
1139
+ end
865
1140
 
866
- def last_migration #:nodoc:
867
- migrations(migrations_paths).last || NullMigration.new
868
- end
1141
+ def migrations_status
1142
+ db_list = schema_migration.normalized_versions
869
1143
 
870
- def migrations_paths
871
- @migrations_paths ||= ['db/migrate']
872
- # just to not break things if someone uses: migration_path = some_string
873
- Array(@migrations_paths)
874
- 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
875
1151
 
876
- def migrations_path
877
- migrations_paths.first
1152
+ db_list.map! do |version|
1153
+ ["up", version, "********** NO FILE **********"]
878
1154
  end
879
1155
 
880
- def migrations(paths)
881
- paths = Array(paths)
1156
+ (db_list + file_list).sort_by { |_, version, _| version }
1157
+ end
882
1158
 
883
- files = Dir[*paths.map { |p| "#{p}/**/[0-9]*_*.rb" }]
1159
+ def current_environment
1160
+ ActiveRecord::ConnectionHandling::DEFAULT_ENV.call
1161
+ end
884
1162
 
885
- migrations = files.map do |file|
886
- version, name, scope = file.scan(/([0-9]+)_([_a-z0-9]*)\.?([_a-z0-9]*)?\.rb\z/).first
1163
+ def protected_environment?
1164
+ ActiveRecord::Base.protected_environments.include?(last_stored_environment) if last_stored_environment
1165
+ end
887
1166
 
888
- raise IllegalMigrationNameError.new(file) unless version
889
- version = version.to_i
890
- name = name.camelize
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?
891
1171
 
892
- MigrationProxy.new(name, version, file, scope)
893
- end
1172
+ environment = ActiveRecord::InternalMetadata[:environment]
1173
+ raise NoEnvironmentInSchemaError unless environment
1174
+ environment
1175
+ end
894
1176
 
895
- migrations.sort_by(&:version)
1177
+ private
1178
+ def migration_files
1179
+ paths = Array(migrations_paths)
1180
+ Dir[*paths.flat_map { |path| "#{path}/**/[0-9]*_*.rb" }]
896
1181
  end
897
1182
 
898
- private
1183
+ def parse_migration_filename(filename)
1184
+ File.basename(filename).scan(Migration::MigrationFilenameRegexp).first
1185
+ end
899
1186
 
900
- def move(direction, migrations_paths, steps)
901
- migrator = new(direction, migrations(migrations_paths))
902
- start_index = migrator.migrations.index(migrator.current_migration)
1187
+ def move(direction, steps)
1188
+ migrator = Migrator.new(direction, migrations, schema_migration)
903
1189
 
904
- if start_index
905
- finish = migrator.migrations[start_index + steps]
906
- version = finish ? finish.version : 0
907
- send(direction, migrations_paths, version)
1190
+ if current_version != 0 && !migrator.current_migration
1191
+ raise UnknownMigrationVersionError.new(current_version)
908
1192
  end
1193
+
1194
+ start_index =
1195
+ if current_version == 0
1196
+ 0
1197
+ else
1198
+ migrator.migrations.index(migrator.current_migration)
1199
+ end
1200
+
1201
+ finish = migrator.migrations[start_index + steps]
1202
+ version = finish ? finish.version : 0
1203
+ public_send(direction, version)
1204
+ end
1205
+ end
1206
+
1207
+ class Migrator # :nodoc:
1208
+ class << self
1209
+ attr_accessor :migrations_paths
1210
+
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
909
1214
  end
910
1215
  end
911
1216
 
912
- def initialize(direction, migrations, target_version = nil)
913
- raise StandardError.new("This database does not yet support migrations") unless Base.connection.supports_migrations?
1217
+ self.migrations_paths = ["db/migrate"]
914
1218
 
1219
+ def initialize(direction, migrations, schema_migration, target_version = nil)
915
1220
  @direction = direction
916
1221
  @target_version = target_version
917
1222
  @migrated_versions = nil
918
1223
  @migrations = migrations
1224
+ @schema_migration = schema_migration
919
1225
 
920
1226
  validate(@migrations)
921
1227
 
922
- Base.connection.initialize_schema_migrations_table
1228
+ @schema_migration.create_table
1229
+ ActiveRecord::InternalMetadata.create_table
923
1230
  end
924
1231
 
925
1232
  def current_version
@@ -932,32 +1239,18 @@ module ActiveRecord
932
1239
  alias :current :current_migration
933
1240
 
934
1241
  def run
935
- migration = migrations.detect { |m| m.version == @target_version }
936
- raise UnknownMigrationVersionError.new(@target_version) if migration.nil?
937
- unless (up? && migrated.include?(migration.version.to_i)) || (down? && !migrated.include?(migration.version.to_i))
938
- begin
939
- execute_migration_in_transaction(migration, @direction)
940
- rescue => e
941
- canceled_msg = use_transaction?(migration) ? ", this migration was canceled" : ""
942
- raise StandardError, "An error has occurred#{canceled_msg}:\n\n#{e}", e.backtrace
943
- end
1242
+ if use_advisory_lock?
1243
+ with_advisory_lock { run_without_lock }
1244
+ else
1245
+ run_without_lock
944
1246
  end
945
1247
  end
946
1248
 
947
1249
  def migrate
948
- if !target && @target_version && @target_version > 0
949
- raise UnknownMigrationVersionError.new(@target_version)
950
- end
951
-
952
- runnable.each do |migration|
953
- Base.logger.info "Migrating to #{migration.name} (#{migration.version})" if Base.logger
954
-
955
- begin
956
- execute_migration_in_transaction(migration, @direction)
957
- rescue => e
958
- canceled_msg = use_transaction?(migration) ? "this and " : ""
959
- raise StandardError, "An error has occurred, #{canceled_msg}all later migrations canceled:\n\n#{e}", e.backtrace
960
- end
1250
+ if use_advisory_lock?
1251
+ with_advisory_lock { migrate_without_lock }
1252
+ else
1253
+ migrate_without_lock
961
1254
  end
962
1255
  end
963
1256
 
@@ -982,70 +1275,153 @@ module ActiveRecord
982
1275
  end
983
1276
 
984
1277
  def migrated
985
- @migrated_versions ||= Set.new(self.class.get_all_versions)
1278
+ @migrated_versions || load_migrated
986
1279
  end
987
1280
 
988
- private
989
- def ran?(migration)
990
- migrated.include?(migration.version.to_i)
1281
+ def load_migrated
1282
+ @migrated_versions = Set.new(@schema_migration.all_versions.map(&:to_i))
991
1283
  end
992
1284
 
993
- def execute_migration_in_transaction(migration, direction)
994
- ddl_transaction(migration) do
995
- migration.migrate(direction)
996
- 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
997
1294
  end
998
- end
999
1295
 
1000
- def target
1001
- migrations.detect { |m| m.version == @target_version }
1002
- 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
1003
1301
 
1004
- def finish
1005
- migrations.index(target) || migrations.size - 1
1006
- end
1302
+ result = runnable.each(&method(:execute_migration_in_transaction))
1303
+ record_environment
1304
+ result
1305
+ end
1007
1306
 
1008
- def start
1009
- up? ? 0 : (migrations.index(current) || 0)
1010
- 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
1011
1312
 
1012
- def validate(migrations)
1013
- name ,= migrations.group_by(&:name).find { |_,v| v.length > 1 }
1014
- raise DuplicateMigrationNameError.new(name) if name
1313
+ def ran?(migration)
1314
+ migrated.include?(migration.version.to_i)
1315
+ end
1015
1316
 
1016
- version ,= migrations.group_by(&:version).find { |_,v| v.length > 1 }
1017
- raise DuplicateMigrationVersionError.new(version) if version
1018
- end
1317
+ # Return true if a valid version is not provided.
1318
+ def invalid_target?
1319
+ @target_version && @target_version != 0 && !target
1320
+ end
1019
1321
 
1020
- def record_version_state_after_migrating(version)
1021
- if down?
1022
- migrated.delete(version)
1023
- ActiveRecord::SchemaMigration.where(:version => version.to_s).delete_all
1024
- else
1025
- migrated << version
1026
- 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
1027
1337
  end
1028
- end
1029
1338
 
1030
- def up?
1031
- @direction == :up
1032
- end
1339
+ def target
1340
+ migrations.detect { |m| m.version == @target_version }
1341
+ end
1033
1342
 
1034
- def down?
1035
- @direction == :down
1036
- end
1343
+ def finish
1344
+ migrations.index(target) || migrations.size - 1
1345
+ end
1037
1346
 
1038
- # Wrap the migration in a transaction only if supported by the adapter.
1039
- def ddl_transaction(migration)
1040
- if use_transaction?(migration)
1041
- Base.transaction { yield }
1042
- else
1043
- yield
1347
+ def start
1348
+ up? ? 0 : (migrations.index(current) || 0)
1044
1349
  end
1045
- end
1046
1350
 
1047
- def use_transaction?(migration)
1048
- !migration.disable_ddl_transaction && Base.connection.supports_ddl_transactions?
1049
- 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
1050
1426
  end
1051
1427
  end