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
@@ -26,15 +26,32 @@ module ActiveRecord
26
26
  end
27
27
 
28
28
  def self.run
29
- ActiveRecord::Base.connection_handler.connection_pool_list.
30
- reject { |p| p.query_cache_enabled }.each { |p| p.enable_query_cache! }
29
+ pools = []
30
+
31
+ if ActiveRecord.legacy_connection_handling
32
+ ActiveRecord::Base.connection_handlers.each do |key, handler|
33
+ pools.concat(handler.connection_pool_list.reject { |p| p.query_cache_enabled }.each { |p| p.enable_query_cache! })
34
+ end
35
+ else
36
+ pools.concat(ActiveRecord::Base.connection_handler.all_connection_pools.reject { |p| p.query_cache_enabled }.each { |p| p.enable_query_cache! })
37
+ end
38
+
39
+ pools
31
40
  end
32
41
 
33
42
  def self.complete(pools)
34
43
  pools.each { |pool| pool.disable_query_cache! }
35
44
 
36
- ActiveRecord::Base.connection_handler.connection_pool_list.each do |pool|
37
- pool.release_connection if pool.active_connection? && !pool.connection.transaction_open?
45
+ if ActiveRecord.legacy_connection_handling
46
+ ActiveRecord::Base.connection_handlers.each do |_, handler|
47
+ handler.connection_pool_list.each do |pool|
48
+ pool.release_connection if pool.active_connection? && !pool.connection.transaction_open?
49
+ end
50
+ end
51
+ else
52
+ ActiveRecord::Base.connection_handler.all_connection_pools.each do |pool|
53
+ pool.release_connection if pool.active_connection? && !pool.connection.transaction_open?
54
+ end
38
55
  end
39
56
  end
40
57
 
