activerecord 5.0.7.2 → 6.0.3.4

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 (359) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +708 -2040
  3. data/MIT-LICENSE +3 -1
  4. data/README.rdoc +9 -7
  5. data/examples/performance.rb +31 -29
  6. data/examples/simple.rb +5 -3
  7. data/lib/active_record.rb +37 -22
  8. data/lib/active_record/advisory_lock_base.rb +18 -0
  9. data/lib/active_record/aggregations.rb +249 -247
  10. data/lib/active_record/association_relation.rb +18 -14
  11. data/lib/active_record/associations.rb +1603 -1592
  12. data/lib/active_record/associations/alias_tracker.rb +24 -34
  13. data/lib/active_record/associations/association.rb +114 -55
  14. data/lib/active_record/associations/association_scope.rb +94 -94
  15. data/lib/active_record/associations/belongs_to_association.rb +58 -42
  16. data/lib/active_record/associations/belongs_to_polymorphic_association.rb +8 -12
  17. data/lib/active_record/associations/builder/association.rb +18 -25
  18. data/lib/active_record/associations/builder/belongs_to.rb +43 -54
  19. data/lib/active_record/associations/builder/collection_association.rb +7 -18
  20. data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +41 -62
  21. data/lib/active_record/associations/builder/has_many.rb +4 -0
  22. data/lib/active_record/associations/builder/has_one.rb +37 -1
  23. data/lib/active_record/associations/builder/singular_association.rb +4 -0
  24. data/lib/active_record/associations/collection_association.rb +86 -254
  25. data/lib/active_record/associations/collection_proxy.rb +158 -122
  26. data/lib/active_record/associations/foreign_association.rb +9 -0
  27. data/lib/active_record/associations/has_many_association.rb +23 -30
  28. data/lib/active_record/associations/has_many_through_association.rb +58 -44
  29. data/lib/active_record/associations/has_one_association.rb +59 -54
  30. data/lib/active_record/associations/has_one_through_association.rb +20 -11
  31. data/lib/active_record/associations/join_dependency.rb +143 -176
  32. data/lib/active_record/associations/join_dependency/join_association.rb +38 -87
  33. data/lib/active_record/associations/join_dependency/join_base.rb +10 -9
  34. data/lib/active_record/associations/join_dependency/join_part.rb +12 -12
  35. data/lib/active_record/associations/preloader.rb +90 -103
  36. data/lib/active_record/associations/preloader/association.rb +86 -100
  37. data/lib/active_record/associations/preloader/through_association.rb +77 -76
  38. data/lib/active_record/associations/singular_association.rb +12 -45
  39. data/lib/active_record/associations/through_association.rb +26 -14
  40. data/lib/active_record/attribute_assignment.rb +54 -61
  41. data/lib/active_record/attribute_decorators.rb +38 -17
  42. data/lib/active_record/attribute_methods.rb +66 -106
  43. data/lib/active_record/attribute_methods/before_type_cast.rb +12 -8
  44. data/lib/active_record/attribute_methods/dirty.rb +179 -109
  45. data/lib/active_record/attribute_methods/primary_key.rb +85 -92
  46. data/lib/active_record/attribute_methods/query.rb +4 -3
  47. data/lib/active_record/attribute_methods/read.rb +20 -49
  48. data/lib/active_record/attribute_methods/serialization.rb +29 -7
  49. data/lib/active_record/attribute_methods/time_zone_conversion.rb +39 -66
  50. data/lib/active_record/attribute_methods/write.rb +34 -33
  51. data/lib/active_record/attributes.rb +38 -25
  52. data/lib/active_record/autosave_association.rb +54 -35
  53. data/lib/active_record/base.rb +27 -24
  54. data/lib/active_record/callbacks.rb +64 -35
  55. data/lib/active_record/coders/json.rb +2 -0
  56. data/lib/active_record/coders/yaml_column.rb +11 -12
  57. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +552 -323
  58. data/lib/active_record/connection_adapters/abstract/database_limits.rb +23 -5
  59. data/lib/active_record/connection_adapters/abstract/database_statements.rb +215 -94
  60. data/lib/active_record/connection_adapters/abstract/query_cache.rb +59 -35
  61. data/lib/active_record/connection_adapters/abstract/quoting.rb +119 -75
  62. data/lib/active_record/connection_adapters/abstract/savepoints.rb +2 -0
  63. data/lib/active_record/connection_adapters/abstract/schema_creation.rb +33 -28
  64. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +228 -147
  65. data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +68 -80
  66. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +400 -213
  67. data/lib/active_record/connection_adapters/abstract/transaction.rb +169 -79
  68. data/lib/active_record/connection_adapters/abstract_adapter.rb +367 -202
  69. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +396 -562
  70. data/lib/active_record/connection_adapters/column.rb +41 -13
  71. data/lib/active_record/connection_adapters/connection_specification.rb +172 -139
  72. data/lib/active_record/connection_adapters/determine_if_preparable_visitor.rb +11 -4
  73. data/lib/active_record/connection_adapters/mysql/column.rb +8 -31
  74. data/lib/active_record/connection_adapters/mysql/database_statements.rb +137 -49
  75. data/lib/active_record/connection_adapters/mysql/explain_pretty_printer.rb +24 -23
  76. data/lib/active_record/connection_adapters/mysql/quoting.rb +50 -20
  77. data/lib/active_record/connection_adapters/mysql/schema_creation.rb +49 -45
  78. data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +58 -56
  79. data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +70 -36
  80. data/lib/active_record/connection_adapters/mysql/schema_statements.rb +264 -0
  81. data/lib/active_record/connection_adapters/mysql/type_metadata.rb +12 -13
  82. data/lib/active_record/connection_adapters/mysql2_adapter.rb +48 -30
  83. data/lib/active_record/connection_adapters/postgresql/column.rb +19 -31
  84. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +64 -54
  85. data/lib/active_record/connection_adapters/postgresql/explain_pretty_printer.rb +5 -3
  86. data/lib/active_record/connection_adapters/postgresql/oid.rb +24 -21
  87. data/lib/active_record/connection_adapters/postgresql/oid/array.rb +22 -11
  88. data/lib/active_record/connection_adapters/postgresql/oid/bit.rb +6 -5
  89. data/lib/active_record/connection_adapters/postgresql/oid/bit_varying.rb +2 -0
  90. data/lib/active_record/connection_adapters/postgresql/oid/bytea.rb +2 -0
  91. data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +3 -1
  92. data/lib/active_record/connection_adapters/postgresql/oid/date.rb +23 -0
  93. data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +4 -2
  94. data/lib/active_record/connection_adapters/postgresql/oid/decimal.rb +3 -1
  95. data/lib/active_record/connection_adapters/postgresql/oid/enum.rb +5 -4
  96. data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +19 -18
  97. data/lib/active_record/connection_adapters/postgresql/oid/inet.rb +2 -0
  98. data/lib/active_record/connection_adapters/postgresql/oid/jsonb.rb +3 -11
  99. data/lib/active_record/connection_adapters/postgresql/oid/legacy_point.rb +44 -0
  100. data/lib/active_record/connection_adapters/postgresql/oid/money.rb +7 -5
  101. data/lib/active_record/connection_adapters/postgresql/oid/{json.rb → oid.rb} +6 -1
  102. data/lib/active_record/connection_adapters/postgresql/oid/point.rb +30 -9
  103. data/lib/active_record/connection_adapters/postgresql/oid/range.rb +34 -31
  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 +58 -54
  106. data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +8 -4
  107. data/lib/active_record/connection_adapters/postgresql/oid/vector.rb +2 -0
  108. data/lib/active_record/connection_adapters/postgresql/oid/xml.rb +2 -0
  109. data/lib/active_record/connection_adapters/postgresql/quoting.rb +95 -35
  110. data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +20 -26
  111. data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +76 -0
  112. data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +147 -105
  113. data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +34 -32
  114. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +378 -308
  115. data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +26 -25
  116. data/lib/active_record/connection_adapters/postgresql/utils.rb +9 -6
  117. data/lib/active_record/connection_adapters/postgresql_adapter.rb +383 -275
  118. data/lib/active_record/connection_adapters/schema_cache.rb +46 -12
  119. data/lib/active_record/connection_adapters/sql_type_metadata.rb +13 -8
  120. data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +119 -0
  121. data/lib/active_record/connection_adapters/sqlite3/explain_pretty_printer.rb +3 -1
  122. data/lib/active_record/connection_adapters/sqlite3/quoting.rb +72 -18
  123. data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +3 -8
  124. data/lib/active_record/connection_adapters/sqlite3/schema_definitions.rb +19 -0
  125. data/lib/active_record/connection_adapters/sqlite3/schema_dumper.rb +18 -0
  126. data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +137 -0
  127. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +259 -266
  128. data/lib/active_record/connection_adapters/statement_pool.rb +9 -8
  129. data/lib/active_record/connection_handling.rb +143 -40
  130. data/lib/active_record/core.rb +201 -163
  131. data/lib/active_record/counter_cache.rb +60 -28
  132. data/lib/active_record/database_configurations.rb +233 -0
  133. data/lib/active_record/database_configurations/database_config.rb +37 -0
  134. data/lib/active_record/database_configurations/hash_config.rb +50 -0
  135. data/lib/active_record/database_configurations/url_config.rb +78 -0
  136. data/lib/active_record/define_callbacks.rb +22 -0
  137. data/lib/active_record/dynamic_matchers.rb +87 -87
  138. data/lib/active_record/enum.rb +60 -23
  139. data/lib/active_record/errors.rb +114 -18
  140. data/lib/active_record/explain.rb +4 -4
  141. data/lib/active_record/explain_registry.rb +3 -1
  142. data/lib/active_record/explain_subscriber.rb +9 -4
  143. data/lib/active_record/fixture_set/file.rb +13 -8
  144. data/lib/active_record/fixture_set/model_metadata.rb +33 -0
  145. data/lib/active_record/fixture_set/render_context.rb +17 -0
  146. data/lib/active_record/fixture_set/table_row.rb +152 -0
  147. data/lib/active_record/fixture_set/table_rows.rb +46 -0
  148. data/lib/active_record/fixtures.rb +194 -504
  149. data/lib/active_record/gem_version.rb +5 -3
  150. data/lib/active_record/inheritance.rb +150 -99
  151. data/lib/active_record/insert_all.rb +179 -0
  152. data/lib/active_record/integration.rb +116 -25
  153. data/lib/active_record/internal_metadata.rb +16 -19
  154. data/lib/active_record/legacy_yaml_adapter.rb +4 -2
  155. data/lib/active_record/locking/optimistic.rb +77 -87
  156. data/lib/active_record/locking/pessimistic.rb +18 -6
  157. data/lib/active_record/log_subscriber.rb +48 -29
  158. data/lib/active_record/middleware/database_selector.rb +74 -0
  159. data/lib/active_record/middleware/database_selector/resolver.rb +87 -0
  160. data/lib/active_record/middleware/database_selector/resolver/session.rb +45 -0
  161. data/lib/active_record/migration.rb +369 -302
  162. data/lib/active_record/migration/command_recorder.rb +134 -100
  163. data/lib/active_record/migration/compatibility.rb +174 -56
  164. data/lib/active_record/migration/join_table.rb +8 -7
  165. data/lib/active_record/model_schema.rb +131 -127
  166. data/lib/active_record/nested_attributes.rb +213 -202
  167. data/lib/active_record/no_touching.rb +12 -3
  168. data/lib/active_record/null_relation.rb +12 -34
  169. data/lib/active_record/persistence.rb +446 -77
  170. data/lib/active_record/query_cache.rb +13 -12
  171. data/lib/active_record/querying.rb +37 -24
  172. data/lib/active_record/railtie.rb +128 -36
  173. data/lib/active_record/railties/collection_cache_association_loading.rb +34 -0
  174. data/lib/active_record/railties/console_sandbox.rb +2 -0
  175. data/lib/active_record/railties/controller_runtime.rb +34 -33
  176. data/lib/active_record/railties/databases.rake +312 -177
  177. data/lib/active_record/readonly_attributes.rb +5 -4
  178. data/lib/active_record/reflection.rb +214 -252
  179. data/lib/active_record/relation.rb +440 -318
  180. data/lib/active_record/relation/batches.rb +98 -52
  181. data/lib/active_record/relation/batches/batch_enumerator.rb +3 -1
  182. data/lib/active_record/relation/calculations.rb +212 -173
  183. data/lib/active_record/relation/delegation.rb +72 -69
  184. data/lib/active_record/relation/finder_methods.rb +207 -247
  185. data/lib/active_record/relation/from_clause.rb +6 -8
  186. data/lib/active_record/relation/merger.rb +78 -62
  187. data/lib/active_record/relation/predicate_builder.rb +83 -105
  188. data/lib/active_record/relation/predicate_builder/array_handler.rb +20 -14
  189. data/lib/active_record/relation/predicate_builder/association_query_value.rb +43 -0
  190. data/lib/active_record/relation/predicate_builder/base_handler.rb +4 -3
  191. data/lib/active_record/relation/predicate_builder/basic_object_handler.rb +6 -4
  192. data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +53 -0
  193. data/lib/active_record/relation/predicate_builder/range_handler.rb +7 -18
  194. data/lib/active_record/relation/predicate_builder/relation_handler.rb +6 -0
  195. data/lib/active_record/relation/query_attribute.rb +33 -2
  196. data/lib/active_record/relation/query_methods.rb +476 -334
  197. data/lib/active_record/relation/record_fetch_warning.rb +5 -3
  198. data/lib/active_record/relation/spawn_methods.rb +8 -8
  199. data/lib/active_record/relation/where_clause.rb +111 -96
  200. data/lib/active_record/relation/where_clause_factory.rb +6 -11
  201. data/lib/active_record/result.rb +69 -40
  202. data/lib/active_record/runtime_registry.rb +5 -3
  203. data/lib/active_record/sanitization.rb +83 -99
  204. data/lib/active_record/schema.rb +7 -14
  205. data/lib/active_record/schema_dumper.rb +71 -69
  206. data/lib/active_record/schema_migration.rb +16 -6
  207. data/lib/active_record/scoping.rb +20 -20
  208. data/lib/active_record/scoping/default.rb +92 -95
  209. data/lib/active_record/scoping/named.rb +47 -27
  210. data/lib/active_record/secure_token.rb +4 -2
  211. data/lib/active_record/serialization.rb +2 -0
  212. data/lib/active_record/statement_cache.rb +63 -28
  213. data/lib/active_record/store.rb +121 -41
  214. data/lib/active_record/suppressor.rb +6 -3
  215. data/lib/active_record/table_metadata.rb +39 -18
  216. data/lib/active_record/tasks/database_tasks.rb +271 -81
  217. data/lib/active_record/tasks/mysql_database_tasks.rb +54 -91
  218. data/lib/active_record/tasks/postgresql_database_tasks.rb +77 -47
  219. data/lib/active_record/tasks/sqlite_database_tasks.rb +33 -16
  220. data/lib/active_record/test_databases.rb +23 -0
  221. data/lib/active_record/test_fixtures.rb +225 -0
  222. data/lib/active_record/timestamp.rb +70 -36
  223. data/lib/active_record/touch_later.rb +8 -6
  224. data/lib/active_record/transactions.rb +141 -157
  225. data/lib/active_record/translation.rb +3 -1
  226. data/lib/active_record/type.rb +23 -18
  227. data/lib/active_record/type/adapter_specific_registry.rb +44 -48
  228. data/lib/active_record/type/date.rb +2 -0
  229. data/lib/active_record/type/date_time.rb +2 -0
  230. data/lib/active_record/type/decimal_without_scale.rb +15 -0
  231. data/lib/active_record/type/hash_lookup_type_map.rb +5 -4
  232. data/lib/active_record/type/internal/timezone.rb +2 -0
  233. data/lib/active_record/type/json.rb +30 -0
  234. data/lib/active_record/type/serialized.rb +16 -9
  235. data/lib/active_record/type/text.rb +11 -0
  236. data/lib/active_record/type/time.rb +2 -1
  237. data/lib/active_record/type/type_map.rb +14 -17
  238. data/lib/active_record/type/unsigned_integer.rb +16 -0
  239. data/lib/active_record/type_caster.rb +4 -2
  240. data/lib/active_record/type_caster/connection.rb +17 -12
  241. data/lib/active_record/type_caster/map.rb +5 -4
  242. data/lib/active_record/validations.rb +7 -5
  243. data/lib/active_record/validations/absence.rb +2 -0
  244. data/lib/active_record/validations/associated.rb +4 -3
  245. data/lib/active_record/validations/length.rb +2 -0
  246. data/lib/active_record/validations/presence.rb +4 -2
  247. data/lib/active_record/validations/uniqueness.rb +29 -42
  248. data/lib/active_record/version.rb +3 -1
  249. data/lib/arel.rb +62 -0
  250. data/lib/arel/alias_predication.rb +9 -0
  251. data/lib/arel/attributes.rb +22 -0
  252. data/lib/arel/attributes/attribute.rb +37 -0
  253. data/lib/arel/collectors/bind.rb +24 -0
  254. data/lib/arel/collectors/composite.rb +31 -0
  255. data/lib/arel/collectors/plain_string.rb +20 -0
  256. data/lib/arel/collectors/sql_string.rb +20 -0
  257. data/lib/arel/collectors/substitute_binds.rb +28 -0
  258. data/lib/arel/crud.rb +42 -0
  259. data/lib/arel/delete_manager.rb +18 -0
  260. data/lib/arel/errors.rb +9 -0
  261. data/lib/arel/expressions.rb +29 -0
  262. data/lib/arel/factory_methods.rb +49 -0
  263. data/lib/arel/insert_manager.rb +49 -0
  264. data/lib/arel/math.rb +45 -0
  265. data/lib/arel/nodes.rb +68 -0
  266. data/lib/arel/nodes/and.rb +32 -0
  267. data/lib/arel/nodes/ascending.rb +23 -0
  268. data/lib/arel/nodes/binary.rb +52 -0
  269. data/lib/arel/nodes/bind_param.rb +36 -0
  270. data/lib/arel/nodes/case.rb +55 -0
  271. data/lib/arel/nodes/casted.rb +50 -0
  272. data/lib/arel/nodes/comment.rb +29 -0
  273. data/lib/arel/nodes/count.rb +12 -0
  274. data/lib/arel/nodes/delete_statement.rb +45 -0
  275. data/lib/arel/nodes/descending.rb +23 -0
  276. data/lib/arel/nodes/equality.rb +18 -0
  277. data/lib/arel/nodes/extract.rb +24 -0
  278. data/lib/arel/nodes/false.rb +16 -0
  279. data/lib/arel/nodes/full_outer_join.rb +8 -0
  280. data/lib/arel/nodes/function.rb +44 -0
  281. data/lib/arel/nodes/grouping.rb +8 -0
  282. data/lib/arel/nodes/in.rb +8 -0
  283. data/lib/arel/nodes/infix_operation.rb +80 -0
  284. data/lib/arel/nodes/inner_join.rb +8 -0
  285. data/lib/arel/nodes/insert_statement.rb +37 -0
  286. data/lib/arel/nodes/join_source.rb +20 -0
  287. data/lib/arel/nodes/matches.rb +18 -0
  288. data/lib/arel/nodes/named_function.rb +23 -0
  289. data/lib/arel/nodes/node.rb +50 -0
  290. data/lib/arel/nodes/node_expression.rb +13 -0
  291. data/lib/arel/nodes/outer_join.rb +8 -0
  292. data/lib/arel/nodes/over.rb +15 -0
  293. data/lib/arel/nodes/regexp.rb +16 -0
  294. data/lib/arel/nodes/right_outer_join.rb +8 -0
  295. data/lib/arel/nodes/select_core.rb +67 -0
  296. data/lib/arel/nodes/select_statement.rb +41 -0
  297. data/lib/arel/nodes/sql_literal.rb +16 -0
  298. data/lib/arel/nodes/string_join.rb +11 -0
  299. data/lib/arel/nodes/table_alias.rb +27 -0
  300. data/lib/arel/nodes/terminal.rb +16 -0
  301. data/lib/arel/nodes/true.rb +16 -0
  302. data/lib/arel/nodes/unary.rb +45 -0
  303. data/lib/arel/nodes/unary_operation.rb +20 -0
  304. data/lib/arel/nodes/unqualified_column.rb +22 -0
  305. data/lib/arel/nodes/update_statement.rb +41 -0
  306. data/lib/arel/nodes/values_list.rb +9 -0
  307. data/lib/arel/nodes/window.rb +126 -0
  308. data/lib/arel/nodes/with.rb +11 -0
  309. data/lib/arel/order_predications.rb +13 -0
  310. data/lib/arel/predications.rb +256 -0
  311. data/lib/arel/select_manager.rb +271 -0
  312. data/lib/arel/table.rb +110 -0
  313. data/lib/arel/tree_manager.rb +72 -0
  314. data/lib/arel/update_manager.rb +34 -0
  315. data/lib/arel/visitors.rb +20 -0
  316. data/lib/arel/visitors/depth_first.rb +203 -0
  317. data/lib/arel/visitors/dot.rb +296 -0
  318. data/lib/arel/visitors/ibm_db.rb +34 -0
  319. data/lib/arel/visitors/informix.rb +62 -0
  320. data/lib/arel/visitors/mssql.rb +156 -0
  321. data/lib/arel/visitors/mysql.rb +83 -0
  322. data/lib/arel/visitors/oracle.rb +158 -0
  323. data/lib/arel/visitors/oracle12.rb +65 -0
  324. data/lib/arel/visitors/postgresql.rb +109 -0
  325. data/lib/arel/visitors/sqlite.rb +38 -0
  326. data/lib/arel/visitors/to_sql.rb +888 -0
  327. data/lib/arel/visitors/visitor.rb +45 -0
  328. data/lib/arel/visitors/where_sql.rb +22 -0
  329. data/lib/arel/window_predications.rb +9 -0
  330. data/lib/rails/generators/active_record.rb +7 -5
  331. data/lib/rails/generators/active_record/application_record/application_record_generator.rb +26 -0
  332. data/lib/rails/generators/active_record/{model/templates/application_record.rb → application_record/templates/application_record.rb.tt} +0 -0
  333. data/lib/rails/generators/active_record/migration.rb +17 -3
  334. data/lib/rails/generators/active_record/migration/migration_generator.rb +37 -35
  335. data/lib/rails/generators/active_record/migration/templates/{create_table_migration.rb → create_table_migration.rb.tt} +1 -1
  336. data/lib/rails/generators/active_record/migration/templates/{migration.rb → migration.rb.tt} +4 -2
  337. data/lib/rails/generators/active_record/model/model_generator.rb +9 -30
  338. data/lib/rails/generators/active_record/model/templates/{model.rb → model.rb.tt} +10 -1
  339. data/lib/rails/generators/active_record/model/templates/{module.rb → module.rb.tt} +0 -0
  340. metadata +137 -52
  341. data/lib/active_record/associations/preloader/belongs_to.rb +0 -17
  342. data/lib/active_record/associations/preloader/collection_association.rb +0 -17
  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 -15
  346. data/lib/active_record/associations/preloader/has_one_through.rb +0 -9
  347. data/lib/active_record/associations/preloader/singular_association.rb +0 -20
  348. data/lib/active_record/attribute.rb +0 -213
  349. data/lib/active_record/attribute/user_provided_default.rb +0 -28
  350. data/lib/active_record/attribute_mutation_tracker.rb +0 -70
  351. data/lib/active_record/attribute_set.rb +0 -110
  352. data/lib/active_record/attribute_set/builder.rb +0 -132
  353. data/lib/active_record/collection_cache_key.rb +0 -50
  354. data/lib/active_record/connection_adapters/postgresql/oid/rails_5_1_point.rb +0 -50
  355. data/lib/active_record/railties/jdbcmysql_error.rb +0 -16
  356. data/lib/active_record/relation/predicate_builder/association_query_handler.rb +0 -88
  357. data/lib/active_record/relation/predicate_builder/class_handler.rb +0 -27
  358. data/lib/active_record/relation/predicate_builder/polymorphic_array_handler.rb +0 -57
  359. data/lib/active_record/type/internal/abstract_json.rb +0 -33
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ActiveRecord
2
4
  module Locking
