activerecord 5.2.8 → 7.0.2

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 (364) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +1393 -587
  3. data/MIT-LICENSE +3 -1
  4. data/README.rdoc +7 -5
  5. data/examples/performance.rb +1 -1
  6. data/lib/active_record/aggregations.rb +10 -9
  7. data/lib/active_record/association_relation.rb +22 -12
  8. data/lib/active_record/associations/alias_tracker.rb +19 -16
  9. data/lib/active_record/associations/association.rb +122 -47
  10. data/lib/active_record/associations/association_scope.rb +24 -24
  11. data/lib/active_record/associations/belongs_to_association.rb +67 -49
  12. data/lib/active_record/associations/belongs_to_polymorphic_association.rb +16 -7
  13. data/lib/active_record/associations/builder/association.rb +52 -23
  14. data/lib/active_record/associations/builder/belongs_to.rb +44 -61
  15. data/lib/active_record/associations/builder/collection_association.rb +17 -19
  16. data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +17 -41
  17. data/lib/active_record/associations/builder/has_many.rb +10 -3
  18. data/lib/active_record/associations/builder/has_one.rb +35 -3
  19. data/lib/active_record/associations/builder/singular_association.rb +5 -3
  20. data/lib/active_record/associations/collection_association.rb +59 -50
  21. data/lib/active_record/associations/collection_proxy.rb +32 -23
  22. data/lib/active_record/associations/disable_joins_association_scope.rb +59 -0
  23. data/lib/active_record/associations/foreign_association.rb +20 -0
  24. data/lib/active_record/associations/has_many_association.rb +27 -14
  25. data/lib/active_record/associations/has_many_through_association.rb +26 -19
  26. data/lib/active_record/associations/has_one_association.rb +52 -37
  27. data/lib/active_record/associations/has_one_through_association.rb +6 -6
  28. data/lib/active_record/associations/join_dependency/join_association.rb +44 -22
  29. data/lib/active_record/associations/join_dependency/join_part.rb +5 -5
  30. data/lib/active_record/associations/join_dependency.rb +97 -62
  31. data/lib/active_record/associations/preloader/association.rb +220 -60
  32. data/lib/active_record/associations/preloader/batch.rb +48 -0
  33. data/lib/active_record/associations/preloader/branch.rb +147 -0
  34. data/lib/active_record/associations/preloader/through_association.rb +85 -40
  35. data/lib/active_record/associations/preloader.rb +44 -105
  36. data/lib/active_record/associations/singular_association.rb +9 -17
  37. data/lib/active_record/associations/through_association.rb +4 -4
  38. data/lib/active_record/associations.rb +207 -66
  39. data/lib/active_record/asynchronous_queries_tracker.rb +60 -0
  40. data/lib/active_record/attribute_assignment.rb +17 -19
  41. data/lib/active_record/attribute_methods/before_type_cast.rb +19 -8
  42. data/lib/active_record/attribute_methods/dirty.rb +141 -47
  43. data/lib/active_record/attribute_methods/primary_key.rb +22 -27
  44. data/lib/active_record/attribute_methods/query.rb +6 -10
  45. data/lib/active_record/attribute_methods/read.rb +15 -55
  46. data/lib/active_record/attribute_methods/serialization.rb +77 -18
  47. data/lib/active_record/attribute_methods/time_zone_conversion.rb +16 -18
  48. data/lib/active_record/attribute_methods/write.rb +18 -37
  49. data/lib/active_record/attribute_methods.rb +90 -153
  50. data/lib/active_record/attributes.rb +38 -12
  51. data/lib/active_record/autosave_association.rb +50 -50
  52. data/lib/active_record/base.rb +23 -18
  53. data/lib/active_record/callbacks.rb +159 -44
  54. data/lib/active_record/coders/yaml_column.rb +12 -3
  55. data/lib/active_record/connection_adapters/abstract/connection_handler.rb +292 -0
  56. data/lib/active_record/connection_adapters/abstract/connection_pool/queue.rb +209 -0
  57. data/lib/active_record/connection_adapters/abstract/connection_pool/reaper.rb +76 -0
  58. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +92 -464
  59. data/lib/active_record/connection_adapters/abstract/database_limits.rb +5 -51
  60. data/lib/active_record/connection_adapters/abstract/database_statements.rb +209 -164
  61. data/lib/active_record/connection_adapters/abstract/query_cache.rb +38 -22
  62. data/lib/active_record/connection_adapters/abstract/quoting.rb +103 -82
  63. data/lib/active_record/connection_adapters/abstract/savepoints.rb +3 -3
  64. data/lib/active_record/connection_adapters/abstract/schema_creation.rb +140 -110
  65. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +236 -94
  66. data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +16 -5
  67. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +456 -159
  68. data/lib/active_record/connection_adapters/abstract/transaction.rb +169 -78
  69. data/lib/active_record/connection_adapters/abstract_adapter.rb +367 -162
  70. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +311 -327
  71. data/lib/active_record/connection_adapters/column.rb +33 -11
  72. data/lib/active_record/connection_adapters/deduplicable.rb +29 -0
  73. data/lib/active_record/connection_adapters/legacy_pool_manager.rb +35 -0
  74. data/lib/active_record/connection_adapters/mysql/column.rb +1 -1
  75. data/lib/active_record/connection_adapters/mysql/database_statements.rb +113 -45
  76. data/lib/active_record/connection_adapters/mysql/explain_pretty_printer.rb +1 -2
  77. data/lib/active_record/connection_adapters/mysql/quoting.rb +71 -5
  78. data/lib/active_record/connection_adapters/mysql/schema_creation.rb +34 -10
  79. data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +48 -32
  80. data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +25 -8
  81. data/lib/active_record/connection_adapters/mysql/schema_statements.rb +143 -19
  82. data/lib/active_record/connection_adapters/mysql/type_metadata.rb +14 -9
  83. data/lib/active_record/connection_adapters/mysql2_adapter.rb +63 -22
  84. data/lib/active_record/connection_adapters/pool_config.rb +73 -0
  85. data/lib/active_record/connection_adapters/pool_manager.rb +47 -0
  86. data/lib/active_record/connection_adapters/postgresql/column.rb +53 -28
  87. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +56 -63
  88. data/lib/active_record/connection_adapters/postgresql/oid/array.rb +1 -2
  89. data/lib/active_record/connection_adapters/postgresql/oid/bit.rb +1 -4
  90. data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +3 -5
  91. data/lib/active_record/connection_adapters/postgresql/oid/date.rb +10 -2
  92. data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +15 -2
  93. data/lib/active_record/connection_adapters/postgresql/oid/enum.rb +0 -1
  94. data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +54 -16
  95. data/lib/active_record/connection_adapters/postgresql/oid/interval.rb +49 -0
  96. data/lib/active_record/connection_adapters/postgresql/oid/legacy_point.rb +3 -4
  97. data/lib/active_record/connection_adapters/postgresql/oid/macaddr.rb +25 -0
  98. data/lib/active_record/connection_adapters/postgresql/oid/oid.rb +1 -1
  99. data/lib/active_record/connection_adapters/postgresql/oid/point.rb +3 -4
  100. data/lib/active_record/connection_adapters/postgresql/oid/range.rb +25 -7
  101. data/lib/active_record/connection_adapters/postgresql/oid/specialized_string.rb +1 -1
  102. data/lib/active_record/connection_adapters/postgresql/oid/timestamp.rb +15 -0
  103. data/lib/active_record/connection_adapters/postgresql/oid/timestamp_with_time_zone.rb +30 -0
  104. data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +26 -12
  105. data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +15 -3
  106. data/lib/active_record/connection_adapters/postgresql/oid.rb +4 -0
  107. data/lib/active_record/connection_adapters/postgresql/quoting.rb +89 -52
  108. data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +34 -2
  109. data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +39 -4
  110. data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +128 -91
  111. data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +25 -1
  112. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +149 -113
  113. data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +31 -26
  114. data/lib/active_record/connection_adapters/postgresql/utils.rb +0 -1
  115. data/lib/active_record/connection_adapters/postgresql_adapter.rb +386 -182
  116. data/lib/active_record/connection_adapters/schema_cache.rb +161 -22
  117. data/lib/active_record/connection_adapters/sql_type_metadata.rb +17 -6
  118. data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +152 -0
  119. data/lib/active_record/connection_adapters/sqlite3/quoting.rb +65 -18
  120. data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +5 -1
  121. data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +92 -26
  122. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +251 -204
  123. data/lib/active_record/connection_adapters/statement_pool.rb +0 -1
  124. data/lib/active_record/connection_adapters.rb +53 -0
  125. data/lib/active_record/connection_handling.rb +292 -38
  126. data/lib/active_record/core.rb +385 -158
  127. data/lib/active_record/counter_cache.rb +8 -30
  128. data/lib/active_record/database_configurations/connection_url_resolver.rb +100 -0
  129. data/lib/active_record/database_configurations/database_config.rb +83 -0
  130. data/lib/active_record/database_configurations/hash_config.rb +154 -0
  131. data/lib/active_record/database_configurations/url_config.rb +53 -0
  132. data/lib/active_record/database_configurations.rb +256 -0
  133. data/lib/active_record/delegated_type.rb +250 -0
  134. data/lib/active_record/destroy_association_async_job.rb +36 -0
  135. data/lib/active_record/disable_joins_association_relation.rb +39 -0
  136. data/lib/active_record/dynamic_matchers.rb +4 -5
  137. data/lib/active_record/encryption/cipher/aes256_gcm.rb +98 -0
  138. data/lib/active_record/encryption/cipher.rb +53 -0
  139. data/lib/active_record/encryption/config.rb +44 -0
  140. data/lib/active_record/encryption/configurable.rb +61 -0
  141. data/lib/active_record/encryption/context.rb +35 -0
  142. data/lib/active_record/encryption/contexts.rb +72 -0
  143. data/lib/active_record/encryption/derived_secret_key_provider.rb +12 -0
  144. data/lib/active_record/encryption/deterministic_key_provider.rb +14 -0
  145. data/lib/active_record/encryption/encryptable_record.rb +208 -0
  146. data/lib/active_record/encryption/encrypted_attribute_type.rb +140 -0
  147. data/lib/active_record/encryption/encrypted_fixtures.rb +38 -0
  148. data/lib/active_record/encryption/encrypting_only_encryptor.rb +12 -0
  149. data/lib/active_record/encryption/encryptor.rb +155 -0
  150. data/lib/active_record/encryption/envelope_encryption_key_provider.rb +55 -0
  151. data/lib/active_record/encryption/errors.rb +15 -0
  152. data/lib/active_record/encryption/extended_deterministic_queries.rb +160 -0
  153. data/lib/active_record/encryption/extended_deterministic_uniqueness_validator.rb +28 -0
  154. data/lib/active_record/encryption/key.rb +28 -0
  155. data/lib/active_record/encryption/key_generator.rb +42 -0
  156. data/lib/active_record/encryption/key_provider.rb +46 -0
  157. data/lib/active_record/encryption/message.rb +33 -0
  158. data/lib/active_record/encryption/message_serializer.rb +90 -0
  159. data/lib/active_record/encryption/null_encryptor.rb +21 -0
  160. data/lib/active_record/encryption/properties.rb +76 -0
  161. data/lib/active_record/encryption/read_only_null_encryptor.rb +24 -0
  162. data/lib/active_record/encryption/scheme.rb +99 -0
  163. data/lib/active_record/encryption.rb +55 -0
  164. data/lib/active_record/enum.rb +130 -51
  165. data/lib/active_record/errors.rb +129 -23
  166. data/lib/active_record/explain.rb +10 -6
  167. data/lib/active_record/explain_registry.rb +11 -6
  168. data/lib/active_record/explain_subscriber.rb +1 -1
  169. data/lib/active_record/fixture_set/file.rb +22 -15
  170. data/lib/active_record/fixture_set/model_metadata.rb +32 -0
  171. data/lib/active_record/fixture_set/render_context.rb +17 -0
  172. data/lib/active_record/fixture_set/table_row.rb +187 -0
  173. data/lib/active_record/fixture_set/table_rows.rb +46 -0
  174. data/lib/active_record/fixtures.rb +206 -490
  175. data/lib/active_record/future_result.rb +139 -0
  176. data/lib/active_record/gem_version.rb +3 -3
  177. data/lib/active_record/inheritance.rb +104 -37
  178. data/lib/active_record/insert_all.rb +278 -0
  179. data/lib/active_record/integration.rb +69 -18
  180. data/lib/active_record/internal_metadata.rb +24 -9
  181. data/lib/active_record/legacy_yaml_adapter.rb +3 -36
  182. data/lib/active_record/locking/optimistic.rb +41 -26
  183. data/lib/active_record/locking/pessimistic.rb +18 -8
  184. data/lib/active_record/log_subscriber.rb +46 -35
  185. data/lib/active_record/middleware/database_selector/resolver/session.rb +48 -0
  186. data/lib/active_record/middleware/database_selector/resolver.rb +88 -0
  187. data/lib/active_record/middleware/database_selector.rb +82 -0
  188. data/lib/active_record/middleware/shard_selector.rb +60 -0
  189. data/lib/active_record/migration/command_recorder.rb +96 -44
  190. data/lib/active_record/migration/compatibility.rb +246 -64
  191. data/lib/active_record/migration/join_table.rb +1 -2
  192. data/lib/active_record/migration.rb +266 -187
  193. data/lib/active_record/model_schema.rb +165 -52
  194. data/lib/active_record/nested_attributes.rb +17 -19
  195. data/lib/active_record/no_touching.rb +11 -4
  196. data/lib/active_record/null_relation.rb +2 -7
  197. data/lib/active_record/persistence.rb +467 -92
  198. data/lib/active_record/query_cache.rb +21 -4
  199. data/lib/active_record/query_logs.rb +138 -0
  200. data/lib/active_record/querying.rb +51 -24
  201. data/lib/active_record/railtie.rb +224 -57
  202. data/lib/active_record/railties/console_sandbox.rb +2 -4
  203. data/lib/active_record/railties/controller_runtime.rb +31 -36
  204. data/lib/active_record/railties/databases.rake +369 -101
  205. data/lib/active_record/readonly_attributes.rb +15 -0
  206. data/lib/active_record/reflection.rb +170 -137
  207. data/lib/active_record/relation/batches/batch_enumerator.rb +44 -14
  208. data/lib/active_record/relation/batches.rb +46 -37
  209. data/lib/active_record/relation/calculations.rb +168 -96
  210. data/lib/active_record/relation/delegation.rb +37 -52
  211. data/lib/active_record/relation/finder_methods.rb +79 -58
  212. data/lib/active_record/relation/from_clause.rb +5 -1
  213. data/lib/active_record/relation/merger.rb +50 -51
  214. data/lib/active_record/relation/predicate_builder/array_handler.rb +13 -13
  215. data/lib/active_record/relation/predicate_builder/association_query_value.rb +5 -9
  216. data/lib/active_record/relation/predicate_builder/basic_object_handler.rb +1 -2
  217. data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +11 -10
  218. data/lib/active_record/relation/predicate_builder/range_handler.rb +3 -23
  219. data/lib/active_record/relation/predicate_builder/relation_handler.rb +1 -1
  220. data/lib/active_record/relation/predicate_builder.rb +58 -46
  221. data/lib/active_record/relation/query_attribute.rb +9 -10
  222. data/lib/active_record/relation/query_methods.rb +685 -208
  223. data/lib/active_record/relation/record_fetch_warning.rb +9 -11
  224. data/lib/active_record/relation/spawn_methods.rb +10 -10
  225. data/lib/active_record/relation/where_clause.rb +108 -64
  226. data/lib/active_record/relation.rb +515 -151
  227. data/lib/active_record/result.rb +78 -42
  228. data/lib/active_record/runtime_registry.rb +9 -13
  229. data/lib/active_record/sanitization.rb +29 -44
  230. data/lib/active_record/schema.rb +37 -31
  231. data/lib/active_record/schema_dumper.rb +74 -23
  232. data/lib/active_record/schema_migration.rb +7 -9
  233. data/lib/active_record/scoping/default.rb +62 -17
  234. data/lib/active_record/scoping/named.rb +17 -32
  235. data/lib/active_record/scoping.rb +70 -41
  236. data/lib/active_record/secure_token.rb +16 -8
  237. data/lib/active_record/serialization.rb +6 -4
  238. data/lib/active_record/signed_id.rb +116 -0
  239. data/lib/active_record/statement_cache.rb +49 -6
  240. data/lib/active_record/store.rb +88 -9
  241. data/lib/active_record/suppressor.rb +13 -17
  242. data/lib/active_record/table_metadata.rb +42 -43
  243. data/lib/active_record/tasks/database_tasks.rb +352 -94
  244. data/lib/active_record/tasks/mysql_database_tasks.rb +37 -39
  245. data/lib/active_record/tasks/postgresql_database_tasks.rb +41 -39
  246. data/lib/active_record/tasks/sqlite_database_tasks.rb +14 -17
  247. data/lib/active_record/test_databases.rb +24 -0
  248. data/lib/active_record/test_fixtures.rb +287 -0
  249. data/lib/active_record/timestamp.rb +44 -34
  250. data/lib/active_record/touch_later.rb +23 -22
  251. data/lib/active_record/transactions.rb +67 -128
  252. data/lib/active_record/translation.rb +3 -3
  253. data/lib/active_record/type/adapter_specific_registry.rb +34 -19
  254. data/lib/active_record/type/hash_lookup_type_map.rb +34 -2
  255. data/lib/active_record/type/internal/timezone.rb +2 -2
  256. data/lib/active_record/type/serialized.rb +7 -4
  257. data/lib/active_record/type/time.rb +10 -0
  258. data/lib/active_record/type/type_map.rb +17 -21
  259. data/lib/active_record/type/unsigned_integer.rb +0 -1
  260. data/lib/active_record/type.rb +9 -5
  261. data/lib/active_record/type_caster/connection.rb +15 -15
  262. data/lib/active_record/type_caster/map.rb +8 -8
  263. data/lib/active_record/validations/associated.rb +2 -3
  264. data/lib/active_record/validations/numericality.rb +35 -0
  265. data/lib/active_record/validations/uniqueness.rb +39 -31
  266. data/lib/active_record/validations.rb +4 -3
  267. data/lib/active_record.rb +209 -32
  268. data/lib/arel/alias_predication.rb +9 -0
  269. data/lib/arel/attributes/attribute.rb +33 -0
  270. data/lib/arel/collectors/bind.rb +29 -0
  271. data/lib/arel/collectors/composite.rb +39 -0
  272. data/lib/arel/collectors/plain_string.rb +20 -0
  273. data/lib/arel/collectors/sql_string.rb +27 -0
  274. data/lib/arel/collectors/substitute_binds.rb +35 -0
  275. data/lib/arel/crud.rb +48 -0
  276. data/lib/arel/delete_manager.rb +32 -0
  277. data/lib/arel/errors.rb +9 -0
  278. data/lib/arel/expressions.rb +29 -0
  279. data/lib/arel/factory_methods.rb +49 -0
  280. data/lib/arel/filter_predications.rb +9 -0
  281. data/lib/arel/insert_manager.rb +48 -0
  282. data/lib/arel/math.rb +45 -0
  283. data/lib/arel/nodes/and.rb +32 -0
  284. data/lib/arel/nodes/ascending.rb +23 -0
  285. data/lib/arel/nodes/binary.rb +126 -0
  286. data/lib/arel/nodes/bind_param.rb +44 -0
  287. data/lib/arel/nodes/case.rb +55 -0
  288. data/lib/arel/nodes/casted.rb +62 -0
  289. data/lib/arel/nodes/comment.rb +29 -0
  290. data/lib/arel/nodes/count.rb +12 -0
  291. data/lib/arel/nodes/delete_statement.rb +44 -0
  292. data/lib/arel/nodes/descending.rb +23 -0
  293. data/lib/arel/nodes/equality.rb +15 -0
  294. data/lib/arel/nodes/extract.rb +24 -0
  295. data/lib/arel/nodes/false.rb +16 -0
  296. data/lib/arel/nodes/filter.rb +10 -0
  297. data/lib/arel/nodes/full_outer_join.rb +8 -0
  298. data/lib/arel/nodes/function.rb +45 -0
  299. data/lib/arel/nodes/grouping.rb +11 -0
  300. data/lib/arel/nodes/homogeneous_in.rb +76 -0
  301. data/lib/arel/nodes/in.rb +15 -0
  302. data/lib/arel/nodes/infix_operation.rb +92 -0
  303. data/lib/arel/nodes/inner_join.rb +8 -0
  304. data/lib/arel/nodes/insert_statement.rb +37 -0
  305. data/lib/arel/nodes/join_source.rb +20 -0
  306. data/lib/arel/nodes/matches.rb +18 -0
  307. data/lib/arel/nodes/named_function.rb +23 -0
  308. data/lib/arel/nodes/node.rb +51 -0
  309. data/lib/arel/nodes/node_expression.rb +13 -0
  310. data/lib/arel/nodes/ordering.rb +27 -0
  311. data/lib/arel/nodes/outer_join.rb +8 -0
  312. data/lib/arel/nodes/over.rb +15 -0
  313. data/lib/arel/nodes/regexp.rb +16 -0
  314. data/lib/arel/nodes/right_outer_join.rb +8 -0
  315. data/lib/arel/nodes/select_core.rb +67 -0
  316. data/lib/arel/nodes/select_statement.rb +41 -0
  317. data/lib/arel/nodes/sql_literal.rb +19 -0
  318. data/lib/arel/nodes/string_join.rb +11 -0
  319. data/lib/arel/nodes/table_alias.rb +31 -0
  320. data/lib/arel/nodes/terminal.rb +16 -0
  321. data/lib/arel/nodes/true.rb +16 -0
  322. data/lib/arel/nodes/unary.rb +44 -0
  323. data/lib/arel/nodes/unary_operation.rb +20 -0
  324. data/lib/arel/nodes/unqualified_column.rb +22 -0
  325. data/lib/arel/nodes/update_statement.rb +46 -0
  326. data/lib/arel/nodes/values_list.rb +9 -0
  327. data/lib/arel/nodes/window.rb +126 -0
  328. data/lib/arel/nodes/with.rb +11 -0
  329. data/lib/arel/nodes.rb +71 -0
  330. data/lib/arel/order_predications.rb +13 -0
  331. data/lib/arel/predications.rb +258 -0
  332. data/lib/arel/select_manager.rb +276 -0
  333. data/lib/arel/table.rb +117 -0
  334. data/lib/arel/tree_manager.rb +60 -0
  335. data/lib/arel/update_manager.rb +48 -0
  336. data/lib/arel/visitors/dot.rb +298 -0
  337. data/lib/arel/visitors/mysql.rb +99 -0
  338. data/lib/arel/visitors/postgresql.rb +110 -0
  339. data/lib/arel/visitors/sqlite.rb +38 -0
  340. data/lib/arel/visitors/to_sql.rb +955 -0
  341. data/lib/arel/visitors/visitor.rb +45 -0
  342. data/lib/arel/visitors.rb +13 -0
  343. data/lib/arel/window_predications.rb +9 -0
  344. data/lib/arel.rb +55 -0
  345. data/lib/rails/generators/active_record/application_record/application_record_generator.rb +0 -1
  346. data/lib/rails/generators/active_record/application_record/templates/application_record.rb.tt +1 -1
  347. data/lib/rails/generators/active_record/migration/migration_generator.rb +3 -5
  348. data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb.tt +3 -1
  349. data/lib/rails/generators/active_record/migration/templates/migration.rb.tt +7 -5
  350. data/lib/rails/generators/active_record/migration.rb +19 -2
  351. data/lib/rails/generators/active_record/model/model_generator.rb +39 -2
  352. data/lib/rails/generators/active_record/model/templates/abstract_base_class.rb.tt +7 -0
  353. data/lib/rails/generators/active_record/model/templates/model.rb.tt +10 -1
  354. data/lib/rails/generators/active_record/model/templates/module.rb.tt +2 -2
  355. data/lib/rails/generators/active_record/multi_db/multi_db_generator.rb +16 -0
  356. data/lib/rails/generators/active_record/multi_db/templates/multi_db.rb.tt +44 -0
  357. metadata +162 -32
  358. data/lib/active_record/attribute_decorators.rb +0 -90
  359. data/lib/active_record/collection_cache_key.rb +0 -53
  360. data/lib/active_record/connection_adapters/connection_specification.rb +0 -287
  361. data/lib/active_record/connection_adapters/determine_if_preparable_visitor.rb +0 -33
  362. data/lib/active_record/define_callbacks.rb +0 -22
  363. data/lib/active_record/relation/predicate_builder/base_handler.rb +0 -19
  364. data/lib/active_record/relation/where_clause_factory.rb +0 -34