@@ -0,0 +1,138 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "active_support/core_ext/module/attribute_accessors_per_thread"
4
+
5
+ module ActiveRecord
6
+ # = Active Record Query Logs
7
+ #
8
+ # Automatically tag SQL queries with runtime information.
9
+ #
10
+ # Default tags available for use:
11
+ #
12
+ # * +application+
13
+ # * +pid+
14
+ # * +socket+
15
+ # * +db_host+
16
+ # * +database+
17
+ #
18
+ # _Action Controller and Active Job tags are also defined when used in Rails:_
19
+ #
20
+ # * +controller+
21
+ # * +action+
22
+ # * +job+
23
+ #
24
+ # The tags used in a query can be configured directly:
25
+ #
26
+ # ActiveRecord::QueryLogs.tags = [ :application, :controller, :action, :job ]
27
+ #
28
+ # or via Rails configuration:
29
+ #
30
+ # config.active_record.query_log_tags = [ :application, :controller, :action, :job ]
31
+ #
32
+ # To add new comment tags, add a hash to the tags array containing the keys and values you
33
+ # want to add to the comment. Dynamic content can be created by setting a proc or lambda value in a hash,
34
+ # and can reference any value stored in the +context+ object.
35
+ #
36
+ # Example:
37
+ #
38
+ # tags = [
39
+ # :application,
40
+ # {
41
+ # custom_tag: ->(context) { context[:controller]&.controller_name },
42
+ # custom_value: -> { Custom.value },
43
+ # }
44
+ # ]
45
+ # ActiveRecord::QueryLogs.tags = tags
46
+ #
47
+ # The QueryLogs +context+ can be manipulated via the +ActiveSupport::ExecutionContext.set+ method.
48
+ #
49
+ # Temporary updates limited to the execution of a block:
50
+ #
51
+ # ActiveSupport::ExecutionContext.set(foo: Bar.new) do
52
+ # posts = Post.all
53
+ # end
54
+ #
55
+ # Direct updates to a context value:
56
+ #
57
+ # ActiveSupport::ExecutionContext[:foo] = Bar.new
58
+ #
59
+ # Tag comments can be prepended to the query:
60
+ #
61
+ # ActiveRecord::QueryLogs.prepend_comment = true
62
+ #
63
+ # For applications where the content will not change during the lifetime of
64
+ # the request or job execution, the tags can be cached for reuse in every query:
65
+ #
66
+ # ActiveRecord::QueryLogs.cache_query_log_tags = true
67
+ #
68
+ # This option can be set during application configuration or in a Rails initializer:
69
+ #
70
+ # config.active_record.cache_query_log_tags = true
71
+ module QueryLogs
72
+ mattr_accessor :taggings, instance_accessor: false, default: {}
73
+ mattr_accessor :tags, instance_accessor: false, default: [ :application ]
74
+ mattr_accessor :prepend_comment, instance_accessor: false, default: false
75
+ mattr_accessor :cache_query_log_tags, instance_accessor: false, default: false
76
+ thread_mattr_accessor :cached_comment, instance_accessor: false
77
+
78
+ class << self
79
+ def call(sql) # :nodoc:
80
+ if prepend_comment
81
+ "#{self.comment} #{sql}"
82
+ else
83
+ "#{sql} #{self.comment}"
84
+ end.strip
85
+ end
86
+
87
+ def clear_cache # :nodoc:
88
+ self.cached_comment = nil
89
+ end
90
+
91
+ ActiveSupport::ExecutionContext.after_change { ActiveRecord::QueryLogs.clear_cache }
92
+
93
+ private
94
+ # Returns an SQL comment +String+ containing the query log tags.
95
+ # Sets and returns a cached comment if <tt>cache_query_log_tags</tt> is +true+.
96
+ def comment
97
+ if cache_query_log_tags
98
+ self.cached_comment ||= uncached_comment
99
+ else
100
+ uncached_comment
101
+ end
102
+ end
103
+
104
+ def uncached_comment
105
+ content = tag_content
106
+ if content.present?
107
+ "/*#{escape_sql_comment(content)}*/"
108
+ end
109
+ end
110
+
111
+ def escape_sql_comment(content)
112
+ content.to_s.gsub(%r{ (/ (?: | \g<1>) \*) \+? \s* | \s* (\* (?: | \g<2>) /) }x, "")
113
+ end
114
+
115
+ def tag_content
116
+ context = ActiveSupport::ExecutionContext.to_h
117
+
118
+ tags.flat_map { |i| [*i] }.filter_map do |tag|
119
+ key, handler = tag
120
+ handler ||= taggings[key]
121
+
122
+ val = if handler.nil?
123
+ context[key]
124
+ elsif handler.respond_to?(:call)
125
+ if handler.arity == 0
126
+ handler.call
127
+ else
128
+ handler.call(context)
129
+ end
130
+ else
131
+ handler
132
+ end
133
+ "#{key}:#{val}" unless val.nil?
134
+ end.join(",")
135
+ end
136
+ end
137
+ end
138
+ end
@@ -2,45 +2,65 @@
2
2
 
3
3
  module ActiveRecord
4
4
  module Querying