3
5
  # Locking::Pessimistic provides support for row-level locking using
@@ -12,9 +14,9 @@ module ActiveRecord
12
14
  # of your own such as 'LOCK IN SHARE MODE' or 'FOR UPDATE NOWAIT'. Example:
13
15
  #
14
16
  # Account.transaction do
15
- # # select * from accounts where name = 'shugo' limit 1 for update
16
- # shugo = Account.where("name = 'shugo'").lock(true).first
17
- # yuko = Account.where("name = 'yuko'").lock(true).first
17
+ # # select * from accounts where name = 'shugo' limit 1 for update nowait
18
+ # shugo = Account.lock("FOR UPDATE NOWAIT").find_by(name: "shugo")
19
+ # yuko = Account.lock("FOR UPDATE NOWAIT").find_by(name: "yuko")
18
20
  # shugo.balance -= 100
19
21
  # shugo.save!
20
22
  # yuko.balance += 100
@@ -51,15 +53,25 @@ module ActiveRecord
51
53
  # end
52
54
  #
53
55
  # Database-specific information on row locking:
54
- # MySQL: http://dev.mysql.com/doc/refman/5.7/en/innodb-locking-reads.html
55
- # PostgreSQL: http://www.postgresql.org/docs/current/interactive/sql-select.html#SQL-FOR-UPDATE-SHARE
56
+ # MySQL: https://dev.mysql.com/doc/refman/5.7/en/innodb-locking-reads.html
57
+ # PostgreSQL: https://www.postgresql.org/docs/current/interactive/sql-select.html#SQL-FOR-UPDATE-SHARE
56
58
  module Pessimistic