@@ -1,11 +1,15 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require "benchmark"
3
4
  require "set"
4
5
  require "zlib"
6
+ require "active_support/core_ext/array/access"
7
+ require "active_support/core_ext/enumerable"
5
8
  require "active_support/core_ext/module/attribute_accessors"
9
+ require "active_support/actionable_error"
6
10
 
7
11
  module ActiveRecord
8
- class MigrationError < ActiveRecordError#:nodoc:
12
+ class MigrationError < ActiveRecordError # :nodoc:
9
13
  def initialize(message = nil)
10
14
  message = "\n\n#{message}\n\n" if message
11
15
  super
@@ -16,13 +20,13 @@ module ActiveRecord
16
20
  # For example the following migration is not reversible.
17
21
  # Rolling back this migration will raise an ActiveRecord::IrreversibleMigration error.
18
22
  #
19
- # class IrreversibleMigrationExample < ActiveRecord::Migration[5.0]
23
+ # class IrreversibleMigrationExample < ActiveRecord::Migration[7.0]
20
24
  # def change
21
25
  # create_table :distributors do |t|
22
26
  # t.string :zipcode
23
27
  # end
24
28
  #
25
- # execute <<-SQL
29
+ # execute <<~SQL
26
30
  # ALTER TABLE distributors
27
31
  # ADD CONSTRAINT zipchk
28
32
  # CHECK (char_length(zipcode) = 5) NO INHERIT;
@@ -34,13 +38,13 @@ module ActiveRecord
34
38
  #
35
39
  # 1. Define <tt>#up</tt> and <tt>#down</tt> methods instead of <tt>#change</tt>:
36
40
  #
37
- # class ReversibleMigrationExample < ActiveRecord::Migration[5.0]
41
+ # class ReversibleMigrationExample < ActiveRecord::Migration[7.0]
38
42
  # def up
39
43
  # create_table :distributors do |t|
40
44
  # t.string :zipcode
41
45
  # end
42
46
  #
43
- # execute <<-SQL
47
+ # execute <<~SQL
44
48
  # ALTER TABLE distributors
45
49
  # ADD CONSTRAINT zipchk
46
50
  # CHECK (char_length(zipcode) = 5) NO INHERIT;
@@ -48,7 +52,7 @@ module ActiveRecord
48
52
  # end
49
53
  #
50
54
  # def down
51
- # execute <<-SQL
55
+ # execute <<~SQL
52
56
  # ALTER TABLE distributors
53
57
  # DROP CONSTRAINT zipchk
54
58
  # SQL
@@ -59,7 +63,7 @@ module ActiveRecord
59
63
  #
60
64
  # 2. Use the #reversible method in <tt>#change</tt> method:
61
65
  #
62
- # class ReversibleMigrationExample < ActiveRecord::Migration[5.0]
66
+ # class ReversibleMigrationExample < ActiveRecord::Migration[7.0]
63
67
  # def change
64
68
  # create_table :distributors do |t|
65
69
  # t.string :zipcode
@@ -67,7 +71,7 @@ module ActiveRecord
67
71
  #
68
72
  # reversible do |dir|
69
73
  # dir.up do
70
- # execute <<-SQL
74
+ # execute <<~SQL
71
75
  # ALTER TABLE distributors
72
76
  # ADD CONSTRAINT zipchk
73
77
  # CHECK (char_length(zipcode) = 5) NO INHERIT;
@@ -75,7 +79,7 @@ module ActiveRecord
75
79
  # end
76
80
  #
77
81
  # dir.down do
78
- # execute <<-SQL
82
+ # execute <<~SQL
79
83
  # ALTER TABLE distributors
80
84
  # DROP CONSTRAINT zipchk
81
85
  # SQL
@@ -86,7 +90,7 @@ module ActiveRecord
86
90
  class IrreversibleMigration < MigrationError
87
91
  end
88
92
 
89
- class DuplicateMigrationVersionError < MigrationError#:nodoc:
93
+ class DuplicateMigrationVersionError < MigrationError # :nodoc:
90
94
  def initialize(version = nil)
91
95
  if version
92
96
  super("Multiple migrations have the version number #{version}.")
@@ -96,7 +100,7 @@ module ActiveRecord
96
100
  end
97
101
  end
98
102
 
99
- class DuplicateMigrationNameError < MigrationError#:nodoc:
103
+ class DuplicateMigrationNameError < MigrationError # :nodoc:
100
104
  def initialize(name = nil)
101
105
  if name
102
106
  super("Multiple migrations have the name #{name}.")
@@ -106,7 +110,7 @@ module ActiveRecord
106
110
  end
107
111
  end
108
112
 
109
- class UnknownMigrationVersionError < MigrationError #:nodoc:
113
+ class UnknownMigrationVersionError < MigrationError # :nodoc:
110
114
  def initialize(version = nil)
111
115
  if version
112
116
  super("No migration with version number #{version}.")
@@ -116,7 +120,7 @@ module ActiveRecord
116
120
  end
117
121
  end
118
122
 
119
- class IllegalMigrationNameError < MigrationError#:nodoc:
123
+ class IllegalMigrationNameError < MigrationError # :nodoc:
120
124
  def initialize(name = nil)
121
125
  if name
122
126
  super("Illegal name for migration file: #{name}\n\t(only lower case letters, numbers, and '_' allowed).")
@@ -126,28 +130,51 @@ module ActiveRecord
126
130
  end
127
131
  end
128
132
 
129
- class PendingMigrationError < MigrationError#:nodoc:
130
- def initialize(message = nil)
131
- if !message && defined?(Rails.env)
132
- super("Migrations are pending. To resolve this issue, run:\n\n bin/rails db:migrate RAILS_ENV=#{::Rails.env}")
133
- elsif !message
134
- super("Migrations are pending. To resolve this issue, run:\n\n bin/rails db:migrate")
135
- else
136
- super
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.dump_schema_after_migration
140
+ ActiveRecord::Tasks::DatabaseTasks.dump_schema(
141
+ ActiveRecord::Base.connection_db_config
142
+ )
137
143
  end
138
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
139
166
  end
140
167
 
141
- class ConcurrentMigrationError < MigrationError #:nodoc:
142
- DEFAULT_MESSAGE = "Cannot run migrations because another migration process is currently running.".freeze
143
- RELEASE_LOCK_FAILED_MESSAGE = "Failed to release advisory lock".freeze
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"
144
171
 
145
172
  def initialize(message = DEFAULT_MESSAGE)
146
173
  super
147
174
  end
148
175
  end
149
176
 
150
- class NoEnvironmentInSchemaError < MigrationError #:nodoc:
177
+ class NoEnvironmentInSchemaError < MigrationError # :nodoc:
151
178
  def initialize
152
179
  msg = "Environment data not found in the schema. To resolve this issue, run: \n\n bin/rails db:environment:set"
153
180
  if defined?(Rails.env)
@@ -158,9 +185,9 @@ module ActiveRecord
158
185
  end
159
186
  end
160
187
 
161
- class ProtectedEnvironmentError < ActiveRecordError #:nodoc:
188
+ class ProtectedEnvironmentError < ActiveRecordError # :nodoc:
162
189
  def initialize(env = "production")
163
- msg = "You are attempting to run a destructive action against your '#{env}' database.\n".dup
190
+ msg = +"You are attempting to run a destructive action against your '#{env}' database.\n"
164
191
  msg << "If you are sure you want to continue, run the same command with the environment variable:\n"
165
192
  msg << "DISABLE_DATABASE_ENVIRONMENT_CHECK=1"
166
193
  super(msg)
@@ -169,7 +196,7 @@ module ActiveRecord
169
196
 
170
197
  class EnvironmentMismatchError < ActiveRecordError
171
198
  def initialize(current: nil, stored: nil)
172
- msg = "You are attempting to modify a database that was last run in `#{ stored }` environment.\n".dup
199
+ msg = +"You are attempting to modify a database that was last run in `#{ stored }` environment.\n"
173
200
  msg << "You are running in `#{ current }` environment. "
174
201
  msg << "If you are sure you want to continue, first set the environment using:\n\n"
175
202
  msg << " bin/rails db:environment:set"
@@ -181,6 +208,14 @@ module ActiveRecord
181
208
  end
182
209
  end
183
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
+
184
219
  # = Active Record Migrations
185
220
  #
186
221
  # Migrations can manage the evolution of a schema used by several physical
@@ -193,7 +228,7 @@ module ActiveRecord
193
228
  #
194
229
  # Example of a simple migration:
195
230
  #
196
- # class AddSsl < ActiveRecord::Migration[5.0]
231
+ # class AddSsl < ActiveRecord::Migration[7.0]
197
232
  # def up
198
233
  # add_column :accounts, :ssl_enabled, :boolean, default: true
199
234
  # end
@@ -213,7 +248,7 @@ module ActiveRecord
213
248
  #
214
249
  # Example of a more complex migration that also needs to initialize data:
215
250
  #
216
- # class AddSystemSettings < ActiveRecord::Migration[5.0]
251
+ # class AddSystemSettings < ActiveRecord::Migration[7.0]
217
252
  # def up
218
253
  # create_table :system_settings do |t|
219
254
  # t.string :name
@@ -285,7 +320,7 @@ module ActiveRecord
285
320
  # +table_name+. Passing a hash containing <tt>:from</tt> and <tt>:to</tt>
286
321
  # as +default_or_changes+ will make this change reversible in the migration.
287
322
  # * <tt>change_column_null(table_name, column_name, null, default = nil)</tt>:
288
- # Sets or removes a +NOT NULL+ constraint on +column_name+. The +null+ flag
323
+ # Sets or removes a <tt>NOT NULL</tt> constraint on +column_name+. The +null+ flag
289
324
  # indicates whether the value can be +NULL+. See
290
325
  # ActiveRecord::ConnectionAdapters::SchemaStatements#change_column_null for
291
326
  # details.
@@ -307,7 +342,7 @@ module ActiveRecord
307
342
  # named +column_name+ from the table called +table_name+.
308
343
  # * <tt>remove_columns(table_name, *column_names)</tt>: Removes the given
309
344
  # columns from the table definition.
310
- # * <tt>remove_foreign_key(from_table, options_or_to_table)</tt>: Removes the
345
+ # * <tt>remove_foreign_key(from_table, to_table = nil, **options)</tt>: Removes the
311
346
  # given foreign key from the table called +table_name+.
312
347
  # * <tt>remove_index(table_name, column: column_names)</tt>: Removes the index
313
348
  # specified by +column_names+.
@@ -329,7 +364,7 @@ module ActiveRecord
329
364
  # The Rails package has several tools to help create and apply migrations.
330
365
  #
331
366
  # To generate a new migration, you can use
332
- # rails generate migration MyNewMigration
367
+ # bin/rails generate migration MyNewMigration
333
368
  #
334
369
  # where MyNewMigration is the name of your migration. The generator will
335
370
  # create an empty migration file <tt>timestamp_my_new_migration.rb</tt>
@@ -338,41 +373,36 @@ module ActiveRecord
338
373
  #
339
374
  # There is a special syntactic shortcut to generate migrations that add fields to a table.
340
375
  #
341
- # rails generate migration add_fieldname_to_tablename fieldname:string
376
+ # bin/rails generate migration add_fieldname_to_tablename fieldname:string
342
377
  #
343
378
  # This will generate the file <tt>timestamp_add_fieldname_to_tablename.rb</tt>, which will look like this:
344
- # class AddFieldnameToTablename < ActiveRecord::Migration[5.0]
379
+ # class AddFieldnameToTablename < ActiveRecord::Migration[7.0]
345
380
  # def change
346
381
  # add_column :tablenames, :fieldname, :string
347
382
  # end
348
383
  # end
349
384
  #
350
385
  # To run migrations against the currently configured database, use
351
- # <tt>rails 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
352
387
  # pending migrations, creating the <tt>schema_migrations</tt> table
353
388
  # (see "About the schema_migrations table" section below) if missing. It will also
354
- # 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
355
390
  # to match the structure of your database.
356
391
  #
357
392
  # To roll the database back to a previous migration version, use
358
- # <tt>rails db:rollback 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
359
394
  # you wish to downgrade. Alternatively, you can also use the STEP option if you
360
- # wish to rollback last few migrations. <tt>rails db:rollback STEP=2</tt> will rollback
395
+ # wish to rollback last few migrations. <tt>bin/rails db:rollback STEP=2</tt> will rollback
361
396
  # the latest two migrations.
362
397
  #
363
398
  # If any of the migrations throw an <tt>ActiveRecord::IrreversibleMigration</tt> exception,
364
399
  # that step will fail and you'll have some manual work to do.
365
400
  #
366
- # == Database support
367
- #
368
- # Migrations are currently supported in MySQL, PostgreSQL, SQLite,
369
- # SQL Server, and Oracle (all supported databases except DB2).
370
- #
371
401
  # == More examples
372
402
  #
373
403
  # Not all migrations change the schema. Some just fix the data:
374
404
  #
375
- # class RemoveEmptyTags < ActiveRecord::Migration[5.0]
405
+ # class RemoveEmptyTags < ActiveRecord::Migration[7.0]
376
406
  # def up
377
407
  # Tag.all.each { |tag| tag.destroy if tag.pages.empty? }
378
408
  # end
@@ -385,7 +415,7 @@ module ActiveRecord
385
415
  #
386
416
  # Others remove columns when they migrate up instead of down:
387
417
  #
388
- # class RemoveUnnecessaryItemAttributes < ActiveRecord::Migration[5.0]
418
+ # class RemoveUnnecessaryItemAttributes < ActiveRecord::Migration[7.0]
389
419
  # def up
390
420
  # remove_column :items, :incomplete_items_count
391
421
  # remove_column :items, :completed_items_count
@@ -399,7 +429,7 @@ module ActiveRecord
399
429
  #
400
430
  # And sometimes you need to do something in SQL not abstracted directly by migrations:
401
431
  #
402
- # class MakeJoinUnique < ActiveRecord::Migration[5.0]
432
+ # class MakeJoinUnique < ActiveRecord::Migration[7.0]
403
433
  # def up
404
434
  # execute "ALTER TABLE `pages_linked_pages` ADD UNIQUE `page_id_linked_page_id` (`page_id`,`linked_page_id`)"
405
435
  # end
@@ -416,7 +446,7 @@ module ActiveRecord
416
446
  # <tt>Base#reset_column_information</tt> in order to ensure that the model has the
417
447
  # latest column data from after the new column was added. Example:
418
448
  #
419
- # class AddPeopleSalary < ActiveRecord::Migration[5.0]
449
+ # class AddPeopleSalary < ActiveRecord::Migration[7.0]
420
450
  # def up
421
451
  # add_column :people, :salary, :integer
422
452
  # Person.reset_column_information
@@ -474,7 +504,7 @@ module ActiveRecord
474
504
  # To define a reversible migration, define the +change+ method in your
475
505
  # migration like this:
476
506
  #
477
- # class TenderloveMigration < ActiveRecord::Migration[5.0]
507
+ # class TenderloveMigration < ActiveRecord::Migration[7.0]
478
508
  # def change
479
509
  # create_table(:horses) do |t|
480
510
  # t.column :content, :text
@@ -486,9 +516,9 @@ module ActiveRecord
486
516
  # This migration will create the horses table for you on the way up, and
487
517
  # automatically figure out how to drop the table on the way down.
488
518
  #
489
- # Some commands like +remove_column+ cannot be reversed. If you care to
490
- # define how to move up and down in these cases, you should define the +up+
491
- # 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.
492
522
  #
493
523
  # If a command cannot be reversed, an
494
524
  # <tt>ActiveRecord::IrreversibleMigration</tt> exception will be raised when
@@ -504,7 +534,7 @@ module ActiveRecord
504
534
  # can't execute inside a transaction though, and for these situations
505
535
  # you can turn the automatic transactions off.
506
536
  #
507
- # class ChangeEnum < ActiveRecord::Migration[5.0]
537
+ # class ChangeEnum < ActiveRecord::Migration[7.0]
508
538
  # disable_ddl_transaction!
509
539
  #
510
540
  # def up
@@ -517,6 +547,7 @@ module ActiveRecord
517
547
  class Migration
518
548
  autoload :CommandRecorder, "active_record/migration/command_recorder"
519
549
  autoload :Compatibility, "active_record/migration/compatibility"
550
+ autoload :JoinTable, "active_record/migration/join_table"
520
551
 
521
552
  # This must be defined before the inherited hook, below
522
553
  class Current < Migration # :nodoc:
@@ -525,10 +556,12 @@ module ActiveRecord
525
556
  def self.inherited(subclass) # :nodoc:
526
557
  super
527
558
  if subclass.superclass == Migration
559
+ major = ActiveRecord::VERSION::MAJOR
560
+ minor = ActiveRecord::VERSION::MINOR
528
561
  raise StandardError, "Directly inheriting from ActiveRecord::Migration is not supported. " \
529
- "Please specify the Rails release the migration was written for:\n" \
562
+ "Please specify the Active Record release the migration was written for:\n" \
530
563
  "\n" \
531
- " class #{subclass} < ActiveRecord::Migration[4.2]"
564
+ " class #{subclass} < ActiveRecord::Migration[#{major}.#{minor}]"
532
565
  end
533
566
  end
534
567
 
@@ -545,21 +578,36 @@ module ActiveRecord
545
578
  # This class is used to verify that all migrations have been run before
546
579
  # loading a web page if <tt>config.active_record.migration_error</tt> is set to :page_load
547
580
  class CheckPending
548
- def initialize(app)
581
+ def initialize(app, file_watcher: ActiveSupport::FileUpdateChecker)
549
582
  @app = app
550
- @last_check = 0
583
+ @needs_check = true
584
+ @mutex = Mutex.new
585
+ @file_watcher = file_watcher
551
586
  end
552
587
 
553
588
  def call(env)
554
- mtime = ActiveRecord::Base.connection.migration_context.last_migration.mtime.to_i
555
- if @last_check < mtime
556
- ActiveRecord::Migration.check_pending!(connection)
557
- @last_check = mtime
589
+ @mutex.synchronize do
590
+ @watcher ||= build_watcher do
591
+ @needs_check = true
592
+ ActiveRecord::Migration.check_pending!(connection)
593
+ @needs_check = false
594
+ end
595
+
596
+ if @needs_check
597
+ @watcher.execute
598
+ else
599
+ @watcher.execute_if_updated
600
+ end
558
601
  end
602
+
559
603
  @app.call(env)
560
604
  end
561
605
 
562
606
  private
607
+ def build_watcher(&block)
608
+ paths = Array(connection.migration_context.migrations_paths)
609
+ @file_watcher.new([], paths.index_with(["rb"]), &block)
610
+ end
563
611
 
564
612
  def connection
565
613
  ActiveRecord::Base.connection
@@ -580,22 +628,30 @@ module ActiveRecord
580
628
  end
581
629
 
582
630
  def load_schema_if_pending!
583
- if Base.connection.migration_context.needs_migration? || !Base.connection.migration_context.any_migrations?
631
+ current_db_config = Base.connection_db_config
632
+ all_configs = ActiveRecord::Base.configurations.configs_for(env_name: Rails.env)
633
+
634
+ needs_update = !all_configs.all? do |db_config|
635
+ Tasks::DatabaseTasks.schema_up_to_date?(db_config, ActiveRecord.schema_format)
636
+ end
637
+
638
+ if needs_update
584
639
  # Roundtrip to Rake to allow plugins to hook into database initialization.
585
640
  root = defined?(ENGINE_ROOT) ? ENGINE_ROOT : Rails.root
586
641
  FileUtils.cd(root) do
587
- current_config = Base.connection_config
588
642
  Base.clear_all_connections!
589
643
  system("bin/rails db:test:prepare")
590
- # Establish a new connection, the old database may be gone (db:test:prepare uses purge)
591
- Base.establish_connection(current_config)
592
644
  end
593
- check_pending!
594
645
  end
646
+
647
+ # Establish a new connection, the old database may be gone (db:test:prepare uses purge)
648
+ Base.establish_connection(current_db_config)
649
+
650
+ check_pending!
595
651
  end
596
652
 
597
653
  def maintain_test_schema! # :nodoc:
598
- if ActiveRecord::Base.maintain_test_schema
654
+ if ActiveRecord.maintain_test_schema
599
655
  suppress_messages { load_schema_if_pending! }
600
656
  end
601
657
  end
@@ -603,6 +659,7 @@ module ActiveRecord
603
659
  def method_missing(name, *args, &block) # :nodoc:
604
660
  nearest_delegate.send(name, *args, &block)
605
661
  end
662
+ ruby2_keywords(:method_missing)
606
663
 
607
664
  def migrate(direction)
608
665
  new.migrate direction
@@ -641,7 +698,7 @@ module ActiveRecord
641
698
  # and create the table 'apples' on the way up, and the reverse
642
699
  # on the way down.
643
700
  #
644
- # class FixTLMigration < ActiveRecord::Migration[5.0]
701
+ # class FixTLMigration < ActiveRecord::Migration[7.0]
645
702
  # def change
646
703
  # revert do
647
704
  # create_table(:horses) do |t|
@@ -658,9 +715,9 @@ module ActiveRecord
658
715
  # Or equivalently, if +TenderloveMigration+ is defined as in the
659
716
  # documentation for Migration:
660
717
  #
661
- # require_relative '20121212123456_tenderlove_migration'
718
+ # require_relative "20121212123456_tenderlove_migration"
662
719
  #
663
- # class FixupTLMigration < ActiveRecord::Migration[5.0]
720
+ # class FixupTLMigration < ActiveRecord::Migration[7.0]
664
721
  # def change
665
722
  # revert TenderloveMigration
666
723
  #
@@ -671,21 +728,19 @@ module ActiveRecord
671
728
  # end
672
729
  #
673
730
  # This command can be nested.
674
- def revert(*migration_classes)
731
+ def revert(*migration_classes, &block)
675
732
  run(*migration_classes.reverse, revert: true) unless migration_classes.empty?
676
733
  if block_given?
677
734
  if connection.respond_to? :revert
678
- connection.revert { yield }
735
+ connection.revert(&block)
679
736
  else
680
- recorder = CommandRecorder.new(connection)
737
+ recorder = command_recorder
681
738
  @connection = recorder
682
739
  suppress_messages do
683
- connection.revert { yield }
740
+ connection.revert(&block)
684
741
  end
685
742
  @connection = recorder.delegate
686
- recorder.commands.each do |cmd, args, block|
687
- send(cmd, *args, &block)
688
- end
743
+ recorder.replay(self)
689
744
  end
690
745
  end
691
746
  end
@@ -713,7 +768,7 @@ module ActiveRecord
713
768
  # when the three columns 'first_name', 'last_name' and 'full_name' exist,
714
769
  # even when migrating down:
715
770
  #
716
- # class SplitNameMigration < ActiveRecord::Migration[5.0]
771
+ # class SplitNameMigration < ActiveRecord::Migration[7.0]
717
772
  # def change
718
773
  # add_column :users, :first_name, :string
719
774
  # add_column :users, :last_name, :string
@@ -741,7 +796,7 @@ module ActiveRecord
741
796
  # In the following example, the new column +published+ will be given
742
797
  # the value +true+ for all existing records.
743
798
  #
744
- # class AddPublishedToPosts < ActiveRecord::Migration[5.2]
799
+ # class AddPublishedToPosts < ActiveRecord::Migration[7.0]
745
800
  # def change
746
801
  # add_column :posts, :published, :boolean, default: false
747
802
  # up_only do
@@ -749,8 +804,8 @@ module ActiveRecord
749
804
  # end
750
805
  # end
751
806
  # end
752
- def up_only
753
- execute_block { yield } unless reverting?
807
+ def up_only(&block)
808
+ execute_block(&block) unless reverting?
754
809
  end
755
810
 
756
811
  # Runs the given migration classes.
@@ -814,7 +869,7 @@ module ActiveRecord
814
869
  change
815
870
  end
816
871
  else
817
- send(direction)
872
+ public_send(direction)
818
873
  end
819
874
  ensure
820
875
  @connection = nil
@@ -830,10 +885,14 @@ module ActiveRecord
830
885
  write "== %s %s" % [text, "=" * length]
831
886
  end
832
887
 
888
+ # Takes a message argument and outputs it as is.
889
+ # A second boolean argument can be passed to specify whether to indent or not.
833
890
  def say(message, subitem = false)
834
891
  write "#{subitem ? " ->" : "--"} #{message}"
835
892
  end
836
893
 
894
+ # Outputs text along with how long it took to run its block.
895
+ # If the block returns an integer it assumes it is the number of rows affected.
837
896
  def say_with_time(message)
838
897
  say(message)
839
898
  result = nil
@@ -843,6 +902,7 @@ module ActiveRecord
843
902
  result
844
903
  end
845
904
 
905
+ # Takes a block as an argument and suppresses any output generated by the block.
846
906
  def suppress_messages
847
907
  save, self.verbose = verbose, false
848
908
  yield
@@ -861,7 +921,7 @@ module ActiveRecord
861
921
  unless connection.respond_to? :revert
862
922
  unless arguments.empty? || [:execute, :enable_extension, :disable_extension].include?(method)
863
923
  arguments[0] = proper_table_name(arguments.first, table_name_options)
864
- if [:rename_table, :add_foreign_key].include?(method) ||
924
+ if method == :rename_table ||
865
925
  (method == :remove_foreign_key && !arguments.second.is_a?(Hash))
866
926
  arguments[1] = proper_table_name(arguments.second, table_name_options)
867
927
  end
@@ -871,21 +931,23 @@ module ActiveRecord
871
931
  connection.send(method, *arguments, &block)
872
932
  end
873
933
  end
934
+ ruby2_keywords(:method_missing)
874
935
 
875
936
  def copy(destination, sources, options = {})
876
937
  copied = []
938
+ schema_migration = options[:schema_migration] || ActiveRecord::SchemaMigration
877
939
 
878
940
  FileUtils.mkdir_p(destination) unless File.exist?(destination)
879
941
 
880
- destination_migrations = ActiveRecord::MigrationContext.new(destination).migrations
942
+ destination_migrations = ActiveRecord::MigrationContext.new(destination, schema_migration).migrations
881
943
  last = destination_migrations.last
882
944
  sources.each do |scope, path|
883
- source_migrations = ActiveRecord::MigrationContext.new(path).migrations
945
+ source_migrations = ActiveRecord::MigrationContext.new(path, schema_migration).migrations
884
946
 
885
947
  source_migrations.each do |migration|
886
948
  source = File.binread(migration.filename)
887
949
  inserted_comment = "# This migration comes from #{scope} (originally #{migration.version})\n"
888
- magic_comments = "".dup
950
+ magic_comments = +""
889
951
  loop do
890
952
  # If we have a magic comment in the original migration,
891
953
  # insert our comment after the first newline(end of the magic comment line)
@@ -895,6 +957,12 @@ module ActiveRecord
895
957
  magic_comments << magic_comment; ""
896
958
  end || break
897
959
  end
960
+
961
+ if !magic_comments.empty? && source.start_with?("\n")
962
+ magic_comments << "\n"
963
+ source = source[1..-1]
964
+ end
965
+
898
966
  source = "#{magic_comments}#{inserted_comment}#{source}"
899
967
 
900
968
  if duplicate = destination_migrations.detect { |m| m.name == migration.name }
@@ -932,7 +1000,7 @@ module ActiveRecord
932
1000
 
933
1001
  # Determines the version number of the next migration.
934
1002
  def next_migration_number(number)
935
- if ActiveRecord::Base.timestamped_migrations
1003
+ if ActiveRecord.timestamped_migrations
936
1004
  [Time.now.utc.strftime("%Y%m%d%H%M%S"), "%.14d" % number].max
937
1005
  else
938
1006
  SchemaMigration.normalize_migration_number(number)
@@ -941,7 +1009,7 @@ module ActiveRecord
941
1009
 
942
1010
  # Builds a hash for use in ActiveRecord::Migration#proper_table_name using
943
1011
  # the Active Record object's table_name prefix and suffix
944
- def table_name_options(config = ActiveRecord::Base) #:nodoc:
1012
+ def table_name_options(config = ActiveRecord::Base) # :nodoc:
945
1013
  {
946
1014
  table_name_prefix: config.table_name_prefix,
947
1015
  table_name_suffix: config.table_name_suffix
@@ -956,6 +1024,10 @@ module ActiveRecord
956
1024
  yield
957
1025
  end
958
1026
  end
1027
+
1028
+ def command_recorder
1029
+ CommandRecorder.new(connection)
1030
+ end
959
1031
  end
960
1032
 
961
1033
  # MigrationProxy is used to defer loading of the actual migration classes
@@ -970,41 +1042,49 @@ module ActiveRecord
970
1042
  File.basename(filename)
971
1043
  end
972
1044
 
973
- def mtime
974
- File.mtime filename
975
- end
976
-
977
1045
  delegate :migrate, :announce, :write, :disable_ddl_transaction, to: :migration
978
1046
 
979
1047
  private
980
-
981
1048
  def migration
982
1049
  @migration ||= load_migration
983
1050
  end
984
1051
 
985
1052
  def load_migration
986
- require(File.expand_path(filename))
1053
+ Object.send(:remove_const, name) rescue nil
1054
+
1055
+ load(File.expand_path(filename))
987
1056
  name.constantize.new(name, version)
988
1057
  end
989
1058
  end
990
1059
 
991
- class NullMigration < MigrationProxy #:nodoc:
992
- def initialize
993
- super(nil, 0, nil, nil)
994
- end
995
-
996
- def mtime
997
- 0
998
- end
999
- end
1000
-
1001
- class MigrationContext # :nodoc:
1002
- attr_reader :migrations_paths
1060
+ # MigrationContext sets the context in which a migration is run.
1061
+ #
1062
+ # A migration context requires the path to the migrations is set
1063
+ # in the +migrations_paths+ parameter. Optionally a +schema_migration+
1064
+ # class can be provided. For most applications, +SchemaMigration+ is
1065
+ # sufficient. Multiple database applications need a +SchemaMigration+
1066
+ # per primary database.
1067
+ class MigrationContext
1068
+ attr_reader :migrations_paths, :schema_migration
1003
1069
 
1004
- def initialize(migrations_paths)
1070
+ def initialize(migrations_paths, schema_migration = SchemaMigration)
1005
1071
  @migrations_paths = migrations_paths
1072
+ @schema_migration = schema_migration
1006
1073
  end
1007
1074
 
1075
+ # Runs the migrations in the +migrations_path+.
1076
+ #
1077
+ # If +target_version+ is +nil+, +migrate+ will run +up+.
1078
+ #
1079
+ # If the +current_version+ and +target_version+ are both
1080
+ # 0 then an empty array will be returned and no migrations
1081
+ # will be run.
1082
+ #
1083
+ # If the +current_version+ in the schema is greater than
1084
+ # the +target_version+, then +down+ will be run.
1085
+ #
1086
+ # If none of the conditions are met, +up+ will be run with
1087
+ # the +target_version+.
1008
1088
  def migrate(target_version = nil, &block)
1009
1089
  case
1010
1090
  when target_version.nil?
@@ -1018,72 +1098,64 @@ module ActiveRecord
1018
1098
  end
1019
1099
  end
1020
1100
 
1021
- def rollback(steps = 1)
1101
+ def rollback(steps = 1) # :nodoc:
1022
1102
  move(:down, steps)
1023
1103
  end
1024
1104
 
1025
- def forward(steps = 1)
1105
+ def forward(steps = 1) # :nodoc:
1026
1106
  move(:up, steps)
1027
1107
  end
1028
1108
 
1029
- def up(target_version = nil)
1109
+ def up(target_version = nil, &block) # :nodoc:
1030
1110
  selected_migrations = if block_given?
1031
- migrations.select { |m| yield m }
1111
+ migrations.select(&block)
1032
1112
  else
1033
1113
  migrations
1034
1114
  end
1035
1115
 
1036
- Migrator.new(:up, selected_migrations, target_version).migrate
1116
+ Migrator.new(:up, selected_migrations, schema_migration, target_version).migrate
1037
1117
  end
1038
1118
 
1039
- def down(target_version = nil)
1119
+ def down(target_version = nil, &block) # :nodoc:
1040
1120
  selected_migrations = if block_given?
1041
- migrations.select { |m| yield m }
1121
+ migrations.select(&block)
1042
1122
  else
1043
1123
  migrations
1044
1124
  end
1045
1125
 
1046
- Migrator.new(:down, selected_migrations, target_version).migrate
1126
+ Migrator.new(:down, selected_migrations, schema_migration, target_version).migrate
1047
1127
  end
1048
1128
 
1049
- def run(direction, target_version)
1050
- Migrator.new(direction, migrations, target_version).run
1129
+ def run(direction, target_version) # :nodoc:
1130
+ Migrator.new(direction, migrations, schema_migration, target_version).run
1051
1131
  end
1052
1132
 
1053
- def open
1054
- Migrator.new(:up, migrations, nil)
1133
+ def open # :nodoc:
1134
+ Migrator.new(:up, migrations, schema_migration)
1055
1135
  end
1056
1136
 
1057
- def get_all_versions
1058
- if SchemaMigration.table_exists?
1059
- SchemaMigration.all_versions.map(&:to_i)
1137
+ def get_all_versions # :nodoc:
1138
+ if schema_migration.table_exists?
1139
+ schema_migration.all_versions.map(&:to_i)
1060
1140
  else
1061
1141
  []
1062
1142
  end
1063
1143
  end
1064
1144
 
1065
- def current_version
1145
+ def current_version # :nodoc:
1066
1146
  get_all_versions.max || 0
1067
1147
  rescue ActiveRecord::NoDatabaseError
1068
1148
  end
1069
1149
 
1070
- def needs_migration?
1071
- (migrations.collect(&:version) - get_all_versions).size > 0
1150
+ def needs_migration? # :nodoc:
1151
+ pending_migration_versions.size > 0
1072
1152
  end
1073
1153
 
1074
- def any_migrations?
1075
- migrations.any?
1154
+ def pending_migration_versions # :nodoc:
1155
+ migrations.collect(&:version) - get_all_versions
1076
1156
  end
1077
1157
 
1078
- def last_migration #:nodoc:
1079
- migrations.last || NullMigration.new
1080
- end
1081
-
1082
- def parse_migration_filename(filename) # :nodoc:
1083
- File.basename(filename).scan(Migration::MigrationFilenameRegexp).first
1084
- end
1085
-
1086
- def migrations
1158
+ def migrations # :nodoc:
1087
1159
  migrations = migration_files.map do |file|
1088
1160
  version, name, scope = parse_migration_filename(file)
1089
1161
  raise IllegalMigrationNameError.new(file) unless version
@@ -1096,38 +1168,34 @@ module ActiveRecord
1096
1168
  migrations.sort_by(&:version)
1097
1169
  end
1098
1170
 
1099
- def migrations_status
1100
- db_list = ActiveRecord::SchemaMigration.normalized_versions
1171
+ def migrations_status # :nodoc:
1172
+ db_list = schema_migration.normalized_versions
1101
1173
 
1102
- file_list = migration_files.map do |file|
1174
+ file_list = migration_files.filter_map do |file|
1103
1175
  version, name, scope = parse_migration_filename(file)
1104
1176
  raise IllegalMigrationNameError.new(file) unless version
1105
- version = ActiveRecord::SchemaMigration.normalize_migration_number(version)
1177
+ version = schema_migration.normalize_migration_number(version)
1106
1178
  status = db_list.delete(version) ? "up" : "down"
1107
1179
  [status, version, (name + scope).humanize]
1108
- end.compact
1180
+ end
1109
1181
 
1110
1182
  db_list.map! do |version|
1111
1183
  ["up", version, "********** NO FILE **********"]
1112
1184
  end
1113
1185
 
1114
- (db_list + file_list).sort_by { |_, version, _| version }
1115
- end
1116
-
1117
- def migration_files
1118
- paths = Array(migrations_paths)
1119
- Dir[*paths.flat_map { |path| "#{path}/**/[0-9]*_*.rb" }]
1186
+ (db_list + file_list).sort_by { |_, version, _| version.to_i }
1120
1187
  end
1121
1188
 
1122
- def current_environment
1189
+ def current_environment # :nodoc:
1123
1190
  ActiveRecord::ConnectionHandling::DEFAULT_ENV.call
1124
1191
  end
1125
1192
 
1126
- def protected_environment?
1193
+ def protected_environment? # :nodoc:
1127
1194
  ActiveRecord::Base.protected_environments.include?(last_stored_environment) if last_stored_environment
1128
1195
  end
1129
1196
 
1130
- def last_stored_environment
1197
+ def last_stored_environment # :nodoc:
1198
+ return nil unless ActiveRecord::InternalMetadata.enabled?
1131
1199
  return nil if current_version == 0
1132
1200
  raise NoEnvironmentInSchemaError unless ActiveRecord::InternalMetadata.table_exists?
1133
1201
 
@@ -1137,8 +1205,17 @@ module ActiveRecord
1137
1205
  end
1138
1206
 
1139
1207
  private
1208
+ def migration_files
1209
+ paths = Array(migrations_paths)
1210
+ Dir[*paths.flat_map { |path| "#{path}/**/[0-9]*_*.rb" }]
1211
+ end
1212
+
1213
+ def parse_migration_filename(filename)
1214
+ File.basename(filename).scan(Migration::MigrationFilenameRegexp).first
1215
+ end
1216
+
1140
1217
  def move(direction, steps)
1141
- migrator = Migrator.new(direction, migrations)
1218
+ migrator = Migrator.new(direction, migrations, schema_migration)
1142
1219
 
1143
1220
  if current_version != 0 && !migrator.current_migration
1144
1221
  raise UnknownMigrationVersionError.new(current_version)
@@ -1153,7 +1230,7 @@ module ActiveRecord
1153
1230
 
1154
1231
  finish = migrator.migrations[start_index + steps]
1155
1232
  version = finish ? finish.version : 0
1156
- send(direction, version)
1233
+ public_send(direction, version)
1157
1234
  end
1158
1235
  end
1159
1236
 
@@ -1161,30 +1238,24 @@ module ActiveRecord
1161
1238
  class << self
1162
1239
  attr_accessor :migrations_paths
1163
1240
 
1164
- def migrations_path=(path)
1165
- ActiveSupport::Deprecation.warn \
1166
- "`ActiveRecord::Migrator.migrations_path=` is now deprecated and will be removed in Rails 6.0. " \
1167
- "You can set the `migrations_paths` on the `connection` instead through the `database.yml`."
1168
- self.migrations_paths = [path]
1169
- end
1170
-
1171
1241
  # For cases where a table doesn't exist like loading from schema cache
1172
1242
  def current_version
1173
- MigrationContext.new(migrations_paths).current_version
1243
+ MigrationContext.new(migrations_paths, SchemaMigration).current_version
1174
1244
  end
1175
1245
  end
1176
1246
 
1177
1247
  self.migrations_paths = ["db/migrate"]
1178
1248
 
1179
- def initialize(direction, migrations, target_version = nil)
1249
+ def initialize(direction, migrations, schema_migration, target_version = nil)
1180
1250
  @direction = direction
1181
1251
  @target_version = target_version
1182
1252
  @migrated_versions = nil
1183
1253
  @migrations = migrations
1254
+ @schema_migration = schema_migration
1184
1255
 
1185
1256
  validate(@migrations)
1186
1257
 
1187
- ActiveRecord::SchemaMigration.create_table
1258
+ @schema_migration.create_table
1188
1259
  ActiveRecord::InternalMetadata.create_table
1189
1260
  end
1190
1261
 
@@ -1238,16 +1309,15 @@ module ActiveRecord
1238
1309
  end
1239
1310
 
1240
1311
  def load_migrated
1241
- @migrated_versions = Set.new(Base.connection.migration_context.get_all_versions)
1312
+ @migrated_versions = Set.new(@schema_migration.all_versions.map(&:to_i))
1242
1313
  end
1243
1314
 
1244
1315
  private
1245
-
1246
1316
  # Used for running a specific migration.
1247
1317
  def run_without_lock
1248
1318
  migration = migrations.detect { |m| m.version == @target_version }
1249
1319
  raise UnknownMigrationVersionError.new(@target_version) if migration.nil?
1250
- result = execute_migration_in_transaction(migration, @direction)
1320
+ result = execute_migration_in_transaction(migration)
1251
1321
 
1252
1322
  record_environment
1253
1323
  result
@@ -1259,10 +1329,7 @@ module ActiveRecord
1259
1329
  raise UnknownMigrationVersionError.new(@target_version)
1260
1330
  end
1261
1331
 
1262
- result = runnable.each do |migration|
1263
- execute_migration_in_transaction(migration, @direction)
1264
- end
1265
-
1332
+ result = runnable.each(&method(:execute_migration_in_transaction))
1266
1333
  record_environment
1267
1334
  result
1268
1335
  end
@@ -1282,18 +1349,18 @@ module ActiveRecord
1282
1349
  @target_version && @target_version != 0 && !target
1283
1350
  end
1284
1351
 
1285
- def execute_migration_in_transaction(migration, direction)
1352
+ def execute_migration_in_transaction(migration)
1286
1353
  return if down? && !migrated.include?(migration.version.to_i)
1287
1354
  return if up? && migrated.include?(migration.version.to_i)
1288
1355
 
1289
1356
  Base.logger.info "Migrating to #{migration.name} (#{migration.version})" if Base.logger
1290
1357
 
1291
1358
  ddl_transaction(migration) do
1292
- migration.migrate(direction)
1359
+ migration.migrate(@direction)
1293
1360
  record_version_state_after_migrating(migration.version)
1294
1361
  end
1295
1362
  rescue => e
1296
- msg = "An error has occurred, ".dup
1363
+ msg = +"An error has occurred, "
1297
1364
  msg << "this and " if use_transaction?(migration)
1298
1365
  msg << "all later migrations canceled:\n\n#{e}"
1299
1366
  raise StandardError, msg, e.backtrace
@@ -1322,10 +1389,10 @@ module ActiveRecord
1322
1389
  def record_version_state_after_migrating(version)
1323
1390
  if down?
1324
1391
  migrated.delete(version)
1325
- ActiveRecord::SchemaMigration.where(version: version.to_s).delete_all
1392
+ @schema_migration.delete_by(version: version.to_s)
1326
1393
  else
1327
1394
  migrated << version
1328
- ActiveRecord::SchemaMigration.create!(version: version.to_s)
1395
+ @schema_migration.create!(version: version.to_s)
1329
1396
  end
1330
1397
  end
1331
1398
 
@@ -1338,9 +1405,9 @@ module ActiveRecord
1338
1405
  end
1339
1406
 
1340
1407
  # Wrap the migration in a transaction only if supported by the adapter.
1341
- def ddl_transaction(migration)
1408
+ def ddl_transaction(migration, &block)
1342
1409
  if use_transaction?(migration)
1343
- Base.transaction { yield }
1410
+ Base.transaction(&block)
1344
1411
  else
1345
1412
  yield
1346
1413
  end
@@ -1351,24 +1418,36 @@ module ActiveRecord
1351
1418
  end
1352
1419
 
1353
1420
  def use_advisory_lock?
1354
- Base.connection.supports_advisory_locks?
1421
+ Base.connection.advisory_locks_enabled?
1355
1422
  end
1356
1423
 
1357
1424
  def with_advisory_lock
1358
1425
  lock_id = generate_migrator_advisory_lock_id
1359
- connection = Base.connection
1360
- got_lock = connection.get_advisory_lock(lock_id)
1361
- raise ConcurrentMigrationError unless got_lock
1362
- load_migrated # reload schema_migrations to be sure it wasn't changed by another process before we got the lock
1363
- yield
1364
- ensure
1365
- if got_lock && !connection.release_advisory_lock(lock_id)
1366
- raise ConcurrentMigrationError.new(
1367
- ConcurrentMigrationError::RELEASE_LOCK_FAILED_MESSAGE
1368
- )
1426
+
1427
+ with_advisory_lock_connection do |connection|
1428
+ got_lock = connection.get_advisory_lock(lock_id)
1429
+ raise ConcurrentMigrationError unless got_lock
1430
+ load_migrated # reload schema_migrations to be sure it wasn't changed by another process before we got the lock
1431
+ yield
1432
+ ensure
1433
+ if got_lock && !connection.release_advisory_lock(lock_id)
1434
+ raise ConcurrentMigrationError.new(
1435
+ ConcurrentMigrationError::RELEASE_LOCK_FAILED_MESSAGE
1436
+ )
1437
+ end
1369
1438
  end
1370
1439
  end
1371
1440
 
1441
+ def with_advisory_lock_connection(&block)
1442
+ pool = ActiveRecord::ConnectionAdapters::ConnectionHandler.new.establish_connection(
1443
+ ActiveRecord::Base.connection_db_config
1444
+ )
1445
+
1446
+ pool.with_connection(&block)
1447
+ ensure
1448
+ pool&.disconnect!
1449
+ end
1450
+
1372
1451
  MIGRATOR_SALT = 2053462845
1373
1452
  def generate_migrator_advisory_lock_id
1374
1453
  db_name_hash = Zlib.crc32(Base.connection.current_database)