5
- delegate :find, :take, :take!, :first, :first!, :last, :last!, :exists?, :any?, :many?, :none?, :one?, to: :all
6
- delegate :second, :second!, :third, :third!, :fourth, :fourth!, :fifth, :fifth!, :forty_two, :forty_two!, :third_to_last, :third_to_last!, :second_to_last, :second_to_last!, to: :all
7
- delegate :first_or_create, :first_or_create!, :first_or_initialize, to: :all
8
- delegate :find_or_create_by, :find_or_create_by!, :find_or_initialize_by, to: :all
9
- delegate :find_by, :find_by!, to: :all
10
- delegate :destroy_all, :delete_all, :update_all, to: :all
11
- delegate :find_each, :find_in_batches, :in_batches, to: :all
12
- delegate :select, :group, :order, :except, :reorder, :limit, :offset, :joins, :left_joins, :left_outer_joins, :or,
13
- :where, :rewhere, :preload, :eager_load, :includes, :from, :lock, :readonly, :extending,
14
- :having, :create_with, :distinct, :references, :none, :unscope, :merge, to: :all
15
- delegate :count, :average, :minimum, :maximum, :sum, :calculate, to: :all
16
- delegate :pluck, :ids, to: :all
5
+ QUERYING_METHODS = [
6
+ :find, :find_by, :find_by!, :take, :take!, :sole, :find_sole_by, :first, :first!, :last, :last!,
7
+ :second, :second!, :third, :third!, :fourth, :fourth!, :fifth, :fifth!,
8
+ :forty_two, :forty_two!, :third_to_last, :third_to_last!, :second_to_last, :second_to_last!,
9
+ :exists?, :any?, :many?, :none?, :one?,
10
+ :first_or_create, :first_or_create!, :first_or_initialize,
11
+ :find_or_create_by, :find_or_create_by!, :find_or_initialize_by,
12
+ :create_or_find_by, :create_or_find_by!,
13
+ :destroy_all, :delete_all, :update_all, :touch_all, :destroy_by, :delete_by,
14
+ :find_each, :find_in_batches, :in_batches,
15
+ :select, :reselect, :order, :in_order_of, :reorder, :group, :limit, :offset, :joins, :left_joins, :left_outer_joins,
16
+ :where, :rewhere, :invert_where, :preload, :extract_associated, :eager_load, :includes, :from, :lock, :readonly,
17
+ :and, :or, :annotate, :optimizer_hints, :extending,
18
+ :having, :create_with, :distinct, :references, :none, :unscope, :merge, :except, :only,
19
+ :count, :average, :minimum, :maximum, :sum, :calculate,
20
+ :pluck, :pick, :ids, :strict_loading, :excluding, :without
21
+ ].freeze # :nodoc:
22
+ delegate(*QUERYING_METHODS, to: :all)
17
23
 
18
24
  # Executes a custom SQL query against your database and returns all the results. The results will
19
- # be returned as an array with columns requested encapsulated as attributes of the model you call
20
- # this method from. If you call <tt>Product.find_by_sql</tt> then the results will be returned in
25
+ # be returned as an array, with the requested columns encapsulated as attributes of the model you call
26
+ # this method from. For example, if you call <tt>Product.find_by_sql</tt>, then the results will be returned in
21
27
  # a +Product+ object with the attributes you specified in the SQL query.
22
28
  #
23
- # If you call a complicated SQL query which spans multiple tables the columns specified by the
29
+ # If you call a complicated SQL query which spans multiple tables, the columns specified by the
24
30
  # SELECT will be attributes of the model, whether or not they are columns of the corresponding
25
31
  # table.
26
32
  #
27
- # The +sql+ parameter is a full SQL query as a string. It will be called as is, there will be
28
- # no database agnostic conversions performed. This should be a last resort because using, for example,
29
- # MySQL specific terms will lock you to using that particular database engine or require you to
33
+ # The +sql+ parameter is a full SQL query as a string. It will be called as is; there will be
34
+ # no database agnostic conversions performed. This should be a last resort because using
35
+ # database-specific terms will lock you into using that particular database engine, or require you to
30
36
  # change your call if you switch engines.
31
37
  #
32
38
  # # A simple SQL query spanning multiple tables
33
39
  # Post.find_by_sql "SELECT p.title, c.author FROM posts p, comments c WHERE p.id = c.post_id"
34
- # # => [#<Post:0x36bff9c @attributes={"title"=>"Ruby Meetup", "first_name"=>"Quentin"}>, ...]
40
+ # # => [#<Post:0x36bff9c @attributes={"title"=>"Ruby Meetup", "author"=>"Quentin"}>, ...]
35
41
  #
36
42
  # You can use the same string replacement techniques as you can with <tt>ActiveRecord::QueryMethods#where</tt>:
37
43
  #
38
44
  # Post.find_by_sql ["SELECT title FROM posts WHERE author = ? AND created > ?", author_id, start_date]
39
45
  # Post.find_by_sql ["SELECT body FROM comments WHERE author = :user_id OR approved_by = :user_id", { :user_id => user_id }]
46
+ #
47
+ # Note that building your own SQL query string from user input may expose your application to
48
+ # injection attacks (https://guides.rubyonrails.org/security.html#sql-injection).
40
49
  def find_by_sql(sql, binds = [], preparable: nil, &block)
41
- result_set = connection.select_all(sanitize_sql(sql), "#{name} Load", binds, preparable: preparable)
42
- column_types = result_set.column_types.dup
43
- attribute_types.each_key { |k| column_types.delete k }
50
+ _load_from_sql(_query_by_sql(sql, binds, preparable: preparable), &block)
51
+ end
52
+
53
+ def _query_by_sql(sql, binds = [], preparable: nil, async: false) # :nodoc:
54
+ connection.select_all(sanitize_sql(sql), "#{name} Load", binds, preparable: preparable, async: async)
55
+ end
56
+
57
+ def _load_from_sql(result_set, &block) # :nodoc:
58
+ column_types = result_set.column_types
59
+
60
+ unless column_types.empty?
61
+ column_types = column_types.reject { |k, _| attribute_types.key?(k) }
62
+ end
63
+
44
64
  message_bus = ActiveSupport::Notifications.instrumenter
45
65
 
46
66
  payload = {
@@ -49,13 +69,20 @@ module ActiveRecord
49
69
  }
50
70
 
51
71
  message_bus.instrument("instantiation.active_record", payload) do
52
- result_set.map { |record| instantiate(record, column_types, &block) }
72
+ if result_set.includes_column?(inheritance_column)
73
+ result_set.map { |record| instantiate(record, column_types, &block) }
74
+ else
75
+ # Instantiate a homogeneous set
76
+ result_set.map { |record| instantiate_instance_of(self, record, column_types, &block) }
77
+ end
53
78
  end
54
79
  end
55
80
 
56
81
  # Returns the result of an SQL statement that should only include a COUNT(*) in the SELECT part.
57
82
  # The use of this method should be restricted to complicated SQL queries that can't be executed
58
- # using the ActiveRecord::Calculations class methods. Look into those before using this.
83
+ # using the ActiveRecord::Calculations class methods. Look into those before using this method,
84
+ # as it could lock you into a specific database engine or require a code change to switch
85
+ # database engines.
59
86
  #
60
87
  # Product.count_by_sql "SELECT COUNT(*) FROM sales s, customers c WHERE s.customer_id = c.id"
61
88
  # # => 12
@@ -2,6 +2,7 @@
2
2
 
3
3
  require "active_record"
4
4
  require "rails"
5
+ require "active_support/core_ext/object/try"
5
6
  require "active_model/railtie"
6
7
 
7
8
  # For now, action_controller must always be present with
@@ -14,6 +15,7 @@ module ActiveRecord
14
15
  # = Active Record Railtie
15
16
  class Railtie < Rails::Railtie # :nodoc:
16
17
  config.active_record = ActiveSupport::OrderedOptions.new
18
+ config.active_record.encryption = ActiveSupport::OrderedOptions.new
17
19
 
18
20
  config.app_generators.orm :active_record, migration: true,
19
21
  timestamps: true
@@ -26,18 +28,21 @@ module ActiveRecord
26
28
  )
27
29
 
28
30
  config.active_record.use_schema_cache_dump = true
31
+ config.active_record.check_schema_cache_dump_version = true
29
32
  config.active_record.maintain_test_schema = true
33
+ config.active_record.has_many_inversing = false
34
+ config.active_record.sqlite3_production_warning = true
35
+ config.active_record.query_log_tags_enabled = false
36
+ config.active_record.query_log_tags = [ :application ]
37
+ config.active_record.cache_query_log_tags = false
30
38
 
31
- config.active_record.sqlite3 = ActiveSupport::OrderedOptions.new
32
- config.active_record.sqlite3.represent_boolean_as_integer = nil
39
+ config.active_record.queues = ActiveSupport::InheritableOptions.new
33
40
 
34
41
  config.eager_load_namespaces << ActiveRecord
35
42
 
36
43
  rake_tasks do
37
44
  namespace :db do
38
45
  task :load_config do
39
- ActiveRecord::Tasks::DatabaseTasks.database_configuration = Rails.application.config.database_configuration
40
-
41
46
  if defined?(ENGINE_ROOT) && engine = Rails::Engine.find(ENGINE_ROOT)
42
47
  if engine.paths["db/migrate"].existent
43
48
  ActiveRecord::Tasks::DatabaseTasks.migrations_paths += engine.paths["db/migrate"].to_a
@@ -57,9 +62,10 @@ module ActiveRecord
57
62
  require "active_record/base"
58
63
  unless ActiveSupport::Logger.logger_outputs_to?(Rails.logger, STDERR, STDOUT)
59
64
  console = ActiveSupport::Logger.new(STDERR)
65
+ console.level = Rails.logger.level
60
66
  Rails.logger.extend ActiveSupport::Logger.broadcast console
61
67
  end
62
- ActiveRecord::Base.verbose_query_logs = false
68
+ ActiveRecord.verbose_query_logs = false
63
69
  end
64
70
 
65
71
  runner do
@@ -69,7 +75,6 @@ module ActiveRecord
69
75
  initializer "active_record.initialize_timezone" do
70
76
  ActiveSupport.on_load(:active_record) do
71
77
  self.time_zone_aware_attributes = true
72
- self.default_timezone = :utc
73
78
  end
74
79
  end
75
80
 
@@ -77,31 +82,120 @@ module ActiveRecord
77
82
  ActiveSupport.on_load(:active_record) { self.logger ||= ::Rails.logger }
78
83
  end
79
84
 
80
- initializer "active_record.migration_error" do
81
- if config.active_record.delete(:migration_error) == :page_load
85
+ initializer "active_record.backtrace_cleaner" do
86
+ ActiveSupport.on_load(:active_record) { LogSubscriber.backtrace_cleaner = ::Rails.backtrace_cleaner }
87
+ end
88
+
89
+ initializer "active_record.migration_error" do |app|
90
+ if config.active_record.migration_error == :page_load
82
91
  config.app_middleware.insert_after ::ActionDispatch::Callbacks,
83
- ActiveRecord::Migration::CheckPending
92
+ ActiveRecord::Migration::CheckPending,
93
+ file_watcher: app.config.file_watcher
94
+ end
95
+ end
96
+
97
+ initializer "active_record.database_selector" do
98
+ if options = config.active_record.database_selector
99
+ resolver = config.active_record.database_resolver
100
+ operations = config.active_record.database_resolver_context
101
+ config.app_middleware.use ActiveRecord::Middleware::DatabaseSelector, resolver, operations, options
102
+ end
103
+ end
104
+
105
+ initializer "active_record.shard_selector" do
106
+ if resolver = config.active_record.shard_resolver
107
+ options = config.active_record.shard_selector || {}
108
+
109
+ config.app_middleware.use ActiveRecord::Middleware::ShardSelector, resolver, options
110
+ end
111
+ end
112
+
113
+ initializer "Check for cache versioning support" do
114
+ config.after_initialize do |app|
115
+ ActiveSupport.on_load(:active_record) do
116
+ if app.config.active_record.cache_versioning && Rails.cache
117
+ unless Rails.cache.class.try(:supports_cache_versioning?)
118
+ raise <<-end_error
119
+
120
+ You're using a cache store that doesn't support native cache versioning.
121
+ Your best option is to upgrade to a newer version of #{Rails.cache.class}
122
+ that supports cache versioning (#{Rails.cache.class}.supports_cache_versioning? #=> true).
123
+
124
+ Next best, switch to a different cache store that does support cache versioning:
125
+ https://guides.rubyonrails.org/caching_with_rails.html#cache-stores.
126
+
127
+ To keep using the current cache store, you can turn off cache versioning entirely:
128
+
129
+ config.active_record.cache_versioning = false
130
+
131
+ end_error
132
+ end
133
+ end
134
+ end
84
135
  end
85
136
  end
86
137
 
87
138
  initializer "active_record.check_schema_cache_dump" do
88
- if config.active_record.delete(:use_schema_cache_dump)
139
+ check_schema_cache_dump_version = config.active_record.check_schema_cache_dump_version
140
+
141
+ if config.active_record.use_schema_cache_dump && !config.active_record.lazily_load_schema_cache
89
142
  config.after_initialize do |app|
90
143
  ActiveSupport.on_load(:active_record) do
91
- filename = File.join(app.config.paths["db"].first, "schema_cache.yml")
144
+ db_config = ActiveRecord::Base.configurations.configs_for(env_name: Rails.env).first
145
+
146
+ filename = ActiveRecord::Tasks::DatabaseTasks.cache_dump_filename(
147
+ db_config.name,
148
+ schema_cache_path: db_config&.schema_cache_path
149
+ )
150
+
151
+ cache = ActiveRecord::ConnectionAdapters::SchemaCache.load_from(filename)
152
+ next if cache.nil?
153
+
154
+ if check_schema_cache_dump_version
155
+ current_version = begin
156
+ ActiveRecord::Migrator.current_version
157
+ rescue ActiveRecordError => error
158
+ warn "Failed to validate the schema cache because of #{error.class}: #{error.message}"
159
+ nil
160
+ end
161
+ next if current_version.nil?
92
162
 
93
- if File.file?(filename)
94
- current_version = ActiveRecord::Migrator.current_version
163
+ if cache.version != current_version
164
+ warn "Ignoring #{filename} because it has expired. The current schema version is #{current_version}, but the one in the schema cache file is #{cache.version}."
165
+ next
166
+ end
167
+ end
95
168
 
96
- next if current_version.nil?
169
+ Rails.logger.info("Using schema cache file #{filename}")
170
+ connection_pool.set_schema_cache(cache)
171
+ end
172
+ end
173
+ end
174
+ end
97
175
 
98
- cache = YAML.load(File.read(filename))
99
- if cache.version == current_version
100
- connection.schema_cache = cache
101
- connection_pool.schema_cache = cache.dup
102
- else
103
- warn "Ignoring db/schema_cache.yml because it has expired. The current schema version is #{current_version}, but the one in the cache is #{cache.version}."
176
+ initializer "active_record.define_attribute_methods" do |app|
177
+ config.after_initialize do
178
+ ActiveSupport.on_load(:active_record) do
179
+ if app.config.eager_load
180
+ begin
181
+ descendants.each do |model|
182
+ # If the schema cache was loaded from a dump, we can use it without connecting
183
+ schema_cache = model.connection_pool.schema_cache
184
+
185
+ # If there's no connection yet, we avoid connecting.
186
+ schema_cache ||= model.connected? && model.connection.schema_cache
187
+
188
+ # If the schema cache doesn't have the columns
189
+ # hash for the model cached, `define_attribute_methods` would trigger a query.
190
+ if schema_cache && schema_cache.columns_hash?(model.table_name)
191
+ model.define_attribute_methods
192
+ end
104
193
  end
194
+ rescue ActiveRecordError => error
195
+ # Regardless of whether there was already a connection or not, we rescue any database
196
+ # error because it is critical that the application can boot even if the database
197
+ # is unhealthy.
198
+ warn "Failed to define attribute methods because of #{error.class}: #{error.message}"
105
199
  end
106
200
  end
107
201
  end
@@ -116,12 +210,58 @@ module ActiveRecord
116
210
  end
117
211
  end
118
212
 
213
+ SQLITE3_PRODUCTION_WARN = "You are running SQLite in production, this is generally not recommended."\
214
+ " You can disable this warning by setting \"config.active_record.sqlite3_production_warning=false\"."
215
+ initializer "active_record.sqlite3_production_warning" do
216
+ if config.active_record.sqlite3_production_warning && Rails.env.production?
217
+ ActiveSupport.on_load(:active_record_sqlite3adapter) do
218
+ Rails.logger.warn(SQLITE3_PRODUCTION_WARN)
219
+ end
220
+ end
221
+ end
222
+
119
223
  initializer "active_record.set_configs" do |app|
224
+ configs = app.config.active_record
225
+
226
+ config.after_initialize do
227
+ configs.each do |k, v|
228
+ next if k == :encryption
229
+ setter = "#{k}="
230
+ if ActiveRecord.respond_to?(setter)
231
+ ActiveRecord.send(setter, v)
232
+ end
233
+ end
234
+ end
235
+
120
236
  ActiveSupport.on_load(:active_record) do
121
- configs = app.config.active_record.dup
122
- configs.delete(:sqlite3)
237
+ # Configs used in other initializers
238
+ configs = configs.except(
239
+ :migration_error,
240
+ :database_selector,
241
+ :database_resolver,
242
+ :database_resolver_context,
243
+ :shard_selector,
244
+ :shard_resolver,
245
+ :query_log_tags_enabled,
246
+ :query_log_tags,
247
+ :cache_query_log_tags,
248
+ :sqlite3_production_warning,
249
+ :check_schema_cache_dump_version,
250
+ :use_schema_cache_dump
251
+ )
252
+
123
253
  configs.each do |k, v|
124
- send "#{k}=", v
254
+ next if k == :encryption
255
+ setter = "#{k}="
256
+ # Some existing initializers might rely on Active Record configuration
257
+ # being copied from the config object to their actual destination when
258
+ # `ActiveRecord::Base` is loaded.
259
+ # So to preserve backward compatibility we copy the config a second time.
260
+ if ActiveRecord.respond_to?(setter)
261
+ ActiveRecord.send(setter, v)
262
+ else
263
+ send(setter, v)
264
+ end
125
265
  end
126
266
  end
127
267
  end
@@ -130,22 +270,12 @@ module ActiveRecord
130
270
  # and then establishes the connection.
131
271
  initializer "active_record.initialize_database" do
132
272
  ActiveSupport.on_load(:active_record) do
273
+ if ActiveRecord.legacy_connection_handling
274
+ self.connection_handlers = { ActiveRecord.writing_role => ActiveRecord::Base.default_connection_handler }
275
+ end
133
276
  self.configurations = Rails.application.config.database_configuration
134
277
 
135
- begin
136
- establish_connection
137
- rescue ActiveRecord::NoDatabaseError
138
- warn <<-end_warning
139
- Oops - You have a database configured, but it doesn't exist yet!
140
-
141
- Here's how to get started:
142
-
143
- 1. Configure your database in config/database.yml.
144
- 2. Run `bin/rails db:create` to create the database.
145
- 3. Run `bin/rails db:setup` to load your database schema.
146
- end_warning
147
- raise
148
- end
278
+ establish_connection
149
279
  end
150
280
  end
151
281
 
@@ -170,6 +300,7 @@ end_warning
170
300
 
171
301
  initializer "active_record.set_executor_hooks" do
172
302
  ActiveRecord::QueryCache.install_executor_hooks
303
+ ActiveRecord::AsynchronousQueriesTracker.install_executor_hooks
173
304
  end
174
305
 
175
306
  initializer "active_record.add_watchable_files" do |app|
@@ -194,30 +325,66 @@ end_warning
194
325
  end
195
326
  end
196
327
 
197
- initializer "active_record.check_represent_sqlite3_boolean_as_integer" do
198
- config.after_initialize do
199
- ActiveSupport.on_load(:active_record_sqlite3adapter) do
200
- represent_boolean_as_integer = Rails.application.config.active_record.sqlite3.delete(:represent_boolean_as_integer)
201
- unless represent_boolean_as_integer.nil?
202
- ActiveRecord::ConnectionAdapters::SQLite3Adapter.represent_boolean_as_integer = represent_boolean_as_integer
203
- end
328
+ initializer "active_record.set_filter_attributes" do
329
+ ActiveSupport.on_load(:active_record) do
330
+ self.filter_attributes += Rails.application.config.filter_parameters
331
+ end
332
+ end
333
+
334
+ initializer "active_record.set_signed_id_verifier_secret" do
335
+ ActiveSupport.on_load(:active_record) do
336
+ self.signed_id_verifier_secret ||= -> { Rails.application.key_generator.generate_key("active_record/signed_id") }
337
+ end
338
+ end
339
+
340
+ initializer "active_record_encryption.configuration" do |app|
341
+ ActiveRecord::Encryption.configure \
342
+ primary_key: app.credentials.dig(:active_record_encryption, :primary_key),
343
+ deterministic_key: app.credentials.dig(:active_record_encryption, :deterministic_key),
344
+ key_derivation_salt: app.credentials.dig(:active_record_encryption, :key_derivation_salt),
345
+ **config.active_record.encryption
346
+
347
+ ActiveSupport.on_load(:active_record) do
348
+ # Support extended queries for deterministic attributes and validations
349
+ if ActiveRecord::Encryption.config.extend_queries
350
+ ActiveRecord::Encryption::ExtendedDeterministicQueries.install_support
351
+ ActiveRecord::Encryption::ExtendedDeterministicUniquenessValidator.install_support
352
+ end
353
+ end
204
354
 
205
- unless ActiveRecord::ConnectionAdapters::SQLite3Adapter.represent_boolean_as_integer
206
- ActiveSupport::Deprecation.warn <<-MSG
207
- Leaving `ActiveRecord::ConnectionAdapters::SQLite3Adapter.represent_boolean_as_integer`
208
- set to false is deprecated. SQLite databases have used 't' and 'f' to serialize
209
- boolean values and must have old data converted to 1 and 0 (its native boolean
210
- serialization) before setting this flag to true. Conversion can be accomplished
211
- by setting up a rake task which runs
355
+ ActiveSupport.on_load(:active_record_fixture_set) do
356
+ # Encrypt active record fixtures
357
+ if ActiveRecord::Encryption.config.encrypt_fixtures
358
+ ActiveRecord::Fixture.prepend ActiveRecord::Encryption::EncryptedFixtures
359
+ end
360
+ end
212
361
 
213
- ExampleModel.where("boolean_column = 't'").update_all(boolean_column: 1)
214
- ExampleModel.where("boolean_column = 'f'").update_all(boolean_column: 0)
362
+ # Filtered params
363
+ ActiveSupport.on_load(:action_controller, run_once: true) do
364
+ if ActiveRecord::Encryption.config.add_to_filter_parameters
365
+ ActiveRecord::Encryption.install_auto_filtered_parameters_hook(app)
366
+ end
367
+ end
368
+ end
215
369
 
216
- for all models and all boolean columns, after which the flag must be set to
217
- true by adding the following to your application.rb file:
370
+ initializer "active_record.query_log_tags_config" do |app|
371
+ config.after_initialize do
372
+ if app.config.active_record.query_log_tags_enabled
373
+ ActiveRecord.query_transformers << ActiveRecord::QueryLogs
374
+ ActiveRecord::QueryLogs.taggings.merge!(
375
+ application: Rails.application.class.name.split("::").first,
376
+ pid: -> { Process.pid },
377
+ socket: -> { ActiveRecord::Base.connection_db_config.socket },
378
+ db_host: -> { ActiveRecord::Base.connection_db_config.host },
379
+ database: -> { ActiveRecord::Base.connection_db_config.database }
380
+ )
381
+
382
+ if app.config.active_record.query_log_tags.present?
383
+ ActiveRecord::QueryLogs.tags = app.config.active_record.query_log_tags
384
+ end
218
385
 
219
- Rails.application.config.active_record.sqlite3.represent_boolean_as_integer = true
220
- MSG
386
+ if app.config.active_record.cache_query_log_tags
387
+ ActiveRecord::QueryLogs.cache_query_log_tags = true
221
388
  end
222
389
  end
223
390
  end