57
59
  # Obtain a row lock on this record. Reloads the record to obtain the requested
58
60
  # lock. Pass an SQL locking clause to append the end of the SELECT statement
59
61
  # or pass true for "FOR UPDATE" (the default, an exclusive row lock). Returns
60
62
  # the locked record.
61
63
  def lock!(lock = true)
62
- reload(:lock => lock) if persisted?
64
+ if persisted?
65
+ if has_changes_to_save?
66
+ raise(<<-MSG.squish)
67
+ Locking a record with unpersisted changes is not supported. Use
68
+ `save` to persist the changes, or `reload` to discard them
69
+ explicitly.
70
+ MSG
71
+ end
72
+
73
+ reload(lock: lock)
74
+ end
63
75
  self
64
76
  end
65
77
 
@@ -1,7 +1,11 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ActiveRecord
2
4
  class LogSubscriber < ActiveSupport::LogSubscriber
3
5
  IGNORE_PAYLOAD_NAMES = ["SCHEMA", "EXPLAIN"]
4
6
 
7
+ class_attribute :backtrace_cleaner, default: ActiveSupport::BacktraceCleaner.new
8
+
5
9
  def self.runtime=(value)
6
10
  ActiveRecord::RuntimeRegistry.sql_runtime = value
7
11
  end
@@ -15,11 +19,6 @@ module ActiveRecord
15
19
  rt
16
20
  end
17
21
 
18
- def initialize
19
- super
20
- @odd = false
21
- end
22
-
23
22
  def sql(event)
24
23
  self.class.runtime += event.duration
25
24
  return unless logger.debug?
@@ -29,6 +28,7 @@ module ActiveRecord
29
28
  return if IGNORE_PAYLOAD_NAMES.include?(payload[:name])
30
29
 
31
30
  name = "#{payload[:name]} (#{event.duration.round(1)}ms)"
31
+ name = "CACHE #{name}" if payload[:cached]
32
32
  sql = payload[:sql]
33
33
  binds = nil
34
34
 
@@ -40,37 +40,36 @@ module ActiveRecord
40
40
  end
41
41
 
42
42
  name = colorize_payload_name(name, payload[:name])
43
- sql = color(sql, sql_color(sql), true)
43
+ sql = color(sql, sql_color(sql), true) if colorize_logging
44
44
 
45
45
  debug " #{name} #{sql}#{binds}"
46
46
  end
47
47
 
48
48
  private
49
+ def type_casted_binds(casted_binds)
50
+ casted_binds.respond_to?(:call) ? casted_binds.call : casted_binds
51
+ end
49
52
 
50
- def type_casted_binds(casted_binds)
51
- casted_binds.respond_to?(:call) ? casted_binds.call : casted_binds
52
- end
53
+ def render_bind(attr, value)
54
+ if attr.is_a?(Array)
55
+ attr = attr.first
56
+ elsif attr.type.binary? && attr.value
57
+ value = "<#{attr.value_for_database.to_s.bytesize} bytes of binary data>"
58
+ end
53
59
 
54
- def render_bind(attr, value)
55
- if attr.is_a?(Array)
56
- attr = attr.first
57
- elsif attr.type.binary? && attr.value
58
- value = "<#{attr.value_for_database.to_s.bytesize} bytes of binary data>"
60
+ [attr && attr.name, value]
59
61
  end
60
62
 
61
- [attr && attr.name, value]
62
- end
63
-
64
- def colorize_payload_name(name, payload_name)
65
- if payload_name.blank? || payload_name == "SQL" # SQL vs Model Load/Exists
66
- color(name, MAGENTA, true)
67
- else
68
- color(name, CYAN, true)
63
+ def colorize_payload_name(name, payload_name)
64
+ if payload_name.blank? || payload_name == "SQL" # SQL vs Model Load/Exists
65
+ color(name, MAGENTA, true)
66
+ else
67
+ color(name, CYAN, true)
68
+ end
69
69
  end
70
- end
71
70
 
72
- def sql_color(sql)
73
- case sql
71
+ def sql_color(sql)
72
+ case sql
74
73
  when /\A\s*rollback/mi
75
74
  RED
76
75
  when /select .*for update/mi, /\A\s*lock/mi
@@ -87,12 +86,32 @@ module ActiveRecord
87
86
  CYAN
88
87
  else
89
88
  MAGENTA
89
+ end
90
90
  end
91
- end
92
91
 
93
- def logger
94
- ActiveRecord::Base.logger
95
- end
92
+ def logger
93
+ ActiveRecord::Base.logger
94
+ end
95
+
96
+ def debug(progname = nil, &block)
97
+ return unless super
98
+
99
+ if ActiveRecord::Base.verbose_query_logs
100
+ log_query_source
101
+ end
102
+ end
103
+
104
+ def log_query_source
105
+ source = extract_query_source_location(caller)
106
+
107
+ if source
108
+ logger.debug(" ↳ #{source}")
109
+ end
110
+ end
111
+
112
+ def extract_query_source_location(locations)
113
+ backtrace_cleaner.clean(locations.lazy).first
114
+ end
96
115
  end
97
116
  end
98
117
 
@@ -0,0 +1,74 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "active_record/middleware/database_selector/resolver"
4
+
5
+ module ActiveRecord
6
+ module Middleware
7
+ # The DatabaseSelector Middleware provides a framework for automatically
8
+ # swapping from the primary to the replica database connection. Rails
9
+ # provides a basic framework to determine when to swap and allows for
10
+ # applications to write custom strategy classes to override the default
11
+ # behavior.
12
+ #
13
+ # The resolver class defines when the application should switch (i.e. read
14
+ # from the primary if a write occurred less than 2 seconds ago) and a
15
+ # resolver context class that sets a value that helps the resolver class
16
+ # decide when to switch.
17
+ #
18
+ # Rails default middleware uses the request's session to set a timestamp
19
+ # that informs the application when to read from a primary or read from a
20
+ # replica.
21
+ #
22
+ # To use the DatabaseSelector in your application with default settings add
23
+ # the following options to your environment config:
24
+ #
25
+ # config.active_record.database_selector = { delay: 2.seconds }
26
+ # config.active_record.database_resolver = ActiveRecord::Middleware::DatabaseSelector::Resolver
27
+ # config.active_record.database_resolver_context = ActiveRecord::Middleware::DatabaseSelector::Resolver::Session
28
+ #
29
+ # New applications will include these lines commented out in the production.rb.
30
+ #
31
+ # The default behavior can be changed by setting the config options to a
32
+ # custom class:
33
+ #
34
+ # config.active_record.database_selector = { delay: 2.seconds }
35
+ # config.active_record.database_resolver = MyResolver
36
+ # config.active_record.database_resolver_context = MyResolver::MySession
37
+ class DatabaseSelector
38
+ def initialize(app, resolver_klass = nil, context_klass = nil, options = {})
39
+ @app = app
40
+ @resolver_klass = resolver_klass || Resolver
41
+ @context_klass = context_klass || Resolver::Session
42
+ @options = options
43
+ end
44
+
45
+ attr_reader :resolver_klass, :context_klass, :options
46
+
47
+ # Middleware that determines which database connection to use in a multiple
48
+ # database application.
49
+ def call(env)
50
+ request = ActionDispatch::Request.new(env)
51
+
52
+ select_database(request) do
53
+ @app.call(env)
54
+ end
55
+ end
56
+
57
+ private
58
+ def select_database(request, &blk)
59
+ context = context_klass.call(request)
60
+ resolver = resolver_klass.call(context, options)
61
+
62
+ if reading_request?(request)
63
+ resolver.read(&blk)
64
+ else
65
+ resolver.write(&blk)
66
+ end
67
+ end
68
+
69
+ def reading_request?(request)
70
+ request.get? || request.head?
71
+ end
72
+ end
73
+ end
74
+ end
@@ -0,0 +1,87 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "active_record/middleware/database_selector/resolver/session"
4
+
5
+ module ActiveRecord
6
+ module Middleware
7
+ class DatabaseSelector
8
+ # The Resolver class is used by the DatabaseSelector middleware to
9
+ # determine which database the request should use.
10
+ #
11
+ # To change the behavior of the Resolver class in your application,
12
+ # create a custom resolver class that inherits from
13
+ # DatabaseSelector::Resolver and implements the methods that need to
14
+ # be changed.
15
+ #
16
+ # By default the Resolver class will send read traffic to the replica
17
+ # if it's been 2 seconds since the last write.
18
+ class Resolver # :nodoc:
19
+ SEND_TO_REPLICA_DELAY = 2.seconds
20
+
21
+ def self.call(context, options = {})
22
+ new(context, options)
23
+ end
24
+
25
+ def initialize(context, options = {})
26
+ @context = context
27
+ @options = options
28
+ @delay = @options && @options[:delay] ? @options[:delay] : SEND_TO_REPLICA_DELAY
29
+ @instrumenter = ActiveSupport::Notifications.instrumenter
30
+ end
31
+
32
+ attr_reader :context, :delay, :instrumenter
33
+
34
+ def read(&blk)
35
+ if read_from_primary?
36
+ read_from_primary(&blk)
37
+ else
38
+ read_from_replica(&blk)
39
+ end
40
+ end
41
+
42
+ def write(&blk)
43
+ write_to_primary(&blk)
44
+ end
45
+
46
+ private
47
+ def read_from_primary(&blk)
48
+ ActiveRecord::Base.connected_to(role: ActiveRecord::Base.writing_role, prevent_writes: true) do
49
+ instrumenter.instrument("database_selector.active_record.read_from_primary") do
50
+ yield
51
+ end
52
+ end
53
+ end
54
+
55
+ def read_from_replica(&blk)
56
+ ActiveRecord::Base.connected_to(role: ActiveRecord::Base.reading_role, prevent_writes: true) do
57
+ instrumenter.instrument("database_selector.active_record.read_from_replica") do
58
+ yield
59
+ end
60
+ end
61
+ end
62
+
63
+ def write_to_primary(&blk)
64
+ ActiveRecord::Base.connected_to(role: ActiveRecord::Base.writing_role, prevent_writes: false) do
65
+ instrumenter.instrument("database_selector.active_record.wrote_to_primary") do
66
+ yield
67
+ ensure
68
+ context.update_last_write_timestamp
69
+ end
70
+ end
71
+ end
72
+
73
+ def read_from_primary?
74
+ !time_since_last_write_ok?
75
+ end
76
+
77
+ def send_to_replica_delay
78
+ delay
79
+ end
80
+
81
+ def time_since_last_write_ok?
82
+ Time.now - context.last_write_timestamp >= send_to_replica_delay
83
+ end
84
+ end
85
+ end
86
+ end
87
+ end
@@ -0,0 +1,45 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActiveRecord
4
+ module Middleware
5
+ class DatabaseSelector
6
+ class Resolver
7
+ # The session class is used by the DatabaseSelector::Resolver to save
8
+ # timestamps of the last write in the session.
9
+ #
10
+ # The last_write is used to determine whether it's safe to read
11
+ # from the replica or the request needs to be sent to the primary.
12
+ class Session # :nodoc:
13
+ def self.call(request)
14
+ new(request.session)
15
+ end
16
+
17
+ # Converts time to a timestamp that represents milliseconds since
18
+ # epoch.
19
+ def self.convert_time_to_timestamp(time)
20
+ time.to_i * 1000 + time.usec / 1000
21
+ end
22
+
23
+ # Converts milliseconds since epoch timestamp into a time object.
24
+ def self.convert_timestamp_to_time(timestamp)
25
+ timestamp ? Time.at(timestamp / 1000, (timestamp % 1000) * 1000) : Time.at(0)
26
+ end
27
+
28
+ def initialize(session)
29
+ @session = session
30
+ end
31
+
32
+ attr_reader :session
33
+
34
+ def last_write_timestamp
35
+ self.class.convert_timestamp_to_time(session[:last_write])
36
+ end
37
+
38
+ def update_last_write_timestamp
39
+ session[:last_write] = self.class.convert_time_to_timestamp(Time.now)
40
+ end
41
+ end
42
+ end
43
+ end
44
+ end
45
+ end
@@ -1,9 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "benchmark"
1
4
  require "set"
2
5
  require "zlib"
3
6
  require "active_support/core_ext/module/attribute_accessors"
7
+ require "active_support/actionable_error"
4
8
 
5
9
  module ActiveRecord
6
- class MigrationError < ActiveRecordError#:nodoc:
10
+ class MigrationError < ActiveRecordError #:nodoc:
7
11
  def initialize(message = nil)
8
12
  message = "\n\n#{message}\n\n" if message
9
13
  super
@@ -20,7 +24,7 @@ module ActiveRecord
20
24
  # t.string :zipcode
21
25
  # end
22
26
  #
23
- # execute <<-SQL
27
+ # execute <<~SQL
24
28
  # ALTER TABLE distributors
25
29
  # ADD CONSTRAINT zipchk
26
30
  # CHECK (char_length(zipcode) = 5) NO INHERIT;
@@ -38,7 +42,7 @@ module ActiveRecord
38
42
  # t.string :zipcode
39
43
  # end
40
44
  #
41
- # execute <<-SQL
45
+ # execute <<~SQL
42
46
  # ALTER TABLE distributors
43
47
  # ADD CONSTRAINT zipchk
44
48
  # CHECK (char_length(zipcode) = 5) NO INHERIT;
@@ -46,7 +50,7 @@ module ActiveRecord
46
50
  # end
47
51
  #
48
52
  # def down
49
- # execute <<-SQL
53
+ # execute <<~SQL
50
54
  # ALTER TABLE distributors
51
55
  # DROP CONSTRAINT zipchk
52
56
  # SQL
@@ -65,7 +69,7 @@ module ActiveRecord
65
69
  #
66
70
  # reversible do |dir|
67
71
  # dir.up do
68
- # execute <<-SQL
72
+ # execute <<~SQL
69
73
  # ALTER TABLE distributors
70
74
  # ADD CONSTRAINT zipchk
71
75
  # CHECK (char_length(zipcode) = 5) NO INHERIT;
@@ -73,7 +77,7 @@ module ActiveRecord
73
77
  # end
74
78
  #
75
79
  # dir.down do
76
- # execute <<-SQL
80
+ # execute <<~SQL
77
81
  # ALTER TABLE distributors
78
82
  # DROP CONSTRAINT zipchk
79
83
  # SQL
@@ -84,7 +88,7 @@ module ActiveRecord
84
88
  class IrreversibleMigration < MigrationError
85
89
  end
86
90
 
87
- class DuplicateMigrationVersionError < MigrationError#:nodoc:
91
+ class DuplicateMigrationVersionError < MigrationError #:nodoc:
88
92
  def initialize(version = nil)
89
93
  if version
90
94
  super("Multiple migrations have the version number #{version}.")
@@ -94,7 +98,7 @@ module ActiveRecord
94
98
  end
95
99
  end
96
100
 
97
- class DuplicateMigrationNameError < MigrationError#:nodoc:
101
+ class DuplicateMigrationNameError < MigrationError #:nodoc:
98
102
  def initialize(name = nil)
99
103
  if name
100
104
  super("Multiple migrations have the name #{name}.")
@@ -114,7 +118,7 @@ module ActiveRecord
114
118
  end
115
119
  end
116
120
 
117
- class IllegalMigrationNameError < MigrationError#:nodoc:
121
+ class IllegalMigrationNameError < MigrationError #:nodoc:
118
122
  def initialize(name = nil)
119
123
  if name
120
124
  super("Illegal name for migration file: #{name}\n\t(only lower case letters, numbers, and '_' allowed).")
@@ -124,12 +128,18 @@ module ActiveRecord
124
128
  end
125
129
  end
126
130
 
127
- class PendingMigrationError < MigrationError#:nodoc:
131
+ class PendingMigrationError < MigrationError #:nodoc:
132
+ include ActiveSupport::ActionableError
133
+
134
+ action "Run pending migrations" do
135
+ ActiveRecord::Tasks::DatabaseTasks.migrate
136
+ end
137
+
128
138
  def initialize(message = nil)
129
139
  if !message && defined?(Rails.env)
130
- super("Migrations are pending. To resolve this issue, run:\n\n bin/rails db:migrate RAILS_ENV=#{::Rails.env}")
140
+ super("Migrations are pending. To resolve this issue, run:\n\n rails db:migrate RAILS_ENV=#{::Rails.env}")
131
141
  elsif !message
132
- super("Migrations are pending. To resolve this issue, run:\n\n bin/rails db:migrate")
142
+ super("Migrations are pending. To resolve this issue, run:\n\n rails db:migrate")
133
143
  else
134
144
  super
135
145
  end
@@ -137,7 +147,8 @@ module ActiveRecord
137
147
  end
138
148
 
139
149
  class ConcurrentMigrationError < MigrationError #:nodoc:
140
- DEFAULT_MESSAGE = "Cannot run migrations because another migration process is currently running.".freeze
150
+ DEFAULT_MESSAGE = "Cannot run migrations because another migration process is currently running."
151
+ RELEASE_LOCK_FAILED_MESSAGE = "Failed to release advisory lock"
141
152
 
142
153
  def initialize(message = DEFAULT_MESSAGE)
143
154
  super
@@ -146,7 +157,7 @@ module ActiveRecord
146
157
 
147
158
  class NoEnvironmentInSchemaError < MigrationError #:nodoc:
148
159
  def initialize
149
- msg = "Environment data not found in the schema. To resolve this issue, run: \n\n bin/rails db:environment:set"
160
+ msg = "Environment data not found in the schema. To resolve this issue, run: \n\n rails db:environment:set"
150
161
  if defined?(Rails.env)
151
162
  super("#{msg} RAILS_ENV=#{::Rails.env}")
152
163
  else
@@ -157,7 +168,7 @@ module ActiveRecord
157
168
 
158
169
  class ProtectedEnvironmentError < ActiveRecordError #:nodoc:
159
170
  def initialize(env = "production")
160
- msg = "You are attempting to run a destructive action against your '#{env}' database.\n"
171
+ msg = +"You are attempting to run a destructive action against your '#{env}' database.\n"
161
172
  msg << "If you are sure you want to continue, run the same command with the environment variable:\n"
162
173
  msg << "DISABLE_DATABASE_ENVIRONMENT_CHECK=1"
163
174
  super(msg)
@@ -166,10 +177,10 @@ module ActiveRecord
166
177
 
167
178
  class EnvironmentMismatchError < ActiveRecordError
168
179
  def initialize(current: nil, stored: nil)
169
- msg = "You are attempting to modify a database that was last run in `#{ stored }` environment.\n"
180
+ msg = +"You are attempting to modify a database that was last run in `#{ stored }` environment.\n"
170
181
  msg << "You are running in `#{ current }` environment. "
171
182
  msg << "If you are sure you want to continue, first set the environment using:\n\n"
172
- msg << " bin/rails db:environment:set"
183
+ msg << " rails db:environment:set"
173
184
  if defined?(Rails.env)
174
185
  super("#{msg} RAILS_ENV=#{::Rails.env}\n\n")
175
186
  else
@@ -277,8 +288,10 @@ module ActiveRecord
277
288
  #
278
289
  # * <tt>change_column(table_name, column_name, type, options)</tt>: Changes
279
290
  # the column to a different type using the same parameters as add_column.
280
- # * <tt>change_column_default(table_name, column_name, default)</tt>: Sets a
281
- # default value for +column_name+ defined by +default+ on +table_name+.
291
+ # * <tt>change_column_default(table_name, column_name, default_or_changes)</tt>:
292
+ # Sets a default value for +column_name+ defined by +default_or_changes+ on
293
+ # +table_name+. Passing a hash containing <tt>:from</tt> and <tt>:to</tt>
294
+ # as +default_or_changes+ will make this change reversible in the migration.
282
295
  # * <tt>change_column_null(table_name, column_name, null, default = nil)</tt>:
283
296
  # Sets or removes a +NOT NULL+ constraint on +column_name+. The +null+ flag
284
297
  # indicates whether the value can be +NULL+. See
@@ -302,7 +315,7 @@ module ActiveRecord
302
315
  # named +column_name+ from the table called +table_name+.
303
316
  # * <tt>remove_columns(table_name, *column_names)</tt>: Removes the given
304
317
  # columns from the table definition.
305
- # * <tt>remove_foreign_key(from_table, options_or_to_table)</tt>: Removes the
318
+ # * <tt>remove_foreign_key(from_table, to_table = nil, **options)</tt>: Removes the
306
319
  # given foreign key from the table called +table_name+.
307
320
  # * <tt>remove_index(table_name, column: column_names)</tt>: Removes the index
308
321
  # specified by +column_names+.
@@ -346,13 +359,13 @@ module ActiveRecord
346
359
  # <tt>rails db:migrate</tt>. This will update the database by running all of the
347
360
  # pending migrations, creating the <tt>schema_migrations</tt> table
348
361
  # (see "About the schema_migrations table" section below) if missing. It will also
349
- # invoke the db:schema:dump task, which will update your db/schema.rb file
362
+ # invoke the db:schema:dump command, which will update your db/schema.rb file
350
363
  # to match the structure of your database.
351
364
  #
352
365
  # To roll the database back to a previous migration version, use
353
- # <tt>rails db:migrate VERSION=X</tt> where <tt>X</tt> is the version to which
366
+ # <tt>rails db:rollback VERSION=X</tt> where <tt>X</tt> is the version to which
354
367
  # you wish to downgrade. Alternatively, you can also use the STEP option if you
355
- # wish to rollback last few migrations. <tt>rails db:migrate STEP=2</tt> will rollback
368
+ # wish to rollback last few migrations. <tt>rails db:rollback STEP=2</tt> will rollback
356
369
  # the latest two migrations.
357
370
  #
358
371
  # If any of the migrations throw an <tt>ActiveRecord::IrreversibleMigration</tt> exception,
@@ -481,9 +494,9 @@ module ActiveRecord
481
494
  # This migration will create the horses table for you on the way up, and
482
495
  # automatically figure out how to drop the table on the way down.
483
496
  #
484
- # Some commands like +remove_column+ cannot be reversed. If you care to
485
- # define how to move up and down in these cases, you should define the +up+
486
- # and +down+ methods as before.
497
+ # Some commands cannot be reversed. If you care to define how to move up
498
+ # and down in these cases, you should define the +up+ and +down+ methods
499
+ # as before.
487
500
  #
488
501
  # If a command cannot be reversed, an
489
502
  # <tt>ActiveRecord::IrreversibleMigration</tt> exception will be raised when
@@ -510,17 +523,20 @@ module ActiveRecord
510
523
  # Remember that you can still open your own transactions, even if you
511
524
  # are in a Migration with <tt>self.disable_ddl_transaction!</tt>.
512
525
  class Migration
513
- autoload :CommandRecorder, 'active_record/migration/command_recorder'
514
- autoload :Compatibility, 'active_record/migration/compatibility'
526
+ autoload :CommandRecorder, "active_record/migration/command_recorder"
527
+ autoload :Compatibility, "active_record/migration/compatibility"
515
528
 
516
529
  # This must be defined before the inherited hook, below
517
- class Current < Migration # :nodoc:
530
+ class Current < Migration #:nodoc:
518
531
  end
519
532
 
520
- def self.inherited(subclass) # :nodoc:
533
+ def self.inherited(subclass) #:nodoc:
521
534
  super
522
535
  if subclass.superclass == Migration
523
- subclass.include Compatibility::Legacy
536
+ raise StandardError, "Directly inheriting from ActiveRecord::Migration is not supported. " \
537
+ "Please specify the Rails release the migration was written for:\n" \
538
+ "\n" \
539
+ " class #{subclass} < ActiveRecord::Migration[4.2]"
524
540
  end
525
541
  end
526
542
 
@@ -532,7 +548,7 @@ module ActiveRecord
532
548
  ActiveRecord::VERSION::STRING.to_f
533
549
  end
534
550
 
535
- MigrationFilenameRegexp = /\A([0-9]+)_([_a-z0-9]*)\.?([_a-z0-9]*)?\.rb\z/ # :nodoc:
551
+ MigrationFilenameRegexp = /\A([0-9]+)_([_a-z0-9]*)\.?([_a-z0-9]*)?\.rb\z/ #:nodoc:
536
552
 
537
553
  # This class is used to verify that all migrations have been run before
538
554
  # loading a web page if <tt>config.active_record.migration_error</tt> is set to :page_load
@@ -543,59 +559,66 @@ module ActiveRecord
543
559
  end
544
560
 
545
561
  def call(env)
546
- if connection.supports_migrations?
547
- mtime = ActiveRecord::Migrator.last_migration.mtime.to_i
548
- if @last_check < mtime
549
- ActiveRecord::Migration.check_pending!(connection)
550
- @last_check = mtime
551
- end
562
+ mtime = ActiveRecord::Base.connection.migration_context.last_migration.mtime.to_i
563
+ if @last_check < mtime
564
+ ActiveRecord::Migration.check_pending!(connection)
565
+ @last_check = mtime
552
566
  end
553
567
  @app.call(env)
554
568
  end
555
569
 
556
570
  private
557
-
558
- def connection
559
- ActiveRecord::Base.connection
560
- end
571
+ def connection
572
+ ActiveRecord::Base.connection
573
+ end
561
574
  end
562
575
 
563
576
  class << self
564
- attr_accessor :delegate # :nodoc:
565
- attr_accessor :disable_ddl_transaction # :nodoc:
577
+ attr_accessor :delegate #:nodoc:
578
+ attr_accessor :disable_ddl_transaction #:nodoc:
566
579
 
567
- def nearest_delegate # :nodoc:
580
+ def nearest_delegate #:nodoc:
568
581
  delegate || superclass.nearest_delegate
569
582
  end
570
583
 
571
584
  # Raises <tt>ActiveRecord::PendingMigrationError</tt> error if any migrations are pending.
572
585
  def check_pending!(connection = Base.connection)
573
- raise ActiveRecord::PendingMigrationError if ActiveRecord::Migrator.needs_migration?(connection)
586
+ raise ActiveRecord::PendingMigrationError if connection.migration_context.needs_migration?
574
587
  end
575
588
 
576
589
  def load_schema_if_pending!
577
- if ActiveRecord::Migrator.needs_migration? || !ActiveRecord::Migrator.any_migrations?
590
+ current_config = Base.connection_config
591
+ all_configs = ActiveRecord::Base.configurations.configs_for(env_name: Rails.env)
592
+
593
+ needs_update = !all_configs.all? do |db_config|
594
+ Tasks::DatabaseTasks.schema_up_to_date?(db_config.config, ActiveRecord::Base.schema_format, nil, Rails.env, db_config.spec_name)
595
+ end
596
+
597
+ if needs_update
578
598
  # Roundtrip to Rake to allow plugins to hook into database initialization.
579
- FileUtils.cd Rails.root do
580
- current_config = Base.connection_config
599
+ root = defined?(ENGINE_ROOT) ? ENGINE_ROOT : Rails.root
600
+ FileUtils.cd(root) do
581
601
  Base.clear_all_connections!
582
602
  system("bin/rails db:test:prepare")
583
- # Establish a new connection, the old database may be gone (db:test:prepare uses purge)
584
- Base.establish_connection(current_config)
585
603
  end
586
- check_pending!
587
604
  end
605
+
606
+ # Establish a new connection, the old database may be gone (db:test:prepare uses purge)
607
+ Base.establish_connection(current_config)
608
+
609
+ check_pending!
588
610
  end
589
611
 
590
- def maintain_test_schema! # :nodoc:
612
+ def maintain_test_schema! #:nodoc:
591
613
  if ActiveRecord::Base.maintain_test_schema
592
614
  suppress_messages { load_schema_if_pending! }
593
615
  end
594
616
  end
595
617
 
596
- def method_missing(name, *args, &block) # :nodoc:
618
+ def method_missing(name, *args, &block) #:nodoc:
597
619
  nearest_delegate.send(name, *args, &block)
598
620
  end
621
+ ruby2_keywords(:method_missing) if respond_to?(:ruby2_keywords, true)
599
622
 
600
623
  def migrate(direction)
601
624
  new.migrate direction
@@ -610,7 +633,7 @@ module ActiveRecord
610
633
  end
611
634
  end
612
635
 
613
- def disable_ddl_transaction # :nodoc:
636
+ def disable_ddl_transaction #:nodoc:
614
637
  self.class.disable_ddl_transaction
615
638
  end
616
639
 
@@ -670,15 +693,13 @@ module ActiveRecord
670
693
  if connection.respond_to? :revert
671
694
  connection.revert { yield }
672
695
  else
673
- recorder = CommandRecorder.new(connection)
696
+ recorder = command_recorder
674
697
  @connection = recorder
675
698
  suppress_messages do
676
699
  connection.revert { yield }
677
700
  end
678
701
  @connection = recorder.delegate
679
- recorder.commands.each do |cmd, args, block|
680
- send(cmd, *args, &block)
681
- end
702
+ recorder.replay(self)
682
703
  end
683
704
  end
684
705
  end
@@ -687,7 +708,7 @@ module ActiveRecord
687
708
  connection.respond_to?(:reverting) && connection.reverting
688
709
  end
689
710
 
690
- class ReversibleBlockHelper < Struct.new(:reverting) # :nodoc:
711
+ ReversibleBlockHelper = Struct.new(:reverting) do #:nodoc:
691
712
  def up
692
713
  yield unless reverting
693
714
  end
@@ -725,7 +746,25 @@ module ActiveRecord
725
746
  # end
726
747
  def reversible
727
748
  helper = ReversibleBlockHelper.new(reverting?)
728
- execute_block{ yield helper }
749
+ execute_block { yield helper }
750
+ end
751
+
752
+ # Used to specify an operation that is only run when migrating up
753
+ # (for example, populating a new column with its initial values).
754
+ #
755
+ # In the following example, the new column +published+ will be given
756
+ # the value +true+ for all existing records.
757
+ #
758
+ # class AddPublishedToPosts < ActiveRecord::Migration[5.2]
759
+ # def change
760
+ # add_column :posts, :published, :boolean, default: false
761
+ # up_only do
762
+ # execute "update posts set published = 'true'"
763
+ # end
764
+ # end
765
+ # end
766
+ def up_only
767
+ execute_block { yield } unless reverting?
729
768
  end
730
769
 
731
770
  # Runs the given migration classes.
@@ -767,7 +806,7 @@ module ActiveRecord
767
806
  when :down then announce "reverting"
768
807
  end
769
808
 
770
- time = nil
809
+ time = nil
771
810
  ActiveRecord::Base.connection_pool.with_connection do |conn|
772
811
  time = Benchmark.measure do
773
812
  exec_migration(conn, direction)
@@ -795,7 +834,7 @@ module ActiveRecord
795
834
  @connection = nil
796
835
  end
797
836
 
798
- def write(text="")
837
+ def write(text = "")
799
838
  puts(text) if verbose
800
839
  end
801
840
 
@@ -805,10 +844,14 @@ module ActiveRecord
805
844
  write "== %s %s" % [text, "=" * length]
806
845
  end
807
846
 
808
- def say(message, subitem=false)
847
+ # Takes a message argument and outputs it as is.
848
+ # A second boolean argument can be passed to specify whether to indent or not.
849
+ def say(message, subitem = false)
809
850
  write "#{subitem ? " ->" : "--"} #{message}"
810
851
  end
811
852
 
853
+ # Outputs text along with how long it took to run its block.
854
+ # If the block returns an integer it assumes it is the number of rows affected.
812
855
  def say_with_time(message)
813
856
  say(message)
814
857
  result = nil
@@ -818,6 +861,7 @@ module ActiveRecord
818
861
  result
819
862
  end
820
863
 
864
+ # Takes a block as an argument and suppresses any output generated by the block.
821
865
  def suppress_messages
822
866
  save, self.verbose = verbose, false
823
867
  yield
@@ -830,7 +874,7 @@ module ActiveRecord
830
874
  end
831
875
 
832
876
  def method_missing(method, *arguments, &block)
833
- arg_list = arguments.map(&:inspect) * ', '
877
+ arg_list = arguments.map(&:inspect) * ", "
834
878
 
835
879
  say_with_time "#{method}(#{arg_list})" do
836
880
  unless connection.respond_to? :revert
@@ -846,29 +890,33 @@ module ActiveRecord
846
890
  connection.send(method, *arguments, &block)
847
891
  end
848
892
  end
893
+ ruby2_keywords(:method_missing) if respond_to?(:ruby2_keywords, true)
849
894
 
850
895
  def copy(destination, sources, options = {})
851
896
  copied = []
897
+ schema_migration = options[:schema_migration] || ActiveRecord::SchemaMigration
852
898
 
853
899
  FileUtils.mkdir_p(destination) unless File.exist?(destination)
854
900
 
855
- destination_migrations = ActiveRecord::Migrator.migrations(destination)
901
+ destination_migrations = ActiveRecord::MigrationContext.new(destination, schema_migration).migrations
856
902
  last = destination_migrations.last
857
903
  sources.each do |scope, path|
858
- source_migrations = ActiveRecord::Migrator.migrations(path)
904
+ source_migrations = ActiveRecord::MigrationContext.new(path, schema_migration).migrations
859
905
 
860
906
  source_migrations.each do |migration|
861
907
  source = File.binread(migration.filename)
862
908
  inserted_comment = "# This migration comes from #{scope} (originally #{migration.version})\n"
863
- if /\A#.*\b(?:en)?coding:\s*\S+/ =~ source
909
+ magic_comments = +""
910
+ loop do
864
911
  # If we have a magic comment in the original migration,
865
912
  # insert our comment after the first newline(end of the magic comment line)
866
913
  # so the magic keep working.
867
914
  # Note that magic comments must be at the first line(except sh-bang).
868
- source[/\n/] = "\n#{inserted_comment}"
869
- else
870
- source = "#{inserted_comment}#{source}"
915
+ source.sub!(/\A(?:#.*\b(?:en)?coding:\s*\S+|#\s*frozen_string_literal:\s*(?:true|false)).*\n/) do |magic_comment|
916
+ magic_comments << magic_comment; ""
917
+ end || break
871
918
  end
919
+ source = "#{magic_comments}#{inserted_comment}#{source}"
872
920
 
873
921
  if duplicate = destination_migrations.detect { |m| m.name == migration.name }
874
922
  if options[:on_skip] && duplicate.scope != scope.to_s
@@ -922,19 +970,22 @@ module ActiveRecord
922
970
  end
923
971
 
924
972
  private
925
- def execute_block
926
- if connection.respond_to? :execute_block
927
- super # use normal delegation to record the block
928
- else
929
- yield
973
+ def execute_block
974
+ if connection.respond_to? :execute_block
975
+ super # use normal delegation to record the block
976
+ else
977
+ yield
978
+ end
979
+ end
980
+
981
+ def command_recorder
982
+ CommandRecorder.new(connection)
930
983
  end
931
- end
932
984
  end
933
985
 
934
986
  # MigrationProxy is used to defer loading of the actual migration classes
935
987
  # until they are needed
936
- class MigrationProxy < Struct.new(:name, :version, :filename, :scope)
937
-
988
+ MigrationProxy = Struct.new(:name, :version, :filename, :scope) do
938
989
  def initialize(name, version, filename, scope)
939
990
  super
940
991
  @migration = nil
@@ -951,7 +1002,6 @@ module ActiveRecord
951
1002
  delegate :migrate, :announce, :write, :disable_ddl_transaction, to: :migration
952
1003
 
953
1004
  private
954
-
955
1005
  def migration
956
1006
  @migration ||= load_migration
957
1007
  end
@@ -960,7 +1010,6 @@ module ActiveRecord
960
1010
  require(File.expand_path(filename))
961
1011
  name.constantize.new(name, version)
962
1012
  end
963
-
964
1013
  end
965
1014
 
966
1015
  class NullMigration < MigrationProxy #:nodoc:
@@ -973,159 +1022,189 @@ module ActiveRecord
973
1022
  end
974
1023
  end
975
1024
 
976
- class Migrator#:nodoc:
977
- class << self
978
- attr_writer :migrations_paths
979
- alias :migrations_path= :migrations_paths=
980
-
981
- def migrate(migrations_paths, target_version = nil, &block)
982
- case
983
- when target_version.nil?
984
- up(migrations_paths, target_version, &block)
985
- when current_version == 0 && target_version == 0
986
- []
987
- when current_version > target_version
988
- down(migrations_paths, target_version, &block)
989
- else
990
- up(migrations_paths, target_version, &block)
991
- end
992
- end
1025
+ class MigrationContext #:nodoc:
1026
+ attr_reader :migrations_paths, :schema_migration
993
1027
 
994
- def rollback(migrations_paths, steps=1)
995
- move(:down, migrations_paths, steps)
996
- end
1028
+ def initialize(migrations_paths, schema_migration)
1029
+ @migrations_paths = migrations_paths
1030
+ @schema_migration = schema_migration
1031
+ end
997
1032
 
998
- def forward(migrations_paths, steps=1)
999
- move(:up, migrations_paths, steps)
1033
+ def migrate(target_version = nil, &block)
1034
+ case
1035
+ when target_version.nil?
1036
+ up(target_version, &block)
1037
+ when current_version == 0 && target_version == 0
1038
+ []
1039
+ when current_version > target_version
1040
+ down(target_version, &block)
1041
+ else
1042
+ up(target_version, &block)
1000
1043
  end
1044
+ end
1001
1045
 
1002
- def up(migrations_paths, target_version = nil)
1003
- migrations = migrations(migrations_paths)
1004
- migrations.select! { |m| yield m } if block_given?
1046
+ def rollback(steps = 1)
1047
+ move(:down, steps)
1048
+ end
1005
1049
 
1006
- new(:up, migrations, target_version).migrate
1050
+ def forward(steps = 1)
1051
+ move(:up, steps)
1052
+ end
1053
+
1054
+ def up(target_version = nil)
1055
+ selected_migrations = if block_given?
1056
+ migrations.select { |m| yield m }
1057
+ else
1058
+ migrations
1007
1059
  end
1008
1060
 
1009
- def down(migrations_paths, target_version = nil)
1010
- migrations = migrations(migrations_paths)
1011
- migrations.select! { |m| yield m } if block_given?
1061
+ Migrator.new(:up, selected_migrations, schema_migration, target_version).migrate
1062
+ end
1012
1063
 
1013
- new(:down, migrations, target_version).migrate
1064
+ def down(target_version = nil)
1065
+ selected_migrations = if block_given?
1066
+ migrations.select { |m| yield m }
1067
+ else
1068
+ migrations
1014
1069
  end
1015
1070
 
1016
- def run(direction, migrations_paths, target_version)
1017
- new(direction, migrations(migrations_paths), target_version).run
1018
- end
1071
+ Migrator.new(:down, selected_migrations, schema_migration, target_version).migrate
1072
+ end
1019
1073
 
1020
- def open(migrations_paths)
1021
- new(:up, migrations(migrations_paths), nil)
1022
- end
1074
+ def run(direction, target_version)
1075
+ Migrator.new(direction, migrations, schema_migration, target_version).run
1076
+ end
1023
1077
 
1024
- def schema_migrations_table_name
1025
- SchemaMigration.table_name
1026
- end
1078
+ def open
1079
+ Migrator.new(:up, migrations, schema_migration)
1080
+ end
1027
1081
 
1028
- def get_all_versions(connection = Base.connection)
1029
- ActiveSupport::Deprecation.silence do
1030
- if connection.table_exists?(schema_migrations_table_name)
1031
- SchemaMigration.all.map { |x| x.version.to_i }.sort
1032
- else
1033
- []
1034
- end
1035
- end
1082
+ def get_all_versions
1083
+ if schema_migration.table_exists?
1084
+ schema_migration.all_versions.map(&:to_i)
1085
+ else
1086
+ []
1036
1087
  end
1088
+ end
1037
1089
 
1038
- def current_version(connection = Base.connection)
1039
- get_all_versions(connection).max || 0
1040
- end
1090
+ def current_version
1091
+ get_all_versions.max || 0
1092
+ rescue ActiveRecord::NoDatabaseError
1093
+ end
1041
1094
 
1042
- def needs_migration?(connection = Base.connection)
1043
- (migrations(migrations_paths).collect(&:version) - get_all_versions(connection)).size > 0
1044
- end
1095
+ def needs_migration?
1096
+ (migrations.collect(&:version) - get_all_versions).size > 0
1097
+ end
1045
1098
 
1046
- def any_migrations?
1047
- migrations(migrations_paths).any?
1048
- end
1099
+ def any_migrations?
1100
+ migrations.any?
1101
+ end
1049
1102
 
1050
- def last_migration #:nodoc:
1051
- migrations(migrations_paths).last || NullMigration.new
1052
- end
1103
+ def last_migration #:nodoc:
1104
+ migrations.last || NullMigration.new
1105
+ end
1053
1106
 
1054
- def migrations_paths
1055
- @migrations_paths ||= ['db/migrate']
1056
- # just to not break things if someone uses: migrations_path = some_string
1057
- Array(@migrations_paths)
1058
- end
1107
+ def migrations
1108
+ migrations = migration_files.map do |file|
1109
+ version, name, scope = parse_migration_filename(file)
1110
+ raise IllegalMigrationNameError.new(file) unless version
1111
+ version = version.to_i
1112
+ name = name.camelize
1059
1113
 
1060
- def parse_migration_filename(filename) # :nodoc:
1061
- File.basename(filename).scan(Migration::MigrationFilenameRegexp).first
1114
+ MigrationProxy.new(name, version, file, scope)
1062
1115
  end
1063
1116
 
1064
- def migrations(paths)
1065
- paths = Array(paths)
1117
+ migrations.sort_by(&:version)
1118
+ end
1066
1119
 
1067
- migrations = migration_files(paths).map do |file|
1068
- version, name, scope = parse_migration_filename(file)
1069
- raise IllegalMigrationNameError.new(file) unless version
1070
- version = version.to_i
1071
- name = name.camelize
1120
+ def migrations_status
1121
+ db_list = schema_migration.normalized_versions
1072
1122
 
1073
- MigrationProxy.new(name, version, file, scope)
1074
- end
1123
+ file_list = migration_files.map do |file|
1124
+ version, name, scope = parse_migration_filename(file)
1125
+ raise IllegalMigrationNameError.new(file) unless version
1126
+ version = schema_migration.normalize_migration_number(version)
1127
+ status = db_list.delete(version) ? "up" : "down"
1128
+ [status, version, (name + scope).humanize]
1129
+ end.compact
1075
1130
 
1076
- migrations.sort_by(&:version)
1131
+ db_list.map! do |version|
1132
+ ["up", version, "********** NO FILE **********"]
1077
1133
  end
1078
1134
 
1079
- def migrations_status(paths)
1080
- paths = Array(paths)
1135
+ (db_list + file_list).sort_by { |_, version, _| version }
1136
+ end
1081
1137
 
1082
- db_list = ActiveRecord::SchemaMigration.normalized_versions
1138
+ def current_environment
1139
+ ActiveRecord::ConnectionHandling::DEFAULT_ENV.call
1140
+ end
1083
1141
 
1084
- file_list = migration_files(paths).map do |file|
1085
- version, name, scope = parse_migration_filename(file)
1086
- raise IllegalMigrationNameError.new(file) unless version
1087
- version = ActiveRecord::SchemaMigration.normalize_migration_number(version)
1088
- status = db_list.delete(version) ? "up" : "down"
1089
- [status, version, (name + scope).humanize]
1090
- end.compact
1142
+ def protected_environment?
1143
+ ActiveRecord::Base.protected_environments.include?(last_stored_environment) if last_stored_environment
1144
+ end
1091
1145
 
1092
- db_list.map! do |version|
1093
- ["up", version, "********** NO FILE **********"]
1094
- end
1146
+ def last_stored_environment
1147
+ return nil if current_version == 0
1148
+ raise NoEnvironmentInSchemaError unless ActiveRecord::InternalMetadata.table_exists?
1095
1149
 
1096
- (db_list + file_list).sort_by { |_, version, _| version }
1097
- end
1150
+ environment = ActiveRecord::InternalMetadata[:environment]
1151
+ raise NoEnvironmentInSchemaError unless environment
1152
+ environment
1153
+ end
1098
1154
 
1099
- def migration_files(paths)
1155
+ private
1156
+ def migration_files
1157
+ paths = Array(migrations_paths)
1100
1158
  Dir[*paths.flat_map { |path| "#{path}/**/[0-9]*_*.rb" }]
1101
1159
  end
1102
1160
 
1103
- private
1161
+ def parse_migration_filename(filename)
1162
+ File.basename(filename).scan(Migration::MigrationFilenameRegexp).first
1163
+ end
1104
1164
 
1105
- def move(direction, migrations_paths, steps)
1106
- migrator = new(direction, migrations(migrations_paths))
1107
- start_index = migrator.migrations.index(migrator.current_migration)
1165
+ def move(direction, steps)
1166
+ migrator = Migrator.new(direction, migrations, schema_migration)
1108
1167
 
1109
- if start_index
1110
- finish = migrator.migrations[start_index + steps]
1111
- version = finish ? finish.version : 0
1112
- send(direction, migrations_paths, version)
1168
+ if current_version != 0 && !migrator.current_migration
1169
+ raise UnknownMigrationVersionError.new(current_version)
1113
1170
  end
1171
+
1172
+ start_index =
1173
+ if current_version == 0
1174
+ 0
1175
+ else
1176
+ migrator.migrations.index(migrator.current_migration)
1177
+ end
1178
+
1179
+ finish = migrator.migrations[start_index + steps]
1180
+ version = finish ? finish.version : 0
1181
+ send(direction, version)
1182
+ end
1183
+ end
1184
+
1185
+ class Migrator # :nodoc:
1186
+ class << self
1187
+ attr_accessor :migrations_paths
1188
+
1189
+ # For cases where a table doesn't exist like loading from schema cache
1190
+ def current_version
1191
+ MigrationContext.new(migrations_paths, SchemaMigration).current_version
1114
1192
  end
1115
1193
  end
1116
1194
 
1117
- def initialize(direction, migrations, target_version = nil)
1118
- raise StandardError.new("This database does not yet support migrations") unless Base.connection.supports_migrations?
1195
+ self.migrations_paths = ["db/migrate"]
1119
1196
 
1197
+ def initialize(direction, migrations, schema_migration, target_version = nil)
1120
1198
  @direction = direction
1121
1199
  @target_version = target_version
1122
1200
  @migrated_versions = nil
1123
1201
  @migrations = migrations
1202
+ @schema_migration = schema_migration
1124
1203
 
1125
1204
  validate(@migrations)
1126
1205
 
1127
- Base.connection.initialize_schema_migrations_table
1128
- Base.connection.initialize_internal_metadata_table
1206
+ @schema_migration.create_table
1207
+ ActiveRecord::InternalMetadata.create_table
1129
1208
  end
1130
1209
 
1131
1210
  def current_version
@@ -1178,153 +1257,141 @@ module ActiveRecord
1178
1257
  end
1179
1258
 
1180
1259
  def load_migrated
1181
- @migrated_versions = Set.new(self.class.get_all_versions)
1260
+ @migrated_versions = Set.new(@schema_migration.all_versions.map(&:to_i))
1182
1261
  end
1183
1262
 
1184
1263
  private
1264
+ # Used for running a specific migration.
1265
+ def run_without_lock
1266
+ migration = migrations.detect { |m| m.version == @target_version }
1267
+ raise UnknownMigrationVersionError.new(@target_version) if migration.nil?
1268
+ result = execute_migration_in_transaction(migration, @direction)
1269
+
1270
+ record_environment
1271
+ result
1272
+ end
1185
1273
 
1186
- # Used for running a specific migration.
1187
- def run_without_lock
1188
- migration = migrations.detect { |m| m.version == @target_version }
1189
- raise UnknownMigrationVersionError.new(@target_version) if migration.nil?
1190
- result = execute_migration_in_transaction(migration, @direction)
1274
+ # Used for running multiple migrations up to or down to a certain value.
1275
+ def migrate_without_lock
1276
+ if invalid_target?
1277
+ raise UnknownMigrationVersionError.new(@target_version)
1278
+ end
1191
1279
 
1192
- record_environment
1193
- result
1194
- end
1280
+ result = runnable.each do |migration|
1281
+ execute_migration_in_transaction(migration, @direction)
1282
+ end
1195
1283
 
1196
- # Used for running multiple migrations up to or down to a certain value.
1197
- def migrate_without_lock
1198
- if invalid_target?
1199
- raise UnknownMigrationVersionError.new(@target_version)
1284
+ record_environment
1285
+ result
1200
1286
  end
1201
1287
 
1202
- result = runnable.each do |migration|
1203
- execute_migration_in_transaction(migration, @direction)
1288
+ # Stores the current environment in the database.
1289
+ def record_environment
1290
+ return if down?
1291
+ ActiveRecord::InternalMetadata[:environment] = ActiveRecord::Base.connection.migration_context.current_environment
1204
1292
  end
1205
1293
 
1206
- record_environment
1207
- result
1208
- end
1209
-
1210
- # Stores the current environment in the database.
1211
- def record_environment
1212
- return if down?
1213
- ActiveRecord::InternalMetadata[:environment] = ActiveRecord::Migrator.current_environment
1214
- end
1215
-
1216
- def ran?(migration)
1217
- migrated.include?(migration.version.to_i)
1218
- end
1294
+ def ran?(migration)
1295
+ migrated.include?(migration.version.to_i)
1296
+ end
1219
1297
 
1220
- # Return true if a valid version is not provided.
1221
- def invalid_target?
1222
- !target && @target_version && @target_version > 0
1223
- end
1298
+ # Return true if a valid version is not provided.
1299
+ def invalid_target?
1300
+ @target_version && @target_version != 0 && !target
1301
+ end
1224
1302
 
1225
- def execute_migration_in_transaction(migration, direction)
1226
- return if down? && !migrated.include?(migration.version.to_i)
1227
- return if up? && migrated.include?(migration.version.to_i)
1303
+ def execute_migration_in_transaction(migration, direction)
1304
+ return if down? && !migrated.include?(migration.version.to_i)
1305
+ return if up? && migrated.include?(migration.version.to_i)
1228
1306
 
1229
- Base.logger.info "Migrating to #{migration.name} (#{migration.version})" if Base.logger
1307
+ Base.logger.info "Migrating to #{migration.name} (#{migration.version})" if Base.logger
1230
1308
 
1231
- ddl_transaction(migration) do
1232
- migration.migrate(direction)
1233
- record_version_state_after_migrating(migration.version)
1309
+ ddl_transaction(migration) do
1310
+ migration.migrate(direction)
1311
+ record_version_state_after_migrating(migration.version)
1312
+ end
1313
+ rescue => e
1314
+ msg = +"An error has occurred, "
1315
+ msg << "this and " if use_transaction?(migration)
1316
+ msg << "all later migrations canceled:\n\n#{e}"
1317
+ raise StandardError, msg, e.backtrace
1234
1318
  end
1235
- rescue => e
1236
- msg = "An error has occurred, "
1237
- msg << "this and " if use_transaction?(migration)
1238
- msg << "all later migrations canceled:\n\n#{e}"
1239
- raise StandardError, msg, e.backtrace
1240
- end
1241
-
1242
- def target
1243
- migrations.detect { |m| m.version == @target_version }
1244
- end
1245
1319
 
1246
- def finish
1247
- migrations.index(target) || migrations.size - 1
1248
- end
1320
+ def target
1321
+ migrations.detect { |m| m.version == @target_version }
1322
+ end
1249
1323
 
1250
- def start
1251
- up? ? 0 : (migrations.index(current) || 0)
1252
- end
1324
+ def finish
1325
+ migrations.index(target) || migrations.size - 1
1326
+ end
1253
1327
 
1254
- def validate(migrations)
1255
- name ,= migrations.group_by(&:name).find { |_,v| v.length > 1 }
1256
- raise DuplicateMigrationNameError.new(name) if name
1328
+ def start
1329
+ up? ? 0 : (migrations.index(current) || 0)
1330
+ end
1257
1331
 
1258
- version ,= migrations.group_by(&:version).find { |_,v| v.length > 1 }
1259
- raise DuplicateMigrationVersionError.new(version) if version
1260
- end
1332
+ def validate(migrations)
1333
+ name, = migrations.group_by(&:name).find { |_, v| v.length > 1 }
1334
+ raise DuplicateMigrationNameError.new(name) if name
1261
1335
 
1262
- def record_version_state_after_migrating(version)
1263
- if down?
1264
- migrated.delete(version)
1265
- ActiveRecord::SchemaMigration.where(:version => version.to_s).delete_all
1266
- else
1267
- migrated << version
1268
- ActiveRecord::SchemaMigration.create!(version: version.to_s)
1336
+ version, = migrations.group_by(&:version).find { |_, v| v.length > 1 }
1337
+ raise DuplicateMigrationVersionError.new(version) if version
1269
1338
  end
1270
- end
1271
1339
 
1272
- def self.last_stored_environment
1273
- return nil if current_version == 0
1274
- raise NoEnvironmentInSchemaError unless ActiveRecord::InternalMetadata.table_exists?
1340
+ def record_version_state_after_migrating(version)
1341
+ if down?
1342
+ migrated.delete(version)
1343
+ @schema_migration.delete_by(version: version.to_s)
1344
+ else
1345
+ migrated << version
1346
+ @schema_migration.create!(version: version.to_s)
1347
+ end
1348
+ end
1275
1349
 
1276
- environment = ActiveRecord::InternalMetadata[:environment]
1277
- raise NoEnvironmentInSchemaError unless environment
1278
- environment
1279
- end
1350
+ def up?
1351
+ @direction == :up
1352
+ end
1280
1353
 
1281
- def self.current_environment
1282
- ActiveRecord::ConnectionHandling::DEFAULT_ENV.call
1283
- end
1354
+ def down?
1355
+ @direction == :down
1356
+ end
1284
1357
 
1285
- def self.protected_environment?
1286
- ActiveRecord::Base.protected_environments.include?(last_stored_environment) if last_stored_environment
1287
- end
1358
+ # Wrap the migration in a transaction only if supported by the adapter.
1359
+ def ddl_transaction(migration)
1360
+ if use_transaction?(migration)
1361
+ Base.transaction { yield }
1362
+ else
1363
+ yield
1364
+ end
1365
+ end
1288
1366
 
1289
- def up?
1290
- @direction == :up
1291
- end
1367
+ def use_transaction?(migration)
1368
+ !migration.disable_ddl_transaction && Base.connection.supports_ddl_transactions?
1369
+ end
1292
1370
 
1293
- def down?
1294
- @direction == :down
1295
- end
1371
+ def use_advisory_lock?
1372
+ Base.connection.advisory_locks_enabled?
1373
+ end
1296
1374
 
1297
- # Wrap the migration in a transaction only if supported by the adapter.
1298
- def ddl_transaction(migration)
1299
- if use_transaction?(migration)
1300
- Base.transaction { yield }
1301
- else
1375
+ def with_advisory_lock
1376
+ lock_id = generate_migrator_advisory_lock_id
1377
+ AdvisoryLockBase.establish_connection(ActiveRecord::Base.connection_config) unless AdvisoryLockBase.connected?
1378
+ connection = AdvisoryLockBase.connection
1379
+ got_lock = connection.get_advisory_lock(lock_id)
1380
+ raise ConcurrentMigrationError unless got_lock
1381
+ load_migrated # reload schema_migrations to be sure it wasn't changed by another process before we got the lock
1302
1382
  yield
1383
+ ensure
1384
+ if got_lock && !connection.release_advisory_lock(lock_id)
1385
+ raise ConcurrentMigrationError.new(
1386
+ ConcurrentMigrationError::RELEASE_LOCK_FAILED_MESSAGE
1387
+ )
1388
+ end
1303
1389
  end
1304
- end
1305
1390
 
1306
- def use_transaction?(migration)
1307
- !migration.disable_ddl_transaction && Base.connection.supports_ddl_transactions?
1308
- end
1309
-
1310
- def use_advisory_lock?
1311
- Base.connection.supports_advisory_locks?
1312
- end
1313
-
1314
- def with_advisory_lock
1315
- lock_id = generate_migrator_advisory_lock_id
1316
- got_lock = Base.connection.get_advisory_lock(lock_id)
1317
- raise ConcurrentMigrationError unless got_lock
1318
- load_migrated # reload schema_migrations to be sure it wasn't changed by another process before we got the lock
1319
- yield
1320
- ensure
1321
- Base.connection.release_advisory_lock(lock_id) if got_lock
1322
- end
1323
-
1324
- MIGRATOR_SALT = 2053462845
1325
- def generate_migrator_advisory_lock_id
1326
- db_name_hash = Zlib.crc32(Base.connection.current_database)
1327
- MIGRATOR_SALT * db_name_hash
1328
- end
1391
+ MIGRATOR_SALT = 2053462845
1392
+ def generate_migrator_advisory_lock_id
1393
+ db_name_hash = Zlib.crc32(Base.connection.current_database)
1394
+ MIGRATOR_SALT * db_name_hash
1395
+ end
1329
1396
  end
1330
1397
  end