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
@@ -3,34 +3,30 @@
3
3
  module ActiveRecord
4
4
  module Associations
5
5
  # = Active Record Belongs To Association
6
- class BelongsToAssociation < SingularAssociation #:nodoc:
6
+ class BelongsToAssociation < SingularAssociation # :nodoc:
7
7
  def handle_dependency
8
8
  return unless load_target
9
9
 
10
10
  case options[:dependent]
11
11
  when :destroy
12
- target.destroy
13
- raise ActiveRecord::Rollback unless target.destroyed?
12
+ raise ActiveRecord::Rollback unless target.destroy
13
+ when :destroy_async
14
+ id = owner.public_send(reflection.foreign_key.to_sym)
15
+ primary_key_column = reflection.active_record_primary_key.to_sym
16
+
17
+ enqueue_destroy_association(
18
+ owner_model_name: owner.class.to_s,
19
+ owner_id: owner.id,
20
+ association_class: reflection.klass.to_s,
21
+ association_ids: [id],
22
+ association_primary_key_column: primary_key_column,
23
+ ensuring_owner_was_method: options.fetch(:ensuring_owner_was, nil)
24
+ )
14
25
  else
15
- target.send(options[:dependent])
26
+ target.public_send(options[:dependent])
16
27
  end
17
28
  end
18
29
 
19
- def replace(record)
20
- if record
21
- raise_on_type_mismatch!(record)
22
- update_counters_on_replace(record)
23
- set_inverse_instance(record)
24
- @updated = true
25
- else
26
- decrement_counters
27
- end
28
-
29
- replace_keys(record)
30
-
31
- self.target = record
32
- end
33
-
34
30
  def inversed_from(record)
35
31
  replace_keys(record)
36
32
  super
@@ -49,30 +45,71 @@ module ActiveRecord
49
45
  @updated
50
46
  end
51
47
 
52
- def decrement_counters # :nodoc:
48
+ def decrement_counters
53
49
  update_counters(-1)
54
50
  end
55
51
 
56
- def increment_counters # :nodoc:
52
+ def increment_counters
57
53
  update_counters(1)
58
54
  end
59
55
 
56
+ def decrement_counters_before_last_save
57
+ if reflection.polymorphic?
58
+ model_type_was = owner.attribute_before_last_save(reflection.foreign_type)
59
+ model_was = owner.class.polymorphic_class_for(model_type_was) if model_type_was
60
+ else
61
+ model_was = klass
62
+ end
63
+
64
+ foreign_key_was = owner.attribute_before_last_save(reflection.foreign_key)
65
+
66
+ if foreign_key_was && model_was < ActiveRecord::Base
67
+ update_counters_via_scope(model_was, foreign_key_was, -1)
68
+ end
69
+ end
70
+
60
71
  def target_changed?
72
+ owner.attribute_changed?(reflection.foreign_key) || (!foreign_key_present? && target&.new_record?)
73
+ end
74
+
75
+ def target_previously_changed?
76
+ owner.attribute_previously_changed?(reflection.foreign_key)
77
+ end
78
+
79
+ def saved_change_to_target?
61
80
  owner.saved_change_to_attribute?(reflection.foreign_key)
62
81
  end
63
82
 
64
83
  private
84
+ def replace(record)
85
+ if record
86
+ raise_on_type_mismatch!(record)
87
+ set_inverse_instance(record)
88
+ @updated = true
89
+ elsif target
90
+ remove_inverse_instance(target)
91
+ end
92
+
93
+ replace_keys(record, force: true)
94
+
95
+ self.target = record
96
+ end
65
97
 
66
98
  def update_counters(by)
67
99
  if require_counter_update? && foreign_key_present?
68
100
  if target && !stale_target?
69
101
  target.increment!(reflection.counter_cache_column, by, touch: reflection.options[:touch])
70
102
  else
71
- klass.update_counters(target_id, reflection.counter_cache_column => by, touch: reflection.options[:touch])
103
+ update_counters_via_scope(klass, owner._read_attribute(reflection.foreign_key), by)
72
104
  end
73
105
  end
74
106
  end
75
107
 
108
+ def update_counters_via_scope(klass, foreign_key, by)
109
+ scope = klass.unscoped.where!(primary_key(klass) => foreign_key)
110
+ scope.update_counters(reflection.counter_cache_column => by, touch: reflection.options[:touch])
111
+ end
112
+
76
113
  def find_target?
77
114
  !loaded? && foreign_key_present? && klass
78
115
  end
@@ -81,44 +118,25 @@ module ActiveRecord
81
118
  reflection.counter_cache_column && owner.persisted?
82
119
  end
83
120
 
84
- def update_counters_on_replace(record)
85
- if require_counter_update? && different_target?(record)
86
- owner.instance_variable_set :@_after_replace_counter_called, true
87
- record.increment!(reflection.counter_cache_column, touch: reflection.options[:touch])
88
- decrement_counters
89
- end
90
- end
91
-
92
- # Checks whether record is different to the current target, without loading it
93
- def different_target?(record)
94
- record._read_attribute(primary_key(record)) != owner._read_attribute(reflection.foreign_key)
95
- end
121
+ def replace_keys(record, force: false)
122
+ target_key = record ? record._read_attribute(primary_key(record.class)) : nil
96
123
 
97
- def replace_keys(record)
98
- owner[reflection.foreign_key] = record ? record._read_attribute(primary_key(record)) : nil
124
+ if force || owner._read_attribute(reflection.foreign_key) != target_key
125
+ owner[reflection.foreign_key] = target_key
126
+ end
99
127
  end
100
128
 
101
- def primary_key(record)
102
- reflection.association_primary_key(record.class)
129
+ def primary_key(klass)
130
+ reflection.association_primary_key(klass)
103
131
  end
104
132
 
105
133
  def foreign_key_present?
106
134
  owner._read_attribute(reflection.foreign_key)
107
135
  end
108
136
 
109
- # NOTE - for now, we're only supporting inverse setting from belongs_to back onto
110
- # has_one associations.
111
137
  def invertible_for?(record)
112
138
  inverse = inverse_reflection_for(record)
113
- inverse && inverse.has_one?
114
- end
115
-
116
- def target_id
117
- if options[:primary_key]
118
- owner.send(reflection.name).try(:id)
119
- else
120
- owner._read_attribute(reflection.foreign_key)
121
- end
139
+ inverse && (inverse.has_one? || inverse.klass.has_many_inversing)
122
140
  end
123
141
 
124
142
  def stale_state
@@ -3,24 +3,33 @@
3
3
  module ActiveRecord
4
4
  module Associations
5
5
  # = Active Record Belongs To Polymorphic Association
6
- class BelongsToPolymorphicAssociation < BelongsToAssociation #:nodoc:
6
+ class BelongsToPolymorphicAssociation < BelongsToAssociation # :nodoc:
7
7
  def klass
8
8
  type = owner[reflection.foreign_type]
9
- type.presence && type.constantize
9
+ type.presence && owner.class.polymorphic_class_for(type)
10
10
  end
11
11
 
12
12
  def target_changed?
13
+ super || owner.attribute_changed?(reflection.foreign_type)
14
+ end
15
+
16
+ def target_previously_changed?
17
+ super || owner.attribute_previously_changed?(reflection.foreign_type)
18
+ end
19
+
20
+ def saved_change_to_target?
13
21
  super || owner.saved_change_to_attribute?(reflection.foreign_type)
14
22
  end
15
23
 
16
24
  private
17
- def replace_keys(record)
25
+ def replace_keys(record, force: false)
18
26
  super
19
- owner[reflection.foreign_type] = record ? record.class.polymorphic_name : nil
20
- end
21
27
 
22
- def different_target?(record)
23
- super || record.class != klass
28
+ target_type = record ? record.class.polymorphic_name : nil
29
+
30
+ if force || owner._read_attribute(reflection.foreign_type) != target_type
31
+ owner[reflection.foreign_type] = target_type
32
+ end
24
33
  end
25
34
 
26
35
  def inverse_reflection_for(record)
@@ -12,13 +12,15 @@
12
12
  # - HasManyAssociation
13
13
 
14
14
  module ActiveRecord::Associations::Builder # :nodoc:
15
- class Association #:nodoc:
15
+ class Association # :nodoc:
16
16
  class << self
17
17
  attr_accessor :extensions
18
18
  end
19
19
  self.extensions = []
20
20
 
21
- VALID_OPTIONS = [:class_name, :anonymous_class, :foreign_key, :validate] # :nodoc:
21
+ VALID_OPTIONS = [
22
+ :class_name, :anonymous_class, :primary_key, :foreign_key, :dependent, :validate, :inverse_of, :strict_loading
23
+ ].freeze # :nodoc:
22
24
 
23
25
  def self.build(model, name, scope, options, &block)
24
26
  if model.dangerous_attribute_method?(name)
@@ -27,40 +29,33 @@ module ActiveRecord::Associations::Builder # :nodoc:
27
29
  "Please choose a different association name."
28
30
  end
29
31
 
30
- extension = define_extensions model, name, &block
31
- reflection = create_reflection model, name, scope, options, extension
32
+ reflection = create_reflection(model, name, scope, options, &block)
32
33
  define_accessors model, reflection
33
34
  define_callbacks model, reflection
34
35
  define_validations model, reflection
36
+ define_change_tracking_methods model, reflection
35
37
  reflection
36
38
  end
37
39
 
38
- def self.create_reflection(model, name, scope, options, extension = nil)
40
+ def self.create_reflection(model, name, scope, options, &block)
39
41
  raise ArgumentError, "association names must be a Symbol" unless name.kind_of?(Symbol)
40
42
 
41
43
  validate_options(options)
42
44
 
43
- scope = build_scope(scope, extension)
45
+ extension = define_extensions(model, name, &block)
46
+ options[:extend] = [*options[:extend], extension] if extension
47
+
48
+ scope = build_scope(scope)
44
49
 
45
50
  ActiveRecord::Reflection.create(macro, name, scope, options, model)
46
51
  end
47
52
 
48
- def self.build_scope(scope, extension)
49
- new_scope = scope
50
-
53
+ def self.build_scope(scope)
51
54
  if scope && scope.arity == 0
52
- new_scope = proc { instance_exec(&scope) }
55
+ proc { instance_exec(&scope) }
56
+ else
57
+ scope
53
58
  end
54
-
55
- if extension
56
- new_scope = wrap_scope new_scope, extension
57
- end
58
-
59
- new_scope
60
- end
61
-
62
- def self.wrap_scope(scope, extension)
63
- scope
64
59
  end
65
60
 
66
61
  def self.macro
@@ -80,8 +75,9 @@ module ActiveRecord::Associations::Builder # :nodoc:
80
75
 
81
76
  def self.define_callbacks(model, reflection)
82
77
  if dependent = reflection.options[:dependent]
83
- check_dependent_options(dependent)
78
+ check_dependent_options(dependent, model)
84
79
  add_destroy_callbacks(model, reflection)
80
+ add_after_commit_jobs_callback(model, dependent)
85
81
  end
86
82
 
87
83
  Association.extensions.each do |extension|
@@ -122,11 +118,19 @@ module ActiveRecord::Associations::Builder # :nodoc:
122
118
  # noop
123
119
  end
124
120
 
121
+ def self.define_change_tracking_methods(model, reflection)
122
+ # noop
123
+ end
124
+
125
125
  def self.valid_dependent_options
126
126
  raise NotImplementedError
127
127
  end
128
128
 
129
- def self.check_dependent_options(dependent)
129
+ def self.check_dependent_options(dependent, model)
130
+ if dependent == :destroy_async && !model.destroy_association_async_job
131
+ err_message = "ActiveJob is required to use destroy_async on associations"
132
+ raise ActiveRecord::ActiveJobRequiredError, err_message
133
+ end
130
134
  unless valid_dependent_options.include? dependent
131
135
  raise ArgumentError, "The :dependent option must be one of #{valid_dependent_options}, but is :#{dependent}"
132
136
  end
@@ -134,7 +138,32 @@ module ActiveRecord::Associations::Builder # :nodoc:
134
138
 
135
139
  def self.add_destroy_callbacks(model, reflection)
136
140
  name = reflection.name
137
- model.before_destroy lambda { |o| o.association(name).handle_dependency }
141
+ model.before_destroy(->(o) { o.association(name).handle_dependency })
138
142
  end
143
+
144
+ def self.add_after_commit_jobs_callback(model, dependent)
145
+ if dependent == :destroy_async
146
+ mixin = model.generated_association_methods
147
+
148
+ unless mixin.method_defined?(:_after_commit_jobs)
149
+ model.after_commit(-> do
150
+ _after_commit_jobs.each do |job_class, job_arguments|
151
+ job_class.perform_later(**job_arguments)
152
+ end
153
+ end)
154
+
155
+ mixin.class_eval <<-CODE, __FILE__, __LINE__ + 1
156
+ def _after_commit_jobs
157
+ @_after_commit_jobs ||= []
158
+ end
159
+ CODE
160
+ end
161
+ end
162
+ end
163
+
164
+ private_class_method :build_scope, :macro, :valid_options, :validate_options, :define_extensions,
165
+ :define_callbacks, :define_accessors, :define_readers, :define_writers, :define_validations,
166
+ :define_change_tracking_methods, :valid_dependent_options, :check_dependent_options,
167
+ :add_destroy_callbacks, :add_after_commit_jobs_callback
139
168
  end
140
169
  end
@@ -1,17 +1,20 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module ActiveRecord::Associations::Builder # :nodoc:
4
- class BelongsTo < SingularAssociation #:nodoc:
4
+ class BelongsTo < SingularAssociation # :nodoc:
5
5
  def self.macro
6
6
  :belongs_to
7
7
  end
8
8
 
9
9
  def self.valid_options(options)
10
- super + [:polymorphic, :touch, :counter_cache, :optional, :default]
10
+ valid = super + [:polymorphic, :counter_cache, :optional, :default]
11
+ valid += [:foreign_type] if options[:polymorphic]
12
+ valid += [:ensuring_owner_was] if options[:dependent] == :destroy_async
13
+ valid
11
14
  end
12
15
 
13
16
  def self.valid_dependent_options
14
- [:destroy, :delete]
17
+ [:destroy, :delete, :destroy_async]
15
18
  end
16
19
 
17
20
  def self.define_callbacks(model, reflection)
@@ -21,58 +24,16 @@ module ActiveRecord::Associations::Builder # :nodoc:
21
24
  add_default_callbacks(model, reflection) if reflection.options[:default]
22
25
  end
23
26
 
24
- def self.define_accessors(mixin, reflection)
25
- super
26
- add_counter_cache_methods mixin
27
- end
28
-
29
- def self.add_counter_cache_methods(mixin)
30
- return if mixin.method_defined? :belongs_to_counter_cache_after_update
31
-
32
- mixin.class_eval do
33
- def belongs_to_counter_cache_after_update(reflection)
34
- foreign_key = reflection.foreign_key
35
- cache_column = reflection.counter_cache_column
36
-
37
- if (@_after_replace_counter_called ||= false)
38
- @_after_replace_counter_called = false
39
- elsif association(reflection.name).target_changed?
40
- if reflection.polymorphic?
41
- model = attribute_in_database(reflection.foreign_type).try(:constantize)
42
- model_was = attribute_before_last_save(reflection.foreign_type).try(:constantize)
43
- else
44
- model = reflection.klass
45
- model_was = reflection.klass
46
- end
47
-
48
- foreign_key_was = attribute_before_last_save foreign_key
49
- foreign_key = attribute_in_database foreign_key
50
-
51
- if foreign_key && model.respond_to?(:increment_counter)
52
- foreign_key = counter_cache_target(reflection, model, foreign_key)
53
- model.increment_counter(cache_column, foreign_key)
54
- end
55
-
56
- if foreign_key_was && model_was.respond_to?(:decrement_counter)
57
- foreign_key_was = counter_cache_target(reflection, model_was, foreign_key_was)
58
- model_was.decrement_counter(cache_column, foreign_key_was)
59
- end
60
- end
61
- end
62
-
63
- private
64
- def counter_cache_target(reflection, model, foreign_key)
65
- primary_key = reflection.association_primary_key(model)
66
- model.unscoped.where!(primary_key => foreign_key)
67
- end
68
- end
69
- end
70
-
71
27
  def self.add_counter_cache_callbacks(model, reflection)
72
28
  cache_column = reflection.counter_cache_column
73
29
 
74
30
  model.after_update lambda { |record|
75
- record.belongs_to_counter_cache_after_update(reflection)
31
+ association = association(reflection.name)
32
+
33
+ if association.saved_change_to_target?
34
+ association.increment_counters
35
+ association.decrement_counters_before_last_save
36
+ end
76
37
  }
77
38
 
78
39
  klass = reflection.class_name.safe_constantize
@@ -88,7 +49,7 @@ module ActiveRecord::Associations::Builder # :nodoc:
88
49
  if reflection.polymorphic?
89
50
  foreign_type = reflection.foreign_type
90
51
  klass = changes[foreign_type] && changes[foreign_type].first || o.public_send(foreign_type)
91
- klass = klass.constantize
52
+ klass = o.class.polymorphic_class_for(klass)
92
53
  else
93
54
  klass = association.klass
94
55
  end
@@ -97,38 +58,44 @@ module ActiveRecord::Associations::Builder # :nodoc:
97
58
 
98
59
  if old_record
99
60
  if touch != true
100
- old_record.send(touch_method, touch)
61
+ old_record.public_send(touch_method, touch)
101
62
  else
102
- old_record.send(touch_method)
63
+ old_record.public_send(touch_method)
103
64
  end
104
65
  end
105
66
  end
106
67
 
107
- record = o.send name
68
+ record = o.public_send name
108
69
  if record && record.persisted?
109
70
  if touch != true
110
- record.send(touch_method, touch)
71
+ record.public_send(touch_method, touch)
111
72
  else
112
- record.send(touch_method)
73
+ record.public_send(touch_method)
113
74
  end
114
75
  end
115
76
  end
116
77
 
117
78
  def self.add_touch_callbacks(model, reflection)
118
79
  foreign_key = reflection.foreign_key
119
- n = reflection.name
80
+ name = reflection.name
120
81
  touch = reflection.options[:touch]
121
82
 
122
83
  callback = lambda { |changes_method| lambda { |record|
123
- BelongsTo.touch_record(record, record.send(changes_method), foreign_key, n, touch, belongs_to_touch_method)
84
+ BelongsTo.touch_record(record, record.send(changes_method), foreign_key, name, touch, belongs_to_touch_method)
124
85
  }}
125
86
 
126
- unless reflection.counter_cache_column
87
+ if reflection.counter_cache_column
88
+ touch_callback = callback.(:saved_changes)
89
+ update_callback = lambda { |record|
90
+ instance_exec(record, &touch_callback) unless association(reflection.name).saved_change_to_target?
91
+ }
92
+ model.after_update update_callback, if: :saved_changes?
93
+ else
127
94
  model.after_create callback.(:saved_changes), if: :saved_changes?
95
+ model.after_update callback.(:saved_changes), if: :saved_changes?
128
96
  model.after_destroy callback.(:changes_to_save)
129
97
  end
130
98
 
131
- model.after_update callback.(:saved_changes), if: :saved_changes?
132
99
  model.after_touch callback.(:changes_to_save)
133
100
  end
134
101
 
@@ -159,5 +126,21 @@ module ActiveRecord::Associations::Builder # :nodoc:
159
126
  model.validates_presence_of reflection.name, message: :required
160
127
  end
161
128
  end
129
+
130
+ def self.define_change_tracking_methods(model, reflection)
131
+ model.generated_association_methods.class_eval <<-CODE, __FILE__, __LINE__ + 1
132
+ def #{reflection.name}_changed?
133
+ association(:#{reflection.name}).target_changed?
134
+ end
135
+
136
+ def #{reflection.name}_previously_changed?
137
+ association(:#{reflection.name}).target_previously_changed?
138
+ end
139
+ CODE
140
+ end
141
+
142
+ private_class_method :macro, :valid_options, :valid_dependent_options, :define_callbacks,
143
+ :define_validations, :define_change_tracking_methods, :add_counter_cache_callbacks,
144
+ :add_touch_callbacks, :add_default_callbacks, :add_destroy_callbacks
162
145
  end
163
146
  end
@@ -3,12 +3,11 @@
3
3
  require "active_record/associations"
4
4
 
5
5
  module ActiveRecord::Associations::Builder # :nodoc:
6
- class CollectionAssociation < Association #:nodoc:
6
+ class CollectionAssociation < Association # :nodoc:
7
7
  CALLBACKS = [:before_add, :after_add, :before_remove, :after_remove]
8
8
 
9
9
  def self.valid_options(options)
10
- super + [:table_name, :before_add,
11
- :after_add, :before_remove, :after_remove, :extend]
10
+ super + [:before_add, :after_add, :before_remove, :after_remove, :extend]
12
11
  end
13
12
 
14
13
  def self.define_callbacks(model, reflection)
@@ -22,18 +21,27 @@ module ActiveRecord::Associations::Builder # :nodoc:
22
21
 
23
22
  def self.define_extensions(model, name, &block)
24
23
  if block_given?
25
- extension_module_name = "#{model.name.demodulize}#{name.to_s.camelize}AssociationExtension"
24
+ extension_module_name = "#{name.to_s.camelize}AssociationExtension"
26
25
  extension = Module.new(&block)
27
- model.parent.const_set(extension_module_name, extension)
26
+ model.const_set(extension_module_name, extension)
28
27
  end
29
28
  end
30
29
 
31
30
  def self.define_callback(model, callback_name, name, options)
32
31
  full_callback_name = "#{callback_name}_for_#{name}"
33
32
 
34
- # TODO : why do i need method_defined? I think its because of the inheritance chain
35
- model.class_attribute full_callback_name unless model.method_defined?(full_callback_name)
36
- callbacks = Array(options[callback_name.to_sym]).map do |callback|
33
+ callback_values = Array(options[callback_name.to_sym])
34
+ method_defined = model.respond_to?(full_callback_name)
35
+
36
+ # If there are no callbacks, we must also check if a superclass had
37
+ # previously defined this association
38
+ return if callback_values.empty? && !method_defined
39
+
40
+ unless method_defined
41
+ model.class_attribute(full_callback_name, instance_accessor: false, instance_predicate: false)
42
+ end
43
+
44
+ callbacks = callback_values.map do |callback|
37
45
  case callback
38
46
  when Symbol
39
47
  ->(method, owner, record) { owner.send(callback, record) }
@@ -67,16 +75,6 @@ module ActiveRecord::Associations::Builder # :nodoc:
67
75
  CODE
68
76
  end
69
77
 
70
- def self.wrap_scope(scope, mod)
71
- if scope
72
- if scope.arity > 0
73
- proc { |owner| instance_exec(owner, &scope).extending(mod) }
74
- else
75
- proc { instance_exec(&scope).extending(mod) }
76
- end
77
- else
78
- proc { extending(mod) }
79
- end
80
- end
78
+ private_class_method :valid_options, :define_callback, :define_extensions, :define_readers, :define_writers
81
79
  end
82
80
  end