activerecord 6.1.7 → 7.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (307) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +1516 -1019
  3. data/MIT-LICENSE +1 -1
  4. data/README.rdoc +17 -18
  5. data/lib/active_record/aggregations.rb +17 -14
  6. data/lib/active_record/association_relation.rb +1 -11
  7. data/lib/active_record/associations/association.rb +50 -19
  8. data/lib/active_record/associations/association_scope.rb +17 -12
  9. data/lib/active_record/associations/belongs_to_association.rb +28 -9
  10. data/lib/active_record/associations/belongs_to_polymorphic_association.rb +10 -2
  11. data/lib/active_record/associations/builder/association.rb +11 -5
  12. data/lib/active_record/associations/builder/belongs_to.rb +40 -14
  13. data/lib/active_record/associations/builder/collection_association.rb +10 -3
  14. data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +1 -5
  15. data/lib/active_record/associations/builder/has_many.rb +3 -2
  16. data/lib/active_record/associations/builder/has_one.rb +2 -1
  17. data/lib/active_record/associations/builder/singular_association.rb +6 -2
  18. data/lib/active_record/associations/collection_association.rb +35 -31
  19. data/lib/active_record/associations/collection_proxy.rb +30 -15
  20. data/lib/active_record/associations/disable_joins_association_scope.rb +59 -0
  21. data/lib/active_record/associations/foreign_association.rb +10 -3
  22. data/lib/active_record/associations/has_many_association.rb +28 -18
  23. data/lib/active_record/associations/has_many_through_association.rb +12 -7
  24. data/lib/active_record/associations/has_one_association.rb +20 -10
  25. data/lib/active_record/associations/has_one_through_association.rb +1 -1
  26. data/lib/active_record/associations/join_dependency.rb +26 -16
  27. data/lib/active_record/associations/preloader/association.rb +207 -52
  28. data/lib/active_record/associations/preloader/batch.rb +48 -0
  29. data/lib/active_record/associations/preloader/branch.rb +147 -0
  30. data/lib/active_record/associations/preloader/through_association.rb +50 -14
  31. data/lib/active_record/associations/preloader.rb +50 -121
  32. data/lib/active_record/associations/singular_association.rb +9 -3
  33. data/lib/active_record/associations/through_association.rb +25 -14
  34. data/lib/active_record/associations.rb +423 -289
  35. data/lib/active_record/asynchronous_queries_tracker.rb +60 -0
  36. data/lib/active_record/attribute_assignment.rb +1 -3
  37. data/lib/active_record/attribute_methods/before_type_cast.rb +24 -2
  38. data/lib/active_record/attribute_methods/dirty.rb +61 -14
  39. data/lib/active_record/attribute_methods/primary_key.rb +78 -26
  40. data/lib/active_record/attribute_methods/query.rb +31 -19
  41. data/lib/active_record/attribute_methods/read.rb +25 -10
  42. data/lib/active_record/attribute_methods/serialization.rb +194 -37
  43. data/lib/active_record/attribute_methods/time_zone_conversion.rb +4 -3
  44. data/lib/active_record/attribute_methods/write.rb +10 -13
  45. data/lib/active_record/attribute_methods.rb +121 -40
  46. data/lib/active_record/attributes.rb +27 -38
  47. data/lib/active_record/autosave_association.rb +61 -30
  48. data/lib/active_record/base.rb +25 -2
  49. data/lib/active_record/callbacks.rb +18 -34
  50. data/lib/active_record/coders/column_serializer.rb +61 -0
  51. data/lib/active_record/coders/json.rb +1 -1
  52. data/lib/active_record/coders/yaml_column.rb +70 -46
  53. data/lib/active_record/connection_adapters/abstract/connection_handler.rb +367 -0
  54. data/lib/active_record/connection_adapters/abstract/connection_pool/queue.rb +211 -0
  55. data/lib/active_record/connection_adapters/abstract/connection_pool/reaper.rb +78 -0
  56. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +96 -590
  57. data/lib/active_record/connection_adapters/abstract/database_limits.rb +5 -17
  58. data/lib/active_record/connection_adapters/abstract/database_statements.rb +171 -51
  59. data/lib/active_record/connection_adapters/abstract/query_cache.rb +77 -27
  60. data/lib/active_record/connection_adapters/abstract/quoting.rb +87 -73
  61. data/lib/active_record/connection_adapters/abstract/savepoints.rb +4 -3
  62. data/lib/active_record/connection_adapters/abstract/schema_creation.rb +21 -20
  63. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +186 -31
  64. data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +14 -1
  65. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +360 -136
  66. data/lib/active_record/connection_adapters/abstract/transaction.rb +281 -59
  67. data/lib/active_record/connection_adapters/abstract_adapter.rb +622 -149
  68. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +285 -156
  69. data/lib/active_record/connection_adapters/column.rb +13 -0
  70. data/lib/active_record/connection_adapters/mysql/column.rb +1 -0
  71. data/lib/active_record/connection_adapters/mysql/database_statements.rb +25 -134
  72. data/lib/active_record/connection_adapters/mysql/quoting.rb +56 -25
  73. data/lib/active_record/connection_adapters/mysql/schema_creation.rb +9 -0
  74. data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +10 -1
  75. data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +8 -2
  76. data/lib/active_record/connection_adapters/mysql/schema_statements.rb +38 -14
  77. data/lib/active_record/connection_adapters/mysql2/database_statements.rb +148 -0
  78. data/lib/active_record/connection_adapters/mysql2_adapter.rb +104 -53
  79. data/lib/active_record/connection_adapters/pool_config.rb +20 -11
  80. data/lib/active_record/connection_adapters/pool_manager.rb +19 -9
  81. data/lib/active_record/connection_adapters/postgresql/column.rb +18 -1
  82. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +86 -52
  83. data/lib/active_record/connection_adapters/postgresql/oid/array.rb +1 -1
  84. data/lib/active_record/connection_adapters/postgresql/oid/date.rb +8 -0
  85. data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +5 -0
  86. data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +53 -14
  87. data/lib/active_record/connection_adapters/postgresql/oid/range.rb +12 -3
  88. data/lib/active_record/connection_adapters/postgresql/oid/timestamp.rb +15 -0
  89. data/lib/active_record/connection_adapters/postgresql/oid/timestamp_with_time_zone.rb +30 -0
  90. data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +18 -6
  91. data/lib/active_record/connection_adapters/postgresql/oid.rb +2 -0
  92. data/lib/active_record/connection_adapters/postgresql/quoting.rb +89 -56
  93. data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +28 -0
  94. data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +92 -2
  95. data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +153 -3
  96. data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +78 -0
  97. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +381 -69
  98. data/lib/active_record/connection_adapters/postgresql/utils.rb +9 -10
  99. data/lib/active_record/connection_adapters/postgresql_adapter.rb +492 -230
  100. data/lib/active_record/connection_adapters/schema_cache.rb +319 -90
  101. data/lib/active_record/connection_adapters/sqlite3/column.rb +49 -0
  102. data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +65 -53
  103. data/lib/active_record/connection_adapters/sqlite3/quoting.rb +37 -21
  104. data/lib/active_record/connection_adapters/sqlite3/schema_definitions.rb +7 -0
  105. data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +43 -22
  106. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +294 -102
  107. data/lib/active_record/connection_adapters/statement_pool.rb +7 -0
  108. data/lib/active_record/connection_adapters/trilogy/database_statements.rb +98 -0
  109. data/lib/active_record/connection_adapters/trilogy_adapter.rb +254 -0
  110. data/lib/active_record/connection_adapters.rb +9 -6
  111. data/lib/active_record/connection_handling.rb +107 -136
  112. data/lib/active_record/core.rb +194 -224
  113. data/lib/active_record/counter_cache.rb +46 -25
  114. data/lib/active_record/database_configurations/connection_url_resolver.rb +2 -1
  115. data/lib/active_record/database_configurations/database_config.rb +21 -12
  116. data/lib/active_record/database_configurations/hash_config.rb +84 -16
  117. data/lib/active_record/database_configurations/url_config.rb +18 -12
  118. data/lib/active_record/database_configurations.rb +95 -59
  119. data/lib/active_record/delegated_type.rb +61 -15
  120. data/lib/active_record/deprecator.rb +7 -0
  121. data/lib/active_record/destroy_association_async_job.rb +3 -1
  122. data/lib/active_record/disable_joins_association_relation.rb +39 -0
  123. data/lib/active_record/dynamic_matchers.rb +1 -1
  124. data/lib/active_record/encryption/auto_filtered_parameters.rb +66 -0
  125. data/lib/active_record/encryption/cipher/aes256_gcm.rb +101 -0
  126. data/lib/active_record/encryption/cipher.rb +53 -0
  127. data/lib/active_record/encryption/config.rb +68 -0
  128. data/lib/active_record/encryption/configurable.rb +60 -0
  129. data/lib/active_record/encryption/context.rb +42 -0
  130. data/lib/active_record/encryption/contexts.rb +76 -0
  131. data/lib/active_record/encryption/derived_secret_key_provider.rb +18 -0
  132. data/lib/active_record/encryption/deterministic_key_provider.rb +14 -0
  133. data/lib/active_record/encryption/encryptable_record.rb +224 -0
  134. data/lib/active_record/encryption/encrypted_attribute_type.rb +151 -0
  135. data/lib/active_record/encryption/encrypted_fixtures.rb +38 -0
  136. data/lib/active_record/encryption/encrypting_only_encryptor.rb +12 -0
  137. data/lib/active_record/encryption/encryptor.rb +155 -0
  138. data/lib/active_record/encryption/envelope_encryption_key_provider.rb +55 -0
  139. data/lib/active_record/encryption/errors.rb +15 -0
  140. data/lib/active_record/encryption/extended_deterministic_queries.rb +172 -0
  141. data/lib/active_record/encryption/extended_deterministic_uniqueness_validator.rb +28 -0
  142. data/lib/active_record/encryption/key.rb +28 -0
  143. data/lib/active_record/encryption/key_generator.rb +53 -0
  144. data/lib/active_record/encryption/key_provider.rb +46 -0
  145. data/lib/active_record/encryption/message.rb +33 -0
  146. data/lib/active_record/encryption/message_serializer.rb +92 -0
  147. data/lib/active_record/encryption/null_encryptor.rb +21 -0
  148. data/lib/active_record/encryption/properties.rb +76 -0
  149. data/lib/active_record/encryption/read_only_null_encryptor.rb +24 -0
  150. data/lib/active_record/encryption/scheme.rb +96 -0
  151. data/lib/active_record/encryption.rb +56 -0
  152. data/lib/active_record/enum.rb +156 -62
  153. data/lib/active_record/errors.rb +171 -15
  154. data/lib/active_record/explain.rb +23 -3
  155. data/lib/active_record/explain_registry.rb +11 -6
  156. data/lib/active_record/explain_subscriber.rb +1 -1
  157. data/lib/active_record/fixture_set/file.rb +15 -1
  158. data/lib/active_record/fixture_set/model_metadata.rb +14 -4
  159. data/lib/active_record/fixture_set/render_context.rb +2 -0
  160. data/lib/active_record/fixture_set/table_row.rb +70 -14
  161. data/lib/active_record/fixture_set/table_rows.rb +4 -4
  162. data/lib/active_record/fixtures.rb +131 -86
  163. data/lib/active_record/future_result.rb +164 -0
  164. data/lib/active_record/gem_version.rb +3 -3
  165. data/lib/active_record/inheritance.rb +81 -29
  166. data/lib/active_record/insert_all.rb +133 -20
  167. data/lib/active_record/integration.rb +11 -10
  168. data/lib/active_record/internal_metadata.rb +117 -33
  169. data/lib/active_record/legacy_yaml_adapter.rb +2 -39
  170. data/lib/active_record/locking/optimistic.rb +36 -21
  171. data/lib/active_record/locking/pessimistic.rb +15 -6
  172. data/lib/active_record/log_subscriber.rb +52 -19
  173. data/lib/active_record/marshalling.rb +56 -0
  174. data/lib/active_record/message_pack.rb +124 -0
  175. data/lib/active_record/middleware/database_selector/resolver.rb +10 -10
  176. data/lib/active_record/middleware/database_selector.rb +23 -13
  177. data/lib/active_record/middleware/shard_selector.rb +62 -0
  178. data/lib/active_record/migration/command_recorder.rb +108 -13
  179. data/lib/active_record/migration/compatibility.rb +221 -48
  180. data/lib/active_record/migration/default_strategy.rb +23 -0
  181. data/lib/active_record/migration/execution_strategy.rb +19 -0
  182. data/lib/active_record/migration/join_table.rb +1 -1
  183. data/lib/active_record/migration.rb +355 -171
  184. data/lib/active_record/model_schema.rb +116 -97
  185. data/lib/active_record/nested_attributes.rb +36 -15
  186. data/lib/active_record/no_touching.rb +3 -3
  187. data/lib/active_record/normalization.rb +159 -0
  188. data/lib/active_record/persistence.rb +405 -85
  189. data/lib/active_record/promise.rb +84 -0
  190. data/lib/active_record/query_cache.rb +3 -21
  191. data/lib/active_record/query_logs.rb +174 -0
  192. data/lib/active_record/query_logs_formatter.rb +41 -0
  193. data/lib/active_record/querying.rb +29 -6
  194. data/lib/active_record/railtie.rb +219 -43
  195. data/lib/active_record/railties/controller_runtime.rb +13 -9
  196. data/lib/active_record/railties/databases.rake +185 -249
  197. data/lib/active_record/railties/job_runtime.rb +23 -0
  198. data/lib/active_record/readonly_attributes.rb +41 -3
  199. data/lib/active_record/reflection.rb +229 -80
  200. data/lib/active_record/relation/batches/batch_enumerator.rb +23 -7
  201. data/lib/active_record/relation/batches.rb +192 -63
  202. data/lib/active_record/relation/calculations.rb +211 -90
  203. data/lib/active_record/relation/delegation.rb +27 -13
  204. data/lib/active_record/relation/finder_methods.rb +108 -51
  205. data/lib/active_record/relation/merger.rb +22 -13
  206. data/lib/active_record/relation/predicate_builder/association_query_value.rb +31 -3
  207. data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +4 -6
  208. data/lib/active_record/relation/predicate_builder/relation_handler.rb +5 -1
  209. data/lib/active_record/relation/predicate_builder.rb +27 -20
  210. data/lib/active_record/relation/query_attribute.rb +30 -12
  211. data/lib/active_record/relation/query_methods.rb +654 -127
  212. data/lib/active_record/relation/record_fetch_warning.rb +7 -9
  213. data/lib/active_record/relation/spawn_methods.rb +20 -3
  214. data/lib/active_record/relation/where_clause.rb +10 -19
  215. data/lib/active_record/relation.rb +262 -120
  216. data/lib/active_record/result.rb +37 -11
  217. data/lib/active_record/runtime_registry.rb +18 -13
  218. data/lib/active_record/sanitization.rb +65 -20
  219. data/lib/active_record/schema.rb +36 -22
  220. data/lib/active_record/schema_dumper.rb +73 -24
  221. data/lib/active_record/schema_migration.rb +68 -33
  222. data/lib/active_record/scoping/default.rb +72 -15
  223. data/lib/active_record/scoping/named.rb +5 -13
  224. data/lib/active_record/scoping.rb +65 -34
  225. data/lib/active_record/secure_password.rb +60 -0
  226. data/lib/active_record/secure_token.rb +21 -3
  227. data/lib/active_record/serialization.rb +6 -1
  228. data/lib/active_record/signed_id.rb +10 -8
  229. data/lib/active_record/store.rb +10 -10
  230. data/lib/active_record/suppressor.rb +13 -15
  231. data/lib/active_record/table_metadata.rb +16 -3
  232. data/lib/active_record/tasks/database_tasks.rb +225 -136
  233. data/lib/active_record/tasks/mysql_database_tasks.rb +16 -7
  234. data/lib/active_record/tasks/postgresql_database_tasks.rb +35 -26
  235. data/lib/active_record/tasks/sqlite_database_tasks.rb +15 -7
  236. data/lib/active_record/test_databases.rb +1 -1
  237. data/lib/active_record/test_fixtures.rb +116 -96
  238. data/lib/active_record/timestamp.rb +28 -17
  239. data/lib/active_record/token_for.rb +113 -0
  240. data/lib/active_record/touch_later.rb +11 -6
  241. data/lib/active_record/transactions.rb +48 -27
  242. data/lib/active_record/translation.rb +3 -3
  243. data/lib/active_record/type/adapter_specific_registry.rb +32 -14
  244. data/lib/active_record/type/hash_lookup_type_map.rb +34 -1
  245. data/lib/active_record/type/internal/timezone.rb +7 -2
  246. data/lib/active_record/type/serialized.rb +9 -5
  247. data/lib/active_record/type/time.rb +4 -0
  248. data/lib/active_record/type/type_map.rb +17 -20
  249. data/lib/active_record/type.rb +1 -2
  250. data/lib/active_record/validations/absence.rb +1 -1
  251. data/lib/active_record/validations/associated.rb +4 -4
  252. data/lib/active_record/validations/numericality.rb +5 -4
  253. data/lib/active_record/validations/presence.rb +5 -28
  254. data/lib/active_record/validations/uniqueness.rb +51 -6
  255. data/lib/active_record/validations.rb +8 -4
  256. data/lib/active_record/version.rb +1 -1
  257. data/lib/active_record.rb +335 -32
  258. data/lib/arel/attributes/attribute.rb +0 -8
  259. data/lib/arel/crud.rb +28 -22
  260. data/lib/arel/delete_manager.rb +18 -4
  261. data/lib/arel/errors.rb +10 -0
  262. data/lib/arel/factory_methods.rb +4 -0
  263. data/lib/arel/filter_predications.rb +9 -0
  264. data/lib/arel/insert_manager.rb +2 -3
  265. data/lib/arel/nodes/and.rb +4 -0
  266. data/lib/arel/nodes/binary.rb +6 -1
  267. data/lib/arel/nodes/bound_sql_literal.rb +61 -0
  268. data/lib/arel/nodes/casted.rb +1 -1
  269. data/lib/arel/nodes/cte.rb +36 -0
  270. data/lib/arel/nodes/delete_statement.rb +12 -13
  271. data/lib/arel/nodes/filter.rb +10 -0
  272. data/lib/arel/nodes/fragments.rb +35 -0
  273. data/lib/arel/nodes/function.rb +1 -0
  274. data/lib/arel/nodes/homogeneous_in.rb +0 -8
  275. data/lib/arel/nodes/insert_statement.rb +2 -2
  276. data/lib/arel/nodes/leading_join.rb +8 -0
  277. data/lib/arel/nodes/node.rb +111 -2
  278. data/lib/arel/nodes/select_core.rb +2 -2
  279. data/lib/arel/nodes/select_statement.rb +2 -2
  280. data/lib/arel/nodes/sql_literal.rb +6 -0
  281. data/lib/arel/nodes/table_alias.rb +4 -0
  282. data/lib/arel/nodes/update_statement.rb +8 -3
  283. data/lib/arel/nodes.rb +5 -0
  284. data/lib/arel/predications.rb +13 -3
  285. data/lib/arel/select_manager.rb +10 -4
  286. data/lib/arel/table.rb +9 -6
  287. data/lib/arel/tree_manager.rb +0 -12
  288. data/lib/arel/update_manager.rb +18 -4
  289. data/lib/arel/visitors/dot.rb +80 -90
  290. data/lib/arel/visitors/mysql.rb +16 -3
  291. data/lib/arel/visitors/postgresql.rb +0 -10
  292. data/lib/arel/visitors/to_sql.rb +139 -19
  293. data/lib/arel/visitors/visitor.rb +2 -2
  294. data/lib/arel.rb +18 -3
  295. data/lib/rails/generators/active_record/application_record/USAGE +8 -0
  296. data/lib/rails/generators/active_record/application_record/templates/application_record.rb.tt +1 -1
  297. data/lib/rails/generators/active_record/migration.rb +3 -1
  298. data/lib/rails/generators/active_record/model/USAGE +113 -0
  299. data/lib/rails/generators/active_record/model/model_generator.rb +15 -6
  300. data/lib/rails/generators/active_record/model/templates/abstract_base_class.rb.tt +1 -1
  301. data/lib/rails/generators/active_record/model/templates/model.rb.tt +1 -1
  302. data/lib/rails/generators/active_record/model/templates/module.rb.tt +2 -2
  303. data/lib/rails/generators/active_record/multi_db/multi_db_generator.rb +16 -0
  304. data/lib/rails/generators/active_record/multi_db/templates/multi_db.rb.tt +44 -0
  305. metadata +92 -13
  306. data/lib/active_record/connection_adapters/legacy_pool_manager.rb +0 -35
  307. data/lib/active_record/null_relation.rb +0 -67
data/CHANGELOG.md CHANGED
@@ -1,1767 +1,2264 @@
1
- ## Rails 6.1.7 (September 09, 2022) ##
1
+ ## Rails 7.1.0 (October 05, 2023) ##
2
2
 
3
- * Symbol is allowed by default for YAML columns
3
+ * No changes.
4
4
 
5
- *Étienne Barrié*
6
5
 
7
- * Fix `ActiveRecord::Store` to serialize as a regular Hash
6
+ ## Rails 7.1.0.rc2 (October 01, 2023) ##
8
7
 
9
- Previously it would serialize as an `ActiveSupport::HashWithIndifferentAccess`
10
- which is wasteful and cause problem with YAML safe_load.
8
+ * Remove -shm and -wal SQLite files when `rails db:drop` is run.
11
9
 
12
- *Jean Boussier*
10
+ *Niklas Häusele*
13
11
 
14
- * Fix PG.connect keyword arguments deprecation warning on ruby 2.7
12
+ * Revert the change to raise an `ArgumentError` when `#accepts_nested_attributes_for` is declared more than once for
13
+ an association in the same class.
15
14
 
16
- Fixes #44307.
15
+ The reverted behavior broke the case where the `#accepts_nested_attributes_for` was defined in a concern and
16
+ where overridden in the class that included the concern.
17
17
 
18
- *Nikita Vasilevsky*
18
+ *Rafael Mendonça França*
19
+
20
+
21
+ ## Rails 7.1.0.rc1 (September 27, 2023) ##
19
22
 
20
- ## Rails 6.1.6.1 (July 12, 2022) ##
23
+ * Better naming for unique constraints support.
21
24
 
22
- * Change ActiveRecord::Coders::YAMLColumn default to safe_load
25
+ Naming unique keys leads to misunderstanding it's a short-hand of unique indexes.
26
+ Just naming it unique constraints is not misleading.
23
27
 
24
- This adds two new configuration options The configuration options are as
25
- follows:
26
-
27
- * `config.active_storage.use_yaml_unsafe_load`
28
-
29
- When set to true, this configuration option tells Rails to use the old
30
- "unsafe" YAML loading strategy, maintaining the existing behavior but leaving
31
- the possible escalation vulnerability in place. Setting this option to true
32
- is *not* recommended, but can aid in upgrading.
33
-
34
- * `config.active_record.yaml_column_permitted_classes`
35
-
36
- The "safe YAML" loading method does not allow all classes to be deserialized
37
- by default. This option allows you to specify classes deemed "safe" in your
38
- application. For example, if your application uses Symbol and Time in
39
- serialized data, you can add Symbol and Time to the allowed list as follows:
40
-
28
+ In Rails 7.1.0.beta1 or before:
29
+
30
+ ```ruby
31
+ add_unique_key :sections, [:position], deferrable: :deferred, name: "unique_section_position"
32
+ remove_unique_key :sections, name: "unique_section_position"
41
33
  ```
42
- config.active_record.yaml_column_permitted_classes = [Symbol, Date, Time]
34
+
35
+ Now:
36
+
37
+ ```ruby
38
+ add_unique_constraint :sections, [:position], deferrable: :deferred, name: "unique_section_position"
39
+ remove_unique_constraint :sections, name: "unique_section_position"
43
40
  ```
44
41
 
45
- [CVE-2022-32224]
42
+ *Ryuta Kamizono*
46
43
 
44
+ * Fix duplicate quoting for check constraint expressions in schema dump when using MySQL
47
45
 
48
- ## Rails 6.1.6 (May 09, 2022) ##
46
+ A check constraint with an expression, that already contains quotes, lead to an invalid schema
47
+ dump with the mysql2 adapter.
49
48
 
50
- * No changes.
49
+ Fixes #42424.
51
50
 
51
+ *Felix Tscheulin*
52
52
 
53
- ## Rails 6.1.5.1 (April 26, 2022) ##
53
+ * Performance tune the SQLite3 adapter connection configuration
54
54
 
55
- * No changes.
55
+ For Rails applications, the Write-Ahead-Log in normal syncing mode with a capped journal size, a healthy shared memory buffer and a shared cache will perform, on average, 2× better.
56
56
 
57
+ *Stephen Margheim*
57
58
 
58
- ## Rails 6.1.5 (March 09, 2022) ##
59
+ * Allow SQLite3 `busy_handler` to be configured with simple max number of `retries`
59
60
 
60
- * Fix `ActiveRecord::ConnectionAdapters::SchemaCache#deep_deduplicate` for Ruby 2.6.
61
+ Retrying busy connections without delay is a preferred practice for performance-sensitive applications. Add support for a `database.yml` `retries` integer, which is used in a simple `busy_handler` function to retry busy connections without exponential backoff up to the max number of `retries`.
61
62
 
62
- Ruby 2.6 and 2.7 have slightly different implementations of the `String#-@` method.
63
- In Ruby 2.6, the receiver of the `String#-@` method is modified under certain circumstances.
64
- This was later identified as a bug (https://bugs.ruby-lang.org/issues/15926) and only
65
- fixed in Ruby 2.7.
63
+ *Stephen Margheim*
66
64
 
67
- Before the changes in this commit, the
68
- `ActiveRecord::ConnectionAdapters::SchemaCache#deep_deduplicate` method, which internally
69
- calls the `String#-@` method, could also modify an input string argument in Ruby 2.6 --
70
- changing a tainted, unfrozen string into a tainted, frozen string.
65
+ * The SQLite3 adapter now supports `supports_insert_returning?`
71
66
 
72
- Fixes #43056
67
+ Implementing the full `supports_insert_returning?` contract means the SQLite3 adapter supports auto-populated columns (#48241) as well as custom primary keys.
73
68
 
74
- *Eric O'Hanlon*
69
+ *Stephen Margheim*
75
70
 
76
- * Fix migration compatibility to create SQLite references/belongs_to column as integer when
77
- migration version is 6.0.
71
+ * Ensure the SQLite3 adapter handles default functions with the `||` concatenation operator
78
72
 
79
- `reference`/`belongs_to` in migrations with version 6.0 were creating columns as
80
- bigint instead of integer for the SQLite Adapter.
73
+ Previously, this default function would produce the static string `"'Ruby ' || 'on ' || 'Rails'"`.
74
+ Now, the adapter will appropriately receive and use `"Ruby on Rails"`.
81
75
 
82
- *Marcelo Lauxen*
76
+ ```ruby
77
+ change_column_default "test_models", "ruby_on_rails", -> { "('Ruby ' || 'on ' || 'Rails')" }
78
+ ```
83
79
 
84
- * Fix dbconsole for 3-tier config.
80
+ *Stephen Margheim*
85
81
 
86
- *Eileen M. Uchitelle*
82
+ * Dump PostgreSQL schemas as part of the schema dump.
83
+
84
+ *Lachlan Sylvester*
85
+
86
+
87
+ ## Rails 7.1.0.beta1 (September 13, 2023) ##
87
88
 
88
- * Better handle SQL queries with invalid encoding.
89
+ * Encryption now supports `support_unencrypted_data` being set per-attribute.
90
+
91
+ You can now opt out of `support_unencrypted_data` on a specific encrypted attribute.
92
+ This only has an effect if `ActiveRecord::Encryption.config.support_unencrypted_data == true`.
89
93
 
90
94
  ```ruby
91
- Post.create(name: "broken \xC8 UTF-8")
95
+ class User < ActiveRecord::Base
96
+ encrypts :name, deterministic: true, support_unencrypted_data: false
97
+ encrypts :email, deterministic: true
98
+ end
92
99
  ```
93
100
 
94
- Would cause all adapters to fail in a non controlled way in the code
95
- responsible to detect write queries.
101
+ *Alex Ghiculescu*
96
102
 
97
- The query is now properly passed to the database connection, which might or might
98
- not be able to handle it, but will either succeed or failed in a more correct way.
103
+ * Add instrumentation for Active Record transactions
99
104
 
100
- *Jean Boussier*
105
+ Allows subscribing to transaction events for tracking/instrumentation. The event payload contains the connection and the outcome (commit, rollback, restart, incomplete), as well as timing details.
101
106
 
102
- * Ignore persisted in-memory records when merging target lists.
107
+ ```ruby
108
+ ActiveSupport::Notifications.subscribe("transaction.active_record") do |event|
109
+ puts "Transaction event occurred!"
110
+ connection = event.payload[:connection]
111
+ puts "Connection: #{connection.inspect}"
112
+ end
113
+ ```
103
114
 
104
- *Kevin Sjöberg*
115
+ *Daniel Colson*, *Ian Candy*
105
116
 
106
- * Fix regression bug that caused ignoring additional conditions for preloading
107
- `has_many` through relations.
117
+ * Support composite foreign keys via migration helpers.
108
118
 
109
- Fixes #43132
119
+ ```ruby
120
+ # Assuming "carts" table has "(shop_id, user_id)" as a primary key.
110
121
 
111
- *Alexander Pauly*
122
+ add_foreign_key(:orders, :carts, primary_key: [:shop_id, :user_id])
112
123
 
113
- * Fix `ActiveRecord::InternalMetadata` to not be broken by
114
- `config.active_record.record_timestamps = false`
124
+ remove_foreign_key(:orders, :carts, primary_key: [:shop_id, :user_id])
125
+ foreign_key_exists?(:orders, :carts, primary_key: [:shop_id, :user_id])
126
+ ```
115
127
 
116
- Since the model always create the timestamp columns, it has to set them, otherwise it breaks
117
- various DB management tasks.
128
+ *fatkodima*
118
129
 
119
- Fixes #42983
130
+ * Adds support for `if_not_exists` when adding a check constraint.
120
131
 
121
- *Jean Boussier*
132
+ ```ruby
133
+ add_check_constraint :posts, "post_type IN ('blog', 'comment', 'share')", if_not_exists: true
134
+ ```
122
135
 
123
- * Fix duplicate active record objects on `inverse_of`.
136
+ *Cody Cutrer*
124
137
 
125
- *Justin Carvalho*
138
+ * Raise an `ArgumentError` when `#accepts_nested_attributes_for` is declared more than once for an association in
139
+ the same class. Previously, the last declaration would silently override the previous one. Overriding in a subclass
140
+ is still allowed.
126
141
 
127
- * Fix duplicate objects stored in has many association after save.
142
+ *Joshua Young*
128
143
 
129
- Fixes #42549.
144
+ * Deprecate `rewhere` argument on `#merge`.
130
145
 
131
- *Alex Ghiculescu*
146
+ The `rewhere` argument on `#merge`is deprecated without replacement and
147
+ will be removed in Rails 7.2.
132
148
 
133
- * Fix performance regression in `CollectionAssocation#build`.
149
+ *Adam Hess*
134
150
 
135
- *Alex Ghiculescu*
151
+ * Fix unscope is not working in specific case
136
152
 
137
- * Fix retrieving default value for text column for MariaDB.
153
+ Before:
154
+ ```ruby
155
+ Post.where(id: 1...3).unscope(where: :id).to_sql # "SELECT `posts`.* FROM `posts` WHERE `posts`.`id` >= 1 AND `posts`.`id` < 3"
138
156
 
139
- *fatkodima*
157
+ ```
140
158
 
159
+ After:
160
+ ```ruby
161
+ Post.where(id: 1...3).unscope(where: :id).to_sql # "SELECT `posts`.* FROM `posts`"
162
+ ```
141
163
 
142
- ## Rails 6.1.4.7 (March 08, 2022) ##
164
+ Fixes #48094.
143
165
 
144
- * No changes.
166
+ *Kazuya Hatanaka*
145
167
 
168
+ * Change `has_secure_token` default to `on: :initialize`
146
169
 
147
- ## Rails 6.1.4.6 (February 11, 2022) ##
170
+ Change the new default value from `on: :create` to `on: :initialize`
148
171
 
149
- * No changes.
172
+ Can be controlled by the `config.active_record.generate_secure_token_on`
173
+ configuration:
150
174
 
175
+ ```ruby
176
+ config.active_record.generate_secure_token_on = :create
177
+ ```
151
178
 
152
- ## Rails 6.1.4.5 (February 11, 2022) ##
179
+ *Sean Doyle*
153
180
 
154
- * No changes.
181
+ * Fix `change_column` not setting `precision: 6` on `datetime` columns when
182
+ using 7.0+ Migrations and SQLite.
155
183
 
184
+ *Hartley McGuire*
156
185
 
157
- ## Rails 6.1.4.4 (December 15, 2021) ##
186
+ * Support composite identifiers in `to_key`
158
187
 
159
- * No changes.
188
+ `to_key` avoids wrapping `#id` value into an `Array` if `#id` already an array
160
189
 
190
+ *Nikita Vasilevsky*
161
191
 
162
- ## Rails 6.1.4.3 (December 14, 2021) ##
192
+ * Add validation option for `enum`
163
193
 
164
- * No changes.
194
+ ```ruby
195
+ class Contract < ApplicationRecord
196
+ enum :status, %w[in_progress completed], validate: true
197
+ end
198
+ Contract.new(status: "unknown").valid? # => false
199
+ Contract.new(status: nil).valid? # => false
200
+ Contract.new(status: "completed").valid? # => true
165
201
 
202
+ class Contract < ApplicationRecord
203
+ enum :status, %w[in_progress completed], validate: { allow_nil: true }
204
+ end
205
+ Contract.new(status: "unknown").valid? # => false
206
+ Contract.new(status: nil).valid? # => true
207
+ Contract.new(status: "completed").valid? # => true
208
+ ```
166
209
 
167
- ## Rails 6.1.4.2 (December 14, 2021) ##
210
+ *Edem Topuzov*, *Ryuta Kamizono*
168
211
 
169
- * No changes.
212
+ * Allow batching methods to use already loaded relation if available
170
213
 
214
+ Calling batch methods on already loaded relations will use the records previously loaded instead of retrieving
215
+ them from the database again.
171
216
 
172
- ## Rails 6.1.4.1 (August 19, 2021) ##
217
+ *Adam Hess*
173
218
 
174
- * No changes.
219
+ * Deprecate `read_attribute(:id)` returning the primary key if the primary key is not `:id`.
175
220
 
221
+ Starting in Rails 7.2, `read_attribute(:id)` will return the value of the id column, regardless of the model's
222
+ primary key. To retrieve the value of the primary key, use `#id` instead. `read_attribute(:id)` for composite
223
+ primary key models will now return the value of the id column.
176
224
 
177
- ## Rails 6.1.4 (June 24, 2021) ##
225
+ *Adrianna Chang*
178
226
 
179
- * Do not try to rollback transactions that failed due to a `ActiveRecord::TransactionRollbackError`.
227
+ * Fix `change_table` setting datetime precision for 6.1 Migrations
180
228
 
181
- *Jamie McCarthy*
229
+ *Hartley McGuire*
182
230
 
183
- * Raise an error if `pool_config` is `nil` in `set_pool_config`.
231
+ * Fix change_column setting datetime precision for 6.1 Migrations
184
232
 
185
- *Eileen M. Uchitelle*
233
+ *Hartley McGuire*
186
234
 
187
- * Fix compatibility with `psych >= 4`.
235
+ * Add `ActiveRecord::Base#id_value` alias to access the raw value of a record's id column.
188
236
 
189
- Starting in Psych 4.0.0 `YAML.load` behaves like `YAML.safe_load`. To preserve compatibility
190
- Active Record's schema cache loader and `YAMLColumn` now uses `YAML.unsafe_load` if available.
237
+ This alias is only provided for models that declare an `:id` column.
191
238
 
192
- *Jean Boussier*
239
+ *Adrianna Chang*
193
240
 
194
- * Support using replicas when using `rails dbconsole`.
241
+ * Fix previous change tracking for `ActiveRecord::Store` when using a column with JSON structured database type
195
242
 
196
- *Christopher Thornton*
243
+ Before, the methods to access the changes made during the last save `#saved_change_to_key?`, `#saved_change_to_key`, and `#key_before_last_save` did not work if the store was defined as a `store_accessor` on a column with a JSON structured database type
197
244
 
198
- * Restore connection pools after transactional tests.
245
+ *Robert DiMartino*
199
246
 
200
- *Eugene Kenny*
247
+ * Fully support `NULLS [NOT] DISTINCT` for PostgreSQL 15+ indexes.
201
248
 
202
- * Change `upsert_all` to fails cleanly for MySQL when `:unique_by` is used.
249
+ Previous work was done to allow the index to be created in a migration, but it was not
250
+ supported in schema.rb. Additionally, the matching for `NULLS [NOT] DISTINCT` was not
251
+ in the correct order, which could have resulted in inconsistent schema detection.
203
252
 
204
- *Bastian Bartmann*
253
+ *Gregory Jones*
205
254
 
206
- * Fix user-defined `self.default_scope` to respect table alias.
255
+ * Allow escaping of literal colon characters in `sanitize_sql_*` methods when named bind variables are used
207
256
 
208
- *Ryuta Kamizono*
257
+ *Justin Bull*
209
258
 
210
- * Clear `@cache_keys` cache after `update_all`, `delete_all`, `destroy_all`.
259
+ * Fix `#previously_new_record?` to return true for destroyed records.
211
260
 
212
- *Ryuta Kamizono*
261
+ Before, if a record was created and then destroyed, `#previously_new_record?` would return true.
262
+ Now, any UPDATE or DELETE to a record is considered a change, and will result in `#previously_new_record?`
263
+ returning false.
213
264
 
214
- * Changed Arel predications `contains` and `overlaps` to use
215
- `quoted_node` so that PostgreSQL arrays are quoted properly.
265
+ *Adrianna Chang*
216
266
 
217
- *Bradley Priest*
267
+ * Specify callback in `has_secure_token`
218
268
 
219
- * Fix `merge` when the `where` clauses have string contents.
269
+ ```ruby
270
+ class User < ApplicationRecord
271
+ has_secure_token on: :initialize
272
+ end
220
273
 
221
- *Ryuta Kamizono*
274
+ User.new.token # => "abc123...."
275
+ ```
222
276
 
223
- * Fix rollback of parent destruction with nested `dependent: :destroy`.
277
+ *Sean Doyle*
224
278
 
225
- *Jacopo Beschi*
279
+ * Fix incrementation of in memory counter caches when associations overlap
226
280
 
227
- * Fix binds logging for `"WHERE ... IN ..."` statements.
281
+ When two associations had a similarly named counter cache column, Active Record
282
+ could sometime increment the wrong one.
228
283
 
229
- *Ricardo Díaz*
284
+ *Jacopo Beschi*, *Jean Boussier*
230
285
 
231
- * Handle `false` in relation strict loading checks.
286
+ * Don't show secrets for Active Record's `Cipher::Aes256Gcm#inspect`.
232
287
 
233
- Previously when a model had strict loading set to true and then had a
234
- relation set `strict_loading` to false the false wasn't considered when
235
- deciding whether to raise/warn about strict loading.
288
+ Before:
236
289
 
290
+ ```ruby
291
+ ActiveRecord::Encryption::Cipher::Aes256Gcm.new(secret).inspect
292
+ "#<ActiveRecord::Encryption::Cipher::Aes256Gcm:0x0000000104888038 ... @secret=\"\\xAF\\bFh]LV}q\\nl\\xB2U\\xB3 ... >"
293
+ ```
294
+
295
+ After:
296
+
297
+ ```ruby
298
+ ActiveRecord::Encryption::Cipher::Aes256Gcm(secret).inspect
299
+ "#<ActiveRecord::Encryption::Cipher::Aes256Gcm:0x0000000104888038>"
237
300
  ```
238
- class Dog < ActiveRecord::Base
239
- self.strict_loading_by_default = true
240
301
 
241
- has_many :treats, strict_loading: false
302
+ *Petrik de Heus*
303
+
304
+ * Bring back the historical behavior of committing transaction on non-local return.
305
+
306
+ ```ruby
307
+ Model.transaction do
308
+ model.save
309
+ return
310
+ other_model.save # not executed
242
311
  end
243
312
  ```
244
313
 
245
- In the example, `dog.treats` would still raise even though
246
- `strict_loading` was set to false. This is a bug affecting more than
247
- Active Storage which is why I made this PR superseding #41461. We need
248
- to fix this for all applications since the behavior is a little
249
- surprising. I took the test from #41461 and the code suggestion from #41453
250
- with some additions.
314
+ Historically only raised errors would trigger a rollback, but in Ruby `2.3`, the `timeout` library
315
+ started using `throw` to interrupt execution which had the adverse effect of committing open transactions.
251
316
 
252
- *Eileen M. Uchitelle*, *Radamés Roriz*
317
+ To solve this, in Active Record 6.1 the behavior was changed to instead rollback the transaction as it was safer
318
+ than to potentially commit an incomplete transaction.
253
319
 
254
- * Fix numericality validator without precision.
320
+ Using `return`, `break` or `throw` inside a `transaction` block was essentially deprecated from Rails 6.1 onwards.
255
321
 
256
- *Ryuta Kamizono*
322
+ However with the release of `timeout 0.4.0`, `Timeout.timeout` now raises an error again, and Active Record is able
323
+ to return to its original, less surprising, behavior.
257
324
 
258
- * Fix aggregate attribute on Enum types.
325
+ This historical behavior can now be opt-ed in via:
259
326
 
260
- *Ryuta Kamizono*
327
+ ```
328
+ Rails.application.config.active_record.commit_transaction_on_non_local_return = true
329
+ ```
261
330
 
262
- * Fix `CREATE INDEX` statement generation for PostgreSQL.
331
+ And is the default for new applications created in Rails 7.1.
263
332
 
264
- *eltongo*
333
+ *Jean Boussier*
265
334
 
266
- * Fix where clause on enum attribute when providing array of strings.
335
+ * Deprecate `name` argument on `#remove_connection`.
267
336
 
268
- *Ryuta Kamizono*
337
+ The `name` argument is deprecated on `#remove_connection` without replacement. `#remove_connection` should be called directly on the class that established the connection.
269
338
 
270
- * Fix `unprepared_statement` to work it when nesting.
339
+ *Eileen M. Uchitelle*
271
340
 
272
- *Ryuta Kamizono*
341
+ * Fix has_one through singular building with inverse.
273
342
 
343
+ Allows building of records from an association with a has_one through a
344
+ singular association with inverse. For belongs_to through associations,
345
+ linking the foreign key to the primary key model isn't needed.
346
+ For has_one, we cannot build records due to the association not being mutable.
274
347
 
275
- ## Rails 6.1.3.2 (May 05, 2021) ##
348
+ *Gannon McGibbon*
276
349
 
277
- * No changes.
350
+ * Disable database prepared statements when query logs are enabled
278
351
 
352
+ Prepared Statements and Query Logs are incompatible features due to query logs making every query unique.
279
353
 
280
- ## Rails 6.1.3.1 (March 26, 2021) ##
354
+ *zzak, Jean Boussier*
281
355
 
282
- * No changes.
356
+ * Support decrypting data encrypted non-deterministically with a SHA1 hash digest.
283
357
 
358
+ This adds a new Active Record encryption option to support decrypting data encrypted
359
+ non-deterministically with a SHA1 hash digest:
284
360
 
285
- ## Rails 6.1.3 (February 17, 2021) ##
361
+ ```
362
+ Rails.application.config.active_record.encryption.support_sha1_for_non_deterministic_encryption = true
363
+ ```
286
364
 
287
- * Fix the MySQL adapter to always set the right collation and charset
288
- to the connection session.
365
+ The new option addresses a problem when upgrading from 7.0 to 7.1. Due to a bug in how Active Record
366
+ Encryption was getting initialized, the key provider used for non-deterministic encryption were using
367
+ SHA-1 as its digest class, instead of the one configured globally by Rails via
368
+ `Rails.application.config.active_support.key_generator_hash_digest_class`.
289
369
 
290
- *Rafael Mendonça França*
370
+ *Cadu Ribeiro and Jorge Manrubia*
291
371
 
292
- * Fix MySQL adapter handling of time objects when prepared statements
293
- are enabled.
372
+ * Added PostgreSQL migration commands for enum rename, add value, and rename value.
294
373
 
295
- *Rafael Mendonça França*
374
+ `rename_enum` and `rename_enum_value` are reversible. Due to Postgres
375
+ limitation, `add_enum_value` is not reversible since you cannot delete enum
376
+ values. As an alternative you should drop and recreate the enum entirely.
377
+
378
+ ```ruby
379
+ rename_enum :article_status, to: :article_state
380
+ ```
296
381
 
297
- * Fix scoping in enum fields using conditions that would generate
298
- an `IN` clause.
382
+ ```ruby
383
+ add_enum_value :article_state, "archived" # will be at the end of existing values
384
+ add_enum_value :article_state, "in review", before: "published"
385
+ add_enum_value :article_state, "approved", after: "in review"
386
+ ```
299
387
 
300
- *Ryuta Kamizono*
388
+ ```ruby
389
+ rename_enum_value :article_state, from: "archived", to: "deleted"
390
+ ```
301
391
 
302
- * Skip optimised #exist? query when #include? is called on a relation
303
- with a having clause
392
+ *Ray Faddis*
304
393
 
305
- Relations that have aliased select values AND a having clause that
306
- references an aliased select value would generate an error when
307
- #include? was called, due to an optimisation that would generate
308
- call #exists? on the relation instead, which effectively alters
309
- the select values of the query (and thus removes the aliased select
310
- values), but leaves the having clause intact. Because the having
311
- clause is then referencing an aliased column that is no longer
312
- present in the simplified query, an ActiveRecord::InvalidStatement
313
- error was raised.
394
+ * Allow composite primary key to be derived from schema
314
395
 
315
- An sample query affected by this problem:
396
+ Booting an application with a schema that contains composite primary keys
397
+ will not issue warning and won't `nil`ify the `ActiveRecord::Base#primary_key` value anymore.
316
398
 
399
+ Given a `travel_routes` table definition and a `TravelRoute` model like:
317
400
  ```ruby
318
- Author.select('COUNT(*) as total_posts', 'authors.*')
319
- .joins(:posts)
320
- .group(:id)
321
- .having('total_posts > 2')
322
- .include?(Author.first)
401
+ create_table :travel_routes, primary_key: [:origin, :destination], force: true do |t|
402
+ t.string :origin
403
+ t.string :destination
404
+ end
405
+
406
+ class TravelRoute < ActiveRecord::Base; end
323
407
  ```
408
+ The `TravelRoute.primary_key` value will be automatically derived to `["origin", "destination"]`
324
409
 
325
- This change adds an addition check to the condition that skips the
326
- simplified #exists? query, which simply checks for the presence of
327
- a having clause.
410
+ *Nikita Vasilevsky*
328
411
 
329
- Fixes #41417
412
+ * Include the `connection_pool` with exceptions raised from an adapter.
330
413
 
331
- *Michael Smart*
414
+ The `connection_pool` provides added context such as the connection used
415
+ that led to the exception as well as which role and shard.
332
416
 
333
- * Increment postgres prepared statement counter before making a prepared statement, so if the statement is aborted
334
- without Rails knowledge (e.g., if app gets kill -9d during long-running query or due to Rack::Timeout), app won't end
335
- up in perpetual crash state for being inconsistent with Postgres.
417
+ *Luan Vieira*
336
418
 
337
- *wbharding*, *Martin Tepper*
419
+ * Support multiple column ordering for `find_each`, `find_in_batches` and `in_batches`.
338
420
 
421
+ When find_each/find_in_batches/in_batches are performed on a table with composite primary keys, ascending or descending order can be selected for each key.
339
422
 
340
- ## Rails 6.1.2.1 (February 10, 2021) ##
423
+ ```ruby
424
+ Person.find_each(order: [:desc, :asc]) do |person|
425
+ person.party_all_night!
426
+ end
427
+ ```
341
428
 
342
- * Fix possible DoS vector in PostgreSQL money type
429
+ *Takuya Kurimoto*
343
430
 
344
- Carefully crafted input can cause a DoS via the regular expressions used
345
- for validating the money format in the PostgreSQL adapter. This patch
346
- fixes the regexp.
431
+ * Fix where on association with has_one/has_many polymorphic relations.
347
432
 
348
- Thanks to @dee-see from Hackerone for this patch!
433
+ Before:
434
+ ```ruby
435
+ Treasure.where(price_estimates: PriceEstimate.all)
436
+ #=> SELECT (...) WHERE "treasures"."id" IN (SELECT "price_estimates"."estimate_of_id" FROM "price_estimates")
437
+ ```
349
438
 
350
- [CVE-2021-22880]
439
+ Later:
440
+ ```ruby
441
+ Treasure.where(price_estimates: PriceEstimate.all)
442
+ #=> SELECT (...) WHERE "treasures"."id" IN (SELECT "price_estimates"."estimate_of_id" FROM "price_estimates" WHERE "price_estimates"."estimate_of_type" = 'Treasure')
443
+ ```
351
444
 
352
- *Aaron Patterson*
445
+ *Lázaro Nixon*
446
+
447
+ * Assign auto populated columns on Active Record record creation.
448
+
449
+ Changes record creation logic to allow for the `auto_increment` column to be assigned
450
+ immediately after creation regardless of it's relation to the model's primary key.
353
451
 
452
+ The PostgreSQL adapter benefits the most from the change allowing for any number of auto-populated
453
+ columns to be assigned on the object immediately after row insertion utilizing the `RETURNING` statement.
354
454
 
355
- ## Rails 6.1.2 (February 09, 2021) ##
455
+ *Nikita Vasilevsky*
456
+
457
+ * Use the first key in the `shards` hash from `connected_to` for the `default_shard`.
458
+
459
+ Some applications may not want to use `:default` as a shard name in their connection model. Unfortunately Active Record expects there to be a `:default` shard because it must assume a shard to get the right connection from the pool manager. Rather than force applications to manually set this, `connects_to` can infer the default shard name from the hash of shards and will now assume that the first shard is your default.
356
460
 
357
- * Fix timestamp type for sqlite3.
461
+ For example if your model looked like this:
462
+
463
+ ```ruby
464
+ class ShardRecord < ApplicationRecord
465
+ self.abstract_class = true
466
+
467
+ connects_to shards: {
468
+ shard_one: { writing: :shard_one },
469
+ shard_two: { writing: :shard_two }
470
+ }
471
+ ```
472
+
473
+ Then the `default_shard` for this class would be set to `shard_one`.
474
+
475
+ Fixes: #45390
358
476
 
359
477
  *Eileen M. Uchitelle*
360
478
 
361
- * Make destroy async transactional.
479
+ * Fix mutation detection for serialized attributes backed by binary columns.
362
480
 
363
- An active record rollback could occur while enqueuing a job. In this
364
- case the job would enqueue even though the database deletion
365
- rolledback putting things in a funky state.
481
+ *Jean Boussier*
366
482
 
367
- Now the jobs are only enqueued until after the db transaction has been committed.
483
+ * Add `ActiveRecord.disconnect_all!` method to immediately close all connections from all pools.
368
484
 
369
- *Cory Gwin*
485
+ *Jean Boussier*
370
486
 
371
- * Fix malformed packet error in MySQL statement for connection configuration.
487
+ * Discard connections which may have been left in a transaction.
372
488
 
373
- *robinroestenburg*
489
+ There are cases where, due to an error, `within_new_transaction` may unexpectedly leave a connection in an open transaction. In these cases the connection may be reused, and the following may occur:
490
+ - Writes appear to fail when they actually succeed.
491
+ - Writes appear to succeed when they actually fail.
492
+ - Reads return stale or uncommitted data.
374
493
 
375
- * Connection specification now passes the "url" key as a configuration for the
376
- adapter if the "url" protocol is "jdbc", "http", or "https". Previously only
377
- urls with the "jdbc" prefix were passed to the Active Record Adapter, others
378
- are assumed to be adapter specification urls.
494
+ Previously, the following case was detected:
495
+ - An error is encountered during the transaction, then another error is encountered while attempting to roll it back.
379
496
 
380
- Fixes #41137.
497
+ Now, the following additional cases are detected:
498
+ - An error is encountered just after successfully beginning a transaction.
499
+ - An error is encountered while committing a transaction, then another error is encountered while attempting to roll it back.
500
+ - An error is encountered while rolling back a transaction.
381
501
 
382
- *Jonathan Bracy*
502
+ *Nick Dower*
383
503
 
384
- * Fix granular connection swapping when there are multiple abstract classes.
504
+ * Active Record query cache now evicts least recently used entries
385
505
 
386
- *Eileen M. Uchitelle*
506
+ By default it only keeps the `100` most recently used queries.
387
507
 
388
- * Fix `find_by` with custom primary key for belongs_to association.
508
+ The cache size can be configured via `database.yml`
389
509
 
390
- *Ryuta Kamizono*
510
+ ```yaml
511
+ development:
512
+ adapter: mysql2
513
+ query_cache: 200
514
+ ```
391
515
 
392
- * Add support for `rails console --sandbox` for multiple database applications.
516
+ It can also be entirely disabled:
393
517
 
394
- *alpaca-tc*
518
+ ```yaml
519
+ development:
520
+ adapter: mysql2
521
+ query_cache: false
522
+ ```
395
523
 
396
- * Fix `where` on polymorphic association with empty array.
524
+ *Jean Boussier*
397
525
 
398
- *Ryuta Kamizono*
526
+ * Deprecate `check_pending!` in favor of `check_all_pending!`.
399
527
 
400
- * Fix preventing writes for `ApplicationRecord`.
528
+ `check_pending!` will only check for pending migrations on the current database connection or the one passed in. This has been deprecated in favor of `check_all_pending!` which will find all pending migrations for the database configurations in a given environment.
401
529
 
402
530
  *Eileen M. Uchitelle*
403
531
 
532
+ * Make `increment_counter`/`decrement_counter` accept an amount argument
404
533
 
405
- ## Rails 6.1.1 (January 07, 2021) ##
534
+ ```ruby
535
+ Post.increment_counter(:comments_count, 5, by: 3)
536
+ ```
406
537
 
407
- * Fix fixtures loading when strict loading is enabled for the association.
538
+ *fatkodima*
408
539
 
409
- *Alex Ghiculescu*
540
+ * Add support for `Array#intersect?` to `ActiveRecord::Relation`.
410
541
 
411
- * Fix `where` with custom primary key for belongs_to association.
542
+ `Array#intersect?` is only available on Ruby 3.1 or later.
412
543
 
413
- *Ryuta Kamizono*
544
+ This allows the Rubocop `Style/ArrayIntersect` cop to work with `ActiveRecord::Relation` objects.
414
545
 
415
- * Fix `where` with aliased associations.
546
+ *John Harry Kelly*
416
547
 
417
- *Ryuta Kamizono*
548
+ * The deferrable foreign key can be passed to `t.references`.
418
549
 
419
- * Fix `composed_of` with symbol mapping.
550
+ *Hiroyuki Ishii*
420
551
 
421
- *Ryuta Kamizono*
552
+ * Deprecate `deferrable: true` option of `add_foreign_key`.
422
553
 
423
- * Don't skip money's type cast for pluck and calculations.
554
+ `deferrable: true` is deprecated in favor of `deferrable: :immediate`, and
555
+ will be removed in Rails 7.2.
424
556
 
425
- *Ryuta Kamizono*
557
+ Because `deferrable: true` and `deferrable: :deferred` are hard to understand.
558
+ Both true and :deferred are truthy values.
559
+ This behavior is the same as the deferrable option of the add_unique_key method, added in #46192.
426
560
 
427
- * Fix `where` on polymorphic association with non Active Record object.
561
+ *Hiroyuki Ishii*
428
562
 
429
- *Ryuta Kamizono*
563
+ * `AbstractAdapter#execute` and `#exec_query` now clear the query cache
430
564
 
431
- * Make sure `db:prepare` works even the schema file doesn't exist.
565
+ If you need to perform a read only SQL query without clearing the query
566
+ cache, use `AbstractAdapter#select_all`.
432
567
 
433
- *Rafael Mendonça França*
568
+ *Jean Boussier*
434
569
 
435
- * Fix complicated `has_many :through` with nested where condition.
570
+ * Make `.joins` / `.left_outer_joins` work with CTEs.
436
571
 
437
- *Ryuta Kamizono*
572
+ For example:
438
573
 
439
- * Handle STI models for `has_many dependent: :destroy_async`.
574
+ ```ruby
575
+ Post
576
+ .with(commented_posts: Comment.select(:post_id).distinct)
577
+ .joins(:commented_posts)
578
+ #=> WITH (...) SELECT ... INNER JOIN commented_posts on posts.id = commented_posts.post_id
579
+ ```
440
580
 
441
- *Muhammad Usman*
581
+ *Vladimir Dementyev*
442
582
 
443
- * Restore possibility of passing `false` to :polymorphic option of `belongs_to`.
583
+ * Add a load hook for `ActiveRecord::ConnectionAdapters::Mysql2Adapter`
584
+ (named `active_record_mysql2adapter`) to allow for overriding aspects of the
585
+ `ActiveRecord::ConnectionAdapters::Mysql2Adapter` class. This makes `Mysql2Adapter`
586
+ consistent with `PostgreSQLAdapter` and `SQLite3Adapter` that already have load hooks.
444
587
 
445
- Previously, passing `false` would trigger the option validation logic
446
- to throw an error saying :polymorphic would not be a valid option.
588
+ *fatkodima*
447
589
 
448
- *glaszig*
590
+ * Introduce adapter for Trilogy database client
449
591
 
450
- * Allow adding nonnamed expression indexes to be revertible.
592
+ Trilogy is a MySQL-compatible database client. Rails applications can use Trilogy
593
+ by configuring their `config/database.yml`:
451
594
 
452
- Fixes #40732.
595
+ ```yaml
596
+ development:
597
+ adapter: trilogy
598
+ database: blog_development
599
+ pool: 5
600
+ ```
453
601
 
454
- Previously, the following code would raise an error, when executed while rolling back,
455
- and the index name should be specified explicitly. Now, the index name is inferred
456
- automatically.
602
+ Or by using the `DATABASE_URL` environment variable:
457
603
 
458
604
  ```ruby
459
- add_index(:items, "to_tsvector('english', description)")
605
+ ENV['DATABASE_URL'] # => "trilogy://localhost/blog_development?pool=5"
460
606
  ```
461
607
 
462
- *fatkodima*
608
+ *Adrianna Chang*
463
609
 
610
+ * `after_commit` callbacks defined on models now execute in the correct order.
464
611
 
465
- ## Rails 6.1.0 (December 09, 2020) ##
612
+ ```ruby
613
+ class User < ActiveRecord::Base
614
+ after_commit { puts("this gets called first") }
615
+ after_commit { puts("this gets called second") }
616
+ end
617
+ ```
466
618
 
467
- * Only warn about negative enums if a positive form that would cause conflicts exists.
619
+ Previously, the callbacks executed in the reverse order. To opt in to the new behaviour:
620
+
621
+ ```ruby
622
+ config.active_record.run_after_transaction_callbacks_in_order_defined = true
623
+ ```
468
624
 
469
- Fixes #39065.
625
+ This is the default for new apps.
470
626
 
471
627
  *Alex Ghiculescu*
472
628
 
473
- * Change `attribute_for_inspect` to take `filter_attributes` in consideration.
629
+ * Infer `foreign_key` when `inverse_of` is present on `has_one` and `has_many` associations.
474
630
 
475
- *Rafael Mendonça França*
631
+ ```ruby
632
+ has_many :citations, foreign_key: "book1_id", inverse_of: :book
633
+ ```
634
+
635
+ can be simplified to
636
+
637
+ ```ruby
638
+ has_many :citations, inverse_of: :book
639
+ ```
640
+
641
+ and the foreign_key will be read from the corresponding `belongs_to` association.
642
+
643
+ *Daniel Whitney*
644
+
645
+ * Limit max length of auto generated index names
646
+
647
+ Auto generated index names are now limited to 62 bytes, which fits within
648
+ the default index name length limits for MySQL, Postgres and SQLite.
649
+
650
+ Any index name over the limit will fallback to the new short format.
651
+
652
+ Before (too long):
653
+ ```
654
+ index_testings_on_foo_and_bar_and_first_name_and_last_name_and_administrator
655
+ ```
476
656
 
477
- * Fix odd behavior of inverse_of with multiple belongs_to to same class.
657
+ After (short format):
658
+ ```
659
+ idx_on_foo_bar_first_name_last_name_administrator_5939248142
660
+ ```
661
+
662
+ The short format includes a hash to ensure the name is unique database-wide.
478
663
 
479
- Fixes #35204.
664
+ *Mike Coutermarsh*
480
665
 
481
- *Tomoyuki Kai*
666
+ * Introduce a more stable and optimized Marshal serializer for Active Record models.
667
+
668
+ Can be enabled with `config.active_record.marshalling_format_version = 7.1`.
669
+
670
+ *Jean Boussier*
482
671
 
483
- * Build predicate conditions with objects that delegate `#id` and primary key:
672
+ * Allow specifying where clauses with column-tuple syntax.
673
+
674
+ Querying through `#where` now accepts a new tuple-syntax which accepts, as
675
+ a key, an array of columns and, as a value, an array of corresponding tuples.
676
+ The key specifies a list of columns, while the value is an array of
677
+ ordered-tuples that conform to the column list.
678
+
679
+ For instance:
484
680
 
485
681
  ```ruby
486
- class AdminAuthor
487
- delegate_missing_to :@author
682
+ # Cpk::Book => Cpk::Book(author_id: integer, number: integer, title: string, revision: integer)
683
+ # Cpk::Book.primary_key => ["author_id", "number"]
488
684
 
489
- def initialize(author)
490
- @author = author
491
- end
685
+ book = Cpk::Book.create!(author_id: 1, number: 1)
686
+ Cpk::Book.where(Cpk::Book.primary_key => [[1, 2]]) # => [book]
687
+
688
+ # Topic => Topic(id: integer, title: string, author_name: string...)
689
+
690
+ Topic.where([:title, :author_name] => [["The Alchemist", "Paulo Coelho"], ["Harry Potter", "J.K Rowling"]])
691
+ ```
692
+
693
+ *Paarth Madan*
694
+
695
+ * Allow warning codes to be ignore when reporting SQL warnings.
696
+
697
+ Active Record config that can ignore warning codes
698
+
699
+ ```ruby
700
+ # Configure allowlist of warnings that should always be ignored
701
+ config.active_record.db_warnings_ignore = [
702
+ "1062", # MySQL Error 1062: Duplicate entry
703
+ ]
704
+ ```
705
+
706
+ This is supported for the MySQL and PostgreSQL adapters.
707
+
708
+ *Nick Borromeo*
709
+
710
+ * Introduce `:active_record_fixtures` lazy load hook.
711
+
712
+ Hooks defined with this name will be run whenever `TestFixtures` is included
713
+ in a class.
714
+
715
+ ```ruby
716
+ ActiveSupport.on_load(:active_record_fixtures) do
717
+ self.fixture_paths << "test/fixtures"
492
718
  end
493
719
 
494
- Post.where(author: AdminAuthor.new(author))
720
+ klass = Class.new
721
+ klass.include(ActiveRecord::TestFixtures)
722
+
723
+ klass.fixture_paths # => ["test/fixtures"]
495
724
  ```
496
725
 
497
- *Sean Doyle*
726
+ *Andrew Novoselac*
498
727
 
499
- * Add `connected_to_many` API.
728
+ * Introduce `TestFixtures#fixture_paths`.
500
729
 
501
- This API allows applications to connect to multiple databases at once without switching all of them or implementing a deeply nested stack.
730
+ Multiple fixture paths can now be specified using the `#fixture_paths` accessor.
731
+ Apps will continue to have `test/fixtures` as their one fixture path by default,
732
+ but additional fixture paths can be specified.
502
733
 
503
- Before:
734
+ ```ruby
735
+ ActiveSupport::TestCase.fixture_paths << "component1/test/fixtures"
736
+ ActiveSupport::TestCase.fixture_paths << "component2/test/fixtures"
737
+ ```
504
738
 
505
- AnimalsRecord.connected_to(role: :reading) do
506
- MealsRecord.connected_to(role: :reading) do
507
- Dog.first # read from animals replica
508
- Dinner.first # read from meals replica
509
- Person.first # read from primary writer
510
- end
511
- end
739
+ `TestFixtures#fixture_path` is now deprecated.
512
740
 
513
- After:
741
+ *Andrew Novoselac*
514
742
 
515
- ActiveRecord::Base.connected_to_many([AnimalsRecord, MealsRecord], role: :reading) do
516
- Dog.first # read from animals replica
517
- Dinner.first # read from meals replica
518
- Person.first # read from primary writer
519
- end
743
+ * Adds support for deferrable exclude constraints in PostgreSQL.
520
744
 
521
- *Eileen M. Uchitelle*, *John Crepezzi*
745
+ By default, exclude constraints in PostgreSQL are checked after each statement.
746
+ This works for most use cases, but becomes a major limitation when replacing
747
+ records with overlapping ranges by using multiple statements.
522
748
 
523
- * Add option to raise or log for `ActiveRecord::StrictLoadingViolationError`.
749
+ ```ruby
750
+ exclusion_constraint :users, "daterange(valid_from, valid_to) WITH &&", deferrable: :immediate
751
+ ```
524
752
 
525
- Some applications may not want to raise an error in production if using `strict_loading`. This would allow an application to set strict loading to log for the production environment while still raising in development and test environments.
753
+ Passing `deferrable: :immediate` checks constraint after each statement,
754
+ but allows manually deferring the check using `SET CONSTRAINTS ALL DEFERRED`
755
+ within a transaction. This will cause the excludes to be checked after the transaction.
526
756
 
527
- Set `config.active_record.action_on_strict_loading_violation` to `:log` errors instead of raising.
757
+ It's also possible to change the default behavior from an immediate check
758
+ (after the statement), to a deferred check (after the transaction):
528
759
 
529
- *Eileen M. Uchitelle*
760
+ ```ruby
761
+ exclusion_constraint :users, "daterange(valid_from, valid_to) WITH &&", deferrable: :deferred
762
+ ```
530
763
 
531
- * Allow the inverse of a `has_one` association that was previously autosaved to be loaded.
764
+ *Hiroyuki Ishii*
532
765
 
533
- Fixes #34255.
766
+ * Respect `foreign_type` option to `delegated_type` for `{role}_class` method.
534
767
 
535
- *Steven Weber*
768
+ Usage of `delegated_type` with non-conventional `{role}_type` column names can now be specified with `foreign_type` option.
769
+ This option is the same as `foreign_type` as forwarded to the underlying `belongs_to` association that `delegated_type` wraps.
536
770
 
537
- * Optimise the length of index names for polymorphic references by using the reference name rather than the type and id column names.
771
+ *Jason Karns*
538
772
 
539
- Because the default behaviour when adding an index with multiple columns is to use all column names in the index name, this could frequently lead to overly long index names for polymorphic references which would fail the migration if it exceeded the database limit.
773
+ * Add support for unique constraints (PostgreSQL-only).
540
774
 
541
- This change reduces the chance of that happening by using the reference name, e.g. `index_my_table_on_my_reference`.
775
+ ```ruby
776
+ add_unique_key :sections, [:position], deferrable: :deferred, name: "unique_section_position"
777
+ remove_unique_key :sections, name: "unique_section_position"
778
+ ```
542
779
 
543
- Fixes #38655.
780
+ See PostgreSQL's [Unique Constraints](https://www.postgresql.org/docs/current/ddl-constraints.html#DDL-CONSTRAINTS-UNIQUE-CONSTRAINTS) documentation for more on unique constraints.
544
781
 
545
- *Luke Redpath*
782
+ By default, unique constraints in PostgreSQL are checked after each statement.
783
+ This works for most use cases, but becomes a major limitation when replacing
784
+ records with unique column by using multiple statements.
546
785
 
547
- * MySQL: Uniqueness validator now respects default database collation,
548
- no longer enforce case sensitive comparison by default.
786
+ An example of swapping unique columns between records.
549
787
 
550
- *Ryuta Kamizono*
788
+ ```ruby
789
+ # position is unique column
790
+ old_item = Item.create!(position: 1)
791
+ new_item = Item.create!(position: 2)
551
792
 
552
- * Remove deprecated methods from `ActiveRecord::ConnectionAdapters::DatabaseLimits`.
793
+ Item.transaction do
794
+ old_item.update!(position: 2)
795
+ new_item.update!(position: 1)
796
+ end
797
+ ```
553
798
 
554
- `column_name_length`
555
- `table_name_length`
556
- `columns_per_table`
557
- `indexes_per_table`
558
- `columns_per_multicolumn_index`
559
- `sql_query_length`
560
- `joins_per_query`
799
+ Using the default behavior, the transaction would fail when executing the
800
+ first `UPDATE` statement.
561
801
 
562
- *Rafael Mendonça França*
802
+ By passing the `:deferrable` option to the `add_unique_key` statement in
803
+ migrations, it's possible to defer this check.
563
804
 
564
- * Remove deprecated `ActiveRecord::ConnectionAdapters::AbstractAdapter#supports_multi_insert?`.
805
+ ```ruby
806
+ add_unique_key :items, [:position], deferrable: :immediate
807
+ ```
565
808
 
566
- *Rafael Mendonça França*
809
+ Passing `deferrable: :immediate` does not change the behaviour of the previous example,
810
+ but allows manually deferring the check using `SET CONSTRAINTS ALL DEFERRED` within a transaction.
811
+ This will cause the unique constraints to be checked after the transaction.
567
812
 
568
- * Remove deprecated `ActiveRecord::ConnectionAdapters::AbstractAdapter#supports_foreign_keys_in_create?`.
813
+ It's also possible to adjust the default behavior from an immediate
814
+ check (after the statement), to a deferred check (after the transaction):
569
815
 
570
- *Rafael Mendonça França*
816
+ ```ruby
817
+ add_unique_key :items, [:position], deferrable: :deferred
818
+ ```
571
819
 
572
- * Remove deprecated `ActiveRecord::ConnectionAdapters::PostgreSQLAdapter#supports_ranges?`.
820
+ If you want to change an existing unique index to deferrable, you can use :using_index
821
+ to create deferrable unique constraints.
573
822
 
574
- *Rafael Mendonça França*
823
+ ```ruby
824
+ add_unique_key :items, deferrable: :deferred, using_index: "index_items_on_position"
825
+ ```
575
826
 
576
- * Remove deprecated `ActiveRecord::Base#update_attributes` and `ActiveRecord::Base#update_attributes!`.
827
+ *Hiroyuki Ishii*
828
+
829
+ * Remove deprecated `Tasks::DatabaseTasks.schema_file_type`.
577
830
 
578
831
  *Rafael Mendonça França*
579
832
 
580
- * Remove deprecated `migrations_path` argument in `ActiveRecord::ConnectionAdapter::SchemaStatements#assume_migrated_upto_version`.
833
+ * Remove deprecated `config.active_record.partial_writes`.
581
834
 
582
835
  *Rafael Mendonça França*
583
836
 
584
- * Remove deprecated `config.active_record.sqlite3.represent_boolean_as_integer`.
837
+ * Remove deprecated `ActiveRecord::Base` config accessors.
585
838
 
586
839
  *Rafael Mendonça França*
587
840
 
588
- * `relation.create` does no longer leak scope to class level querying methods
589
- in initialization block and callbacks.
841
+ * Remove the `:include_replicas` argument from `configs_for`. Use `:include_hidden` argument instead.
590
842
 
591
- Before:
843
+ *Eileen M. Uchitelle*
592
844
 
593
- User.where(name: "John").create do |john|
594
- User.find_by(name: "David") # => nil
595
- end
845
+ * Allow applications to lookup a config via a custom hash key.
596
846
 
597
- After:
847
+ If you have registered a custom config or want to find configs where the hash matches a specific key, now you can pass `config_key` to `configs_for`. For example if you have a `db_config` with the key `vitess` you can look up a database configuration hash by matching that key.
598
848
 
599
- User.where(name: "John").create do |john|
600
- User.find_by(name: "David") # => #<User name: "David", ...>
601
- end
849
+ ```ruby
850
+ ActiveRecord::Base.configurations.configs_for(env_name: "development", name: "primary", config_key: :vitess)
851
+ ActiveRecord::Base.configurations.configs_for(env_name: "development", config_key: :vitess)
852
+ ```
602
853
 
603
- *Ryuta Kamizono*
854
+ *Eileen M. Uchitelle*
855
+
856
+ * Allow applications to register a custom database configuration handler.
857
+
858
+ Adds a mechanism for registering a custom handler for cases where you want database configurations to respond to custom methods. This is useful for non-Rails database adapters or tools like Vitess that you may want to configure differently from a standard `HashConfig` or `UrlConfig`.
859
+
860
+ Given the following database YAML we want the `animals` db to create a `CustomConfig` object instead while the `primary` database will be a `UrlConfig`:
861
+
862
+ ```yaml
863
+ development:
864
+ primary:
865
+ url: postgres://localhost/primary
866
+ animals:
867
+ url: postgres://localhost/animals
868
+ custom_config:
869
+ sharded: 1
870
+ ```
604
871
 
605
- * Named scope chain does no longer leak scope to class level querying methods.
872
+ To register a custom handler first make a class that has your custom methods:
606
873
 
607
- class User < ActiveRecord::Base
608
- scope :david, -> { User.where(name: "David") }
874
+ ```ruby
875
+ class CustomConfig < ActiveRecord::DatabaseConfigurations::UrlConfig
876
+ def sharded?
877
+ custom_config.fetch("sharded", false)
878
+ end
879
+
880
+ private
881
+ def custom_config
882
+ configuration_hash.fetch(:custom_config)
609
883
  end
884
+ end
885
+ ```
610
886
 
611
- Before:
887
+ Then register the config in an initializer:
612
888
 
613
- User.where(name: "John").david
614
- # SELECT * FROM users WHERE name = 'John' AND name = 'David'
889
+ ```ruby
890
+ ActiveRecord::DatabaseConfigurations.register_db_config_handler do |env_name, name, url, config|
891
+ next unless config.key?(:custom_config)
892
+ CustomConfig.new(env_name, name, url, config)
893
+ end
894
+ ```
615
895
 
616
- After:
896
+ When the application is booted, configuration hashes with the `:custom_config` key will be `CustomConfig` objects and respond to `sharded?`. Applications must handle the condition in which Active Record should use their custom handler.
617
897
 
618
- User.where(name: "John").david
619
- # SELECT * FROM users WHERE name = 'David'
898
+ *Eileen M. Uchitelle and John Crepezzi*
620
899
 
621
- *Ryuta Kamizono*
900
+ * `ActiveRecord::Base.serialize` no longer uses YAML by default.
622
901
 
623
- * Remove deprecated methods from `ActiveRecord::DatabaseConfigurations`.
902
+ YAML isn't particularly performant and can lead to security issues
903
+ if not used carefully.
624
904
 
625
- `fetch`
626
- `each`
627
- `first`
628
- `values`
629
- `[]=`
905
+ Unfortunately there isn't really any good serializers in Ruby's stdlib
906
+ to replace it.
630
907
 
631
- *Rafael Mendonça França*
908
+ The obvious choice would be JSON, which is a fine format for this use case,
909
+ however the JSON serializer in Ruby's stdlib isn't strict enough, as it fallback
910
+ to casting unknown types to strings, which could lead to corrupted data.
632
911
 
633
- * `where.not` now generates NAND predicates instead of NOR.
912
+ Some third party JSON libraries like `Oj` have a suitable strict mode.
634
913
 
635
- Before:
914
+ So it's preferable that users choose a serializer based on their own constraints.
636
915
 
637
- User.where.not(name: "Jon", role: "admin")
638
- # SELECT * FROM users WHERE name != 'Jon' AND role != 'admin'
916
+ The original default can be restored by setting `config.active_record.default_column_serializer = YAML`.
639
917
 
640
- After:
918
+ *Jean Boussier*
641
919
 
642
- User.where.not(name: "Jon", role: "admin")
643
- # SELECT * FROM users WHERE NOT (name == 'Jon' AND role == 'admin')
920
+ * `ActiveRecord::Base.serialize` signature changed.
644
921
 
645
- *Rafael Mendonça França*
922
+ Rather than a single positional argument that accepts two possible
923
+ types of values, `serialize` now accepts two distinct keyword arguments.
646
924
 
647
- * Remove deprecated `ActiveRecord::Result#to_hash` method.
925
+ Before:
648
926
 
649
- *Rafael Mendonça França*
927
+ ```ruby
928
+ serialize :content, JSON
929
+ serialize :backtrace, Array
930
+ ```
650
931
 
651
- * Deprecate `ActiveRecord::Base.allow_unsafe_raw_sql`.
932
+ After:
652
933
 
653
- *Rafael Mendonça França*
934
+ ```ruby
935
+ serialize :content, coder: JSON
936
+ serialize :backtrace, type: Array
937
+ ```
654
938
 
655
- * Remove deprecated support for using unsafe raw SQL in `ActiveRecord::Relation` methods.
939
+ *Jean Boussier*
656
940
 
657
- *Rafael Mendonça França*
941
+ * YAML columns use `YAML.safe_dump` if available.
658
942
 
659
- * Allow users to silence the "Rails couldn't infer whether you are using multiple databases..."
660
- message using `config.active_record.suppress_multiple_database_warning`.
943
+ As of `psych 5.1.0`, `YAML.safe_dump` can now apply the same permitted
944
+ types restrictions than `YAML.safe_load`.
661
945
 
662
- *Omri Gabay*
946
+ It's preferable to ensure the payload only use allowed types when we first
947
+ try to serialize it, otherwise you may end up with invalid records in the
948
+ database.
663
949
 
664
- * Connections can be granularly switched for abstract classes when `connected_to` is called.
950
+ *Jean Boussier*
665
951
 
666
- This change allows `connected_to` to switch a `role` and/or `shard` for a single abstract class instead of all classes globally. Applications that want to use the new feature need to set `config.active_record.legacy_connection_handling` to `false` in their application configuration.
952
+ * `ActiveRecord::QueryLogs` better handle broken encoding.
667
953
 
668
- Example usage:
954
+ It's not uncommon when building queries with BLOB fields to contain
955
+ binary data. Unless the call carefully encode the string in ASCII-8BIT
956
+ it generally end up being encoded in `UTF-8`, and `QueryLogs` would
957
+ end up failing on it.
669
958
 
670
- Given an application we have a `User` model that inherits from `ApplicationRecord` and a `Dog` model that inherits from `AnimalsRecord`. `AnimalsRecord` and `ApplicationRecord` have writing and reading connections as well as shard `default`, `one`, and `two`.
959
+ `ActiveRecord::QueryLogs` no longer depend on the query to be properly encoded.
671
960
 
672
- ```ruby
673
- ActiveRecord::Base.connected_to(role: :reading) do
674
- User.first # reads from default replica
675
- Dog.first # reads from default replica
961
+ *Jean Boussier*
676
962
 
677
- AnimalsRecord.connected_to(role: :writing, shard: :one) do
678
- User.first # reads from default replica
679
- Dog.first # reads from shard one primary
680
- end
963
+ * Fix a bug where `ActiveRecord::Generators::ModelGenerator` would not respect create_table_migration template overrides.
681
964
 
682
- User.first # reads from default replica
683
- Dog.first # reads from default replica
965
+ ```
966
+ rails g model create_books title:string content:text
967
+ ```
968
+ will now read from the create_table_migration.rb.tt template in the following locations in order:
969
+ ```
970
+ lib/templates/active_record/model/create_table_migration.rb
971
+ lib/templates/active_record/migration/create_table_migration.rb
972
+ ```
684
973
 
685
- ApplicationRecord.connected_to(role: :writing, shard: :two) do
686
- User.first # reads from shard two primary
687
- Dog.first # reads from default replica
688
- end
689
- end
974
+ *Spencer Neste*
975
+
976
+ * `ActiveRecord::Relation#explain` now accepts options.
977
+
978
+ For databases and adapters which support them (currently PostgreSQL
979
+ and MySQL), options can be passed to `explain` to provide more
980
+ detailed query plan analysis:
981
+
982
+ ```ruby
983
+ Customer.where(id: 1).joins(:orders).explain(:analyze, :verbose)
690
984
  ```
691
985
 
692
- *Eileen M. Uchitelle*, *John Crepezzi*
986
+ *Reid Lynch*
987
+
988
+ * Multiple `Arel::Nodes::SqlLiteral` nodes can now be added together to
989
+ form `Arel::Nodes::Fragments` nodes. This allows joining several pieces
990
+ of SQL.
991
+
992
+ *Matthew Draper*, *Ole Friis*
693
993
 
694
- * Allow double-dash comment syntax when querying read-only databases
994
+ * `ActiveRecord::Base#signed_id` raises if called on a new record.
695
995
 
696
- *James Adam*
996
+ Previously it would return an ID that was not usable, since it was based on `id = nil`.
997
+
998
+ *Alex Ghiculescu*
697
999
 
698
- * Add `values_at` method.
1000
+ * Allow SQL warnings to be reported.
699
1001
 
700
- Returns an array containing the values associated with the given methods.
1002
+ Active Record configs can be set to enable SQL warning reporting.
701
1003
 
702
1004
  ```ruby
703
- topic = Topic.first
704
- topic.values_at(:title, :author_name)
705
- # => ["Budget", "Jason"]
1005
+ # Configure action to take when SQL query produces warning
1006
+ config.active_record.db_warnings_action = :raise
1007
+
1008
+ # Configure allowlist of warnings that should always be ignored
1009
+ config.active_record.db_warnings_ignore = [
1010
+ /Invalid utf8mb4 character string/,
1011
+ "An exact warning message",
1012
+ ]
706
1013
  ```
707
1014
 
708
- Similar to `Hash#values_at` but on an Active Record instance.
1015
+ This is supported for the MySQL and PostgreSQL adapters.
709
1016
 
710
- *Guillaume Briday*
1017
+ *Adrianna Chang*, *Paarth Madan*
711
1018
 
712
- * Fix `read_attribute_before_type_cast` to consider attribute aliases.
1019
+ * Add `#regroup` query method as a short-hand for `.unscope(:group).group(fields)`
713
1020
 
714
- *Marcelo Lauxen*
715
-
716
- * Support passing record to uniqueness validator `:conditions` callable:
1021
+ Example:
717
1022
 
718
1023
  ```ruby
719
- class Article < ApplicationRecord
720
- validates_uniqueness_of :title, conditions: ->(article) {
721
- published_at = article.published_at
722
- where(published_at: published_at.beginning_of_year..published_at.end_of_year)
723
- }
724
- end
1024
+ Post.group(:title).regroup(:author)
1025
+ # SELECT `posts`.`*` FROM `posts` GROUP BY `posts`.`author`
725
1026
  ```
726
1027
 
727
- *Eliot Sykes*
1028
+ *Danielius Visockas*
728
1029
 
729
- * `BatchEnumerator#update_all` and `BatchEnumerator#delete_all` now return the
730
- total number of rows affected, just like their non-batched counterparts.
1030
+ * PostgreSQL adapter method `enable_extension` now allows parameter to be `[schema_name.]<extension_name>`
1031
+ if the extension must be installed on another schema.
1032
+
1033
+ Example: `enable_extension('heroku_ext.hstore')`
1034
+
1035
+ *Leonardo Luarte*
1036
+
1037
+ * Add `:include` option to `add_index`.
1038
+
1039
+ Add support for including non-key columns in indexes for PostgreSQL
1040
+ with the `INCLUDE` parameter.
731
1041
 
732
1042
  ```ruby
733
- Person.in_batches.update_all("first_name = 'Eugene'") # => 42
734
- Person.in_batches.delete_all # => 42
1043
+ add_index(:users, :email, include: [:id, :created_at])
735
1044
  ```
736
1045
 
737
- Fixes #40287.
1046
+ will result in:
738
1047
 
739
- *Eugene Kenny*
1048
+ ```sql
1049
+ CREATE INDEX index_users_on_email USING btree (email) INCLUDE (id, created_at)
1050
+ ```
740
1051
 
741
- * Add support for PostgreSQL `interval` data type with conversion to
742
- `ActiveSupport::Duration` when loading records from database and
743
- serialization to ISO 8601 formatted duration string on save.
744
- Add support to define a column in migrations and get it in a schema dump.
745
- Optional column precision is supported.
1052
+ *Steve Abrams*
746
1053
 
747
- To use this in 6.1, you need to place the next string to your model file:
1054
+ * `ActiveRecord::Relation`’s `#any?`, `#none?`, and `#one?` methods take an optional pattern
1055
+ argument, more closely matching their `Enumerable` equivalents.
748
1056
 
749
- attribute :duration, :interval
1057
+ *George Claghorn*
750
1058
 
751
- To keep old behavior until 7.0 is released:
1059
+ * Add `ActiveRecord::Base.normalizes` for declaring attribute normalizations.
752
1060
 
753
- attribute :duration, :string
1061
+ An attribute normalization is applied when the attribute is assigned or
1062
+ updated, and the normalized value will be persisted to the database. The
1063
+ normalization is also applied to the corresponding keyword argument of query
1064
+ methods, allowing records to be queried using unnormalized values.
754
1065
 
755
- Example:
1066
+ For example:
756
1067
 
757
- create_table :events do |t|
758
- t.string :name
759
- t.interval :duration
760
- end
1068
+ ```ruby
1069
+ class User < ActiveRecord::Base
1070
+ normalizes :email, with: -> email { email.strip.downcase }
1071
+ normalizes :phone, with: -> phone { phone.delete("^0-9").delete_prefix("1") }
1072
+ end
761
1073
 
762
- class Event < ApplicationRecord
763
- attribute :duration, :interval
764
- end
1074
+ user = User.create(email: " CRUISE-CONTROL@EXAMPLE.COM\n")
1075
+ user.email # => "cruise-control@example.com"
1076
+
1077
+ user = User.find_by(email: "\tCRUISE-CONTROL@EXAMPLE.COM ")
1078
+ user.email # => "cruise-control@example.com"
1079
+ user.email_before_type_cast # => "cruise-control@example.com"
1080
+
1081
+ User.where(email: "\tCRUISE-CONTROL@EXAMPLE.COM ").count # => 1
1082
+ User.where(["email = ?", "\tCRUISE-CONTROL@EXAMPLE.COM "]).count # => 0
1083
+
1084
+ User.exists?(email: "\tCRUISE-CONTROL@EXAMPLE.COM ") # => true
1085
+ User.exists?(["email = ?", "\tCRUISE-CONTROL@EXAMPLE.COM "]) # => false
1086
+
1087
+ User.normalize_value_for(:phone, "+1 (555) 867-5309") # => "5558675309"
1088
+ ```
1089
+
1090
+ *Jonathan Hefner*
765
1091
 
766
- Event.create!(name: 'Rock Fest', duration: 2.days)
767
- Event.last.duration # => 2 days
768
- Event.last.duration.iso8601 # => "P2D"
769
- Event.new(duration: 'P1DT12H3S').duration # => 1 day, 12 hours, and 3 seconds
770
- Event.new(duration: '1 day') # Unknown value will be ignored and NULL will be written to database
1092
+ * Hide changes to before_committed! callback behaviour behind flag.
771
1093
 
772
- *Andrey Novikov*
1094
+ In #46525, behavior around before_committed! callbacks was changed so that callbacks
1095
+ would run on every enrolled record in a transaction, not just the first copy of a record.
1096
+ This change in behavior is now controlled by a configuration option,
1097
+ `config.active_record.before_committed_on_all_records`. It will be enabled by default on Rails 7.1.
773
1098
 
774
- * Allow associations supporting the `dependent:` key to take `dependent: :destroy_async`.
1099
+ *Adrianna Chang*
1100
+
1101
+ * The `namespaced_controller` Query Log tag now matches the `controller` format
1102
+
1103
+ For example, a request processed by `NameSpaced::UsersController` will now log as:
1104
+
1105
+ ```
1106
+ :controller # "users"
1107
+ :namespaced_controller # "name_spaced/users"
1108
+ ```
1109
+
1110
+ *Alex Ghiculescu*
1111
+
1112
+ * Return only unique ids from ActiveRecord::Calculations#ids
1113
+
1114
+ Updated ActiveRecord::Calculations#ids to only return the unique ids of the base model
1115
+ when using eager_load, preload and includes.
775
1116
 
776
1117
  ```ruby
777
- class Account < ActiveRecord::Base
778
- belongs_to :supplier, dependent: :destroy_async
779
- end
1118
+ Post.find_by(id: 1).comments.count
1119
+ # => 5
1120
+ Post.includes(:comments).where(id: 1).pluck(:id)
1121
+ # => [1, 1, 1, 1, 1]
1122
+ Post.includes(:comments).where(id: 1).ids
1123
+ # => [1]
780
1124
  ```
781
1125
 
782
- `:destroy_async` will enqueue a job to destroy associated records in the background.
1126
+ *Joshua Young*
783
1127
 
784
- *DHH*, *George Claghorn*, *Cory Gwin*, *Rafael Mendonça França*, *Adrianna Chang*
1128
+ * Stop using `LOWER()` for case-insensitive queries on `citext` columns
785
1129
 
786
- * Add `SKIP_TEST_DATABASE` environment variable to disable modifying the test database when `rails db:create` and `rails db:drop` are called.
1130
+ Previously, `LOWER()` was added for e.g. uniqueness validations with
1131
+ `case_sensitive: false`.
1132
+ It wasn't mentioned in the documentation that the index without `LOWER()`
1133
+ wouldn't be used in this case.
787
1134
 
788
- *Jason Schweier*
1135
+ *Phil Pirozhkov*
789
1136
 
790
- * `connects_to` can only be called on `ActiveRecord::Base` or abstract classes.
1137
+ * Extract `#sync_timezone_changes` method in AbstractMysqlAdapter to enable subclasses
1138
+ to sync database timezone changes without overriding `#raw_execute`.
791
1139
 
792
- Ensure that `connects_to` can only be called from `ActiveRecord::Base` or abstract classes. This protects the application from opening duplicate or too many connections.
1140
+ *Adrianna Chang*, *Paarth Madan*
793
1141
 
794
- *Eileen M. Uchitelle*, *John Crepezzi*
1142
+ * Do not write additional new lines when dumping sql migration versions
795
1143
 
796
- * All connection adapters `execute` now raises `ActiveRecord::ConnectionNotEstablished` rather than
797
- `ActiveRecord::StatementInvalid` when they encounter a connection error.
1144
+ This change updates the `insert_versions_sql` function so that the database insert string containing the current database migration versions does not end with two additional new lines.
798
1145
 
799
- *Jean Boussier*
1146
+ *Misha Schwartz*
800
1147
 
801
- * `Mysql2Adapter#quote_string` now raises `ActiveRecord::ConnectionNotEstablished` rather than
802
- `ActiveRecord::StatementInvalid` when it can't connect to the MySQL server.
1148
+ * Fix `composed_of` value freezing and duplication.
803
1149
 
804
- *Jean Boussier*
1150
+ Previously composite values exhibited two confusing behaviors:
805
1151
 
806
- * Add support for check constraints that are `NOT VALID` via `validate: false` (PostgreSQL-only).
1152
+ - When reading a compositve value it'd _NOT_ be frozen, allowing it to get out of sync with its underlying database
1153
+ columns.
1154
+ - When writing a compositve value the argument would be frozen, potentially confusing the caller.
807
1155
 
808
- *Alex Robbin*
1156
+ Currently, composite values instantiated based on database columns are frozen (addressing the first issue) and
1157
+ assigned compositve values are duplicated and the duplicate is frozen (addressing the second issue).
809
1158
 
810
- * Ensure the default configuration is considered primary or first for an environment
1159
+ *Greg Navis*
811
1160
 
812
- If a multiple database application provides a configuration named primary, that will be treated as default. In applications that do not have a primary entry, the default database configuration will be the first configuration for an environment.
1161
+ * Fix redundant updates to the column insensitivity cache
813
1162
 
814
- *Eileen M. Uchitelle*
1163
+ Fixed redundant queries checking column capability for insensitive
1164
+ comparison.
815
1165
 
816
- * Allow `where` references association names as joined table name aliases.
1166
+ *Phil Pirozhkov*
817
1167
 
818
- ```ruby
819
- class Comment < ActiveRecord::Base
820
- enum label: [:default, :child]
821
- has_many :children, class_name: "Comment", foreign_key: :parent_id
822
- end
1168
+ * Allow disabling methods generated by `ActiveRecord.enum`.
823
1169
 
824
- # ... FROM comments LEFT OUTER JOIN comments children ON ... WHERE children.label = 1
825
- Comment.includes(:children).where("children.label": "child")
826
- ```
1170
+ *Alfred Dominic*
827
1171
 
828
- *Ryuta Kamizono*
1172
+ * Avoid validating `belongs_to` association if it has not changed.
829
1173
 
830
- * Support storing demodulized class name for polymorphic type.
1174
+ Previously, when updating a record, Active Record will perform an extra query to check for the presence of
1175
+ `belongs_to` associations (if the presence is configured to be mandatory), even if that attribute hasn't changed.
831
1176
 
832
- Before Rails 6.1, storing demodulized class name is supported only for STI type
833
- by `store_full_sti_class` class attribute.
1177
+ Currently, only `belongs_to`-related columns are checked for presence. It is possible to have orphaned records with
1178
+ this approach. To avoid this problem, you need to use a foreign key.
834
1179
 
835
- Now `store_full_class_name` class attribute can handle both STI and polymorphic types.
1180
+ This behavior can be controlled by configuration:
836
1181
 
837
- *Ryuta Kamizono*
1182
+ ```ruby
1183
+ config.active_record.belongs_to_required_validates_foreign_key = false
1184
+ ```
838
1185
 
839
- * Deprecate `rails db:structure:{load, dump}` tasks and extend
840
- `rails db:schema:{load, dump}` tasks to work with either `:ruby` or `:sql` format,
841
- depending on `config.active_record.schema_format` configuration value.
1186
+ and will be disabled by default with `config.load_defaults 7.1`.
842
1187
 
843
1188
  *fatkodima*
844
1189
 
845
- * Respect the `select` values for eager loading.
1190
+ * `has_one` and `belongs_to` associations now define a `reset_association` method
1191
+ on the owner model (where `association` is the name of the association). This
1192
+ method unloads the cached associate record, if any, and causes the next access
1193
+ to query it from the database.
846
1194
 
847
- ```ruby
848
- post = Post.select("UPPER(title) AS title").first
849
- post.title # => "WELCOME TO THE WEBLOG"
850
- post.body # => ActiveModel::MissingAttributeError
1195
+ *George Claghorn*
851
1196
 
852
- # Rails 6.0 (ignore the `select` values)
853
- post = Post.select("UPPER(title) AS title").eager_load(:comments).first
854
- post.title # => "Welcome to the weblog"
855
- post.body # => "Such a lovely day"
1197
+ * Allow per attribute setting of YAML permitted classes (safe load) and unsafe load.
856
1198
 
857
- # Rails 6.1 (respect the `select` values)
858
- post = Post.select("UPPER(title) AS title").eager_load(:comments).first
859
- post.title # => "WELCOME TO THE WEBLOG"
860
- post.body # => ActiveModel::MissingAttributeError
861
- ```
1199
+ *Carlos Palhares*
862
1200
 
863
- *Ryuta Kamizono*
1201
+ * Add a build persistence method
1202
+
1203
+ Provides a wrapper for `new`, to provide feature parity with `create`s
1204
+ ability to create multiple records from an array of hashes, using the
1205
+ same notation as the `build` method on associations.
1206
+
1207
+ *Sean Denny*
864
1208
 
865
- * Allow attribute's default to be configured but keeping its own type.
1209
+ * Raise on assignment to readonly attributes
866
1210
 
867
1211
  ```ruby
868
1212
  class Post < ActiveRecord::Base
869
- attribute :written_at, default: -> { Time.now.utc }
1213
+ attr_readonly :content
870
1214
  end
871
-
872
- # Rails 6.0
873
- Post.type_for_attribute(:written_at) # => #<Type::Value ... precision: nil, ...>
874
-
875
- # Rails 6.1
876
- Post.type_for_attribute(:written_at) # => #<Type::DateTime ... precision: 6, ...>
1215
+ Post.create!(content: "cannot be updated")
1216
+ post.content # "cannot be updated"
1217
+ post.content = "something else" # => ActiveRecord::ReadonlyAttributeError
877
1218
  ```
878
1219
 
879
- *Ryuta Kamizono*
1220
+ Previously, assignment would succeed but silently not write to the database.
880
1221
 
881
- * Allow default to be configured for Enum.
1222
+ This behavior can be controlled by configuration:
882
1223
 
883
1224
  ```ruby
884
- class Book < ActiveRecord::Base
885
- enum status: [:proposed, :written, :published], _default: :published
886
- end
887
-
888
- Book.new.status # => "published"
1225
+ config.active_record.raise_on_assign_to_attr_readonly = true
889
1226
  ```
890
1227
 
891
- *Ryuta Kamizono*
1228
+ and will be enabled by default with `config.load_defaults 7.1`.
892
1229
 
893
- * Deprecate YAML loading from legacy format older than Rails 5.0.
1230
+ *Alex Ghiculescu*, *Hartley McGuire*
894
1231
 
895
- *Ryuta Kamizono*
1232
+ * Allow unscoping of preload and eager_load associations
896
1233
 
897
- * Added the setting `ActiveRecord::Base.immutable_strings_by_default`, which
898
- allows you to specify that all string columns should be frozen unless
899
- otherwise specified. This will reduce memory pressure for applications which
900
- do not generally mutate string properties of Active Record objects.
1234
+ Added the ability to unscope preload and eager_load associations just like
1235
+ includes, joins, etc. See ActiveRecord::QueryMethods::VALID_UNSCOPING_VALUES
1236
+ for the full list of supported unscopable scopes.
901
1237
 
902
- *Sean Griffin*, *Ryuta Kamizono*
1238
+ ```ruby
1239
+ query.unscope(:eager_load, :preload).group(:id).select(:id)
1240
+ ```
903
1241
 
904
- * Deprecate `map!` and `collect!` on `ActiveRecord::Result`.
1242
+ *David Morehouse*
905
1243
 
906
- *Ryuta Kamizono*
1244
+ * Add automatic filtering of encrypted attributes on inspect
907
1245
 
908
- * Support `relation.and` for intersection as Set theory.
1246
+ This feature is enabled by default but can be disabled with
909
1247
 
910
1248
  ```ruby
911
- david_and_mary = Author.where(id: [david, mary])
912
- mary_and_bob = Author.where(id: [mary, bob])
913
-
914
- david_and_mary.merge(mary_and_bob) # => [mary, bob]
915
-
916
- david_and_mary.and(mary_and_bob) # => [mary]
917
- david_and_mary.or(mary_and_bob) # => [david, mary, bob]
1249
+ config.active_record.encryption.add_to_filter_parameters = false
918
1250
  ```
919
1251
 
920
- *Ryuta Kamizono*
921
-
922
- * Merging conditions on the same column no longer maintain both conditions,
923
- and will be consistently replaced by the latter condition in Rails 7.0.
924
- To migrate to Rails 7.0's behavior, use `relation.merge(other, rewhere: true)`.
925
-
926
- ```ruby
927
- # Rails 6.1 (IN clause is replaced by merger side equality condition)
928
- Author.where(id: [david.id, mary.id]).merge(Author.where(id: bob)) # => [bob]
1252
+ *Hartley McGuire*
929
1253
 
930
- # Rails 6.1 (both conflict conditions exists, deprecated)
931
- Author.where(id: david.id..mary.id).merge(Author.where(id: bob)) # => []
1254
+ * Clear locking column on #dup
932
1255
 
933
- # Rails 6.1 with rewhere to migrate to Rails 7.0's behavior
934
- Author.where(id: david.id..mary.id).merge(Author.where(id: bob), rewhere: true) # => [bob]
1256
+ This change fixes not to duplicate locking_column like id and timestamps.
935
1257
 
936
- # Rails 7.0 (same behavior with IN clause, mergee side condition is consistently replaced)
937
- Author.where(id: [david.id, mary.id]).merge(Author.where(id: bob)) # => [bob]
938
- Author.where(id: david.id..mary.id).merge(Author.where(id: bob)) # => [bob]
1258
+ ```
1259
+ car = Car.create!
1260
+ car.touch
1261
+ car.lock_version #=> 1
1262
+ car.dup.lock_version #=> 0
939
1263
  ```
940
1264
 
941
- *Ryuta Kamizono*
1265
+ *Shouichi Kamiya*, *Seonggi Yang*, *Ryohei UEDA*
942
1266
 
943
- * Do not mark Postgresql MAC address and UUID attributes as changed when the assigned value only varies by case.
1267
+ * Invalidate transaction as early as possible
944
1268
 
945
- *Peter Fry*
1269
+ After rescuing a `TransactionRollbackError` exception Rails invalidates transactions earlier in the flow
1270
+ allowing the framework to skip issuing the `ROLLBACK` statement in more cases.
1271
+ Only affects adapters that have `savepoint_errors_invalidate_transactions?` configured as `true`,
1272
+ which at this point is only applicable to the `mysql2` adapter.
946
1273
 
947
- * Resolve issue with insert_all unique_by option when used with expression index.
1274
+ *Nikita Vasilevsky*
948
1275
 
949
- When the `:unique_by` option of `ActiveRecord::Persistence.insert_all` and
950
- `ActiveRecord::Persistence.upsert_all` was used with the name of an expression index, an error
951
- was raised. Adding a guard around the formatting behavior for the `:unique_by` corrects this.
1276
+ * Allow configuring columns list to be used in SQL queries issued by an `ActiveRecord::Base` object
952
1277
 
953
- Usage:
1278
+ It is now possible to configure columns list that will be used to build an SQL query clauses when
1279
+ updating, deleting or reloading an `ActiveRecord::Base` object
954
1280
 
955
1281
  ```ruby
956
- create_table :books, id: :integer, force: true do |t|
957
- t.column :name, :string
958
- t.index "lower(name)", unique: true
1282
+ class Developer < ActiveRecord::Base
1283
+ query_constraints :company_id, :id
959
1284
  end
960
-
961
- Book.insert_all [{ name: "MyTest" }], unique_by: :index_books_on_lower_name
1285
+ developer = Developer.first.update(name: "Bob")
1286
+ # => UPDATE "developers" SET "name" = 'Bob' WHERE "developers"."company_id" = 1 AND "developers"."id" = 1
962
1287
  ```
963
1288
 
964
- Fixes #39516.
1289
+ *Nikita Vasilevsky*
965
1290
 
966
- *Austen Madden*
1291
+ * Adds `validate` to foreign keys and check constraints in schema.rb
967
1292
 
968
- * Add basic support for CHECK constraints to database migrations.
1293
+ Previously, `schema.rb` would not record if `validate: false` had been used when adding a foreign key or check
1294
+ constraint, so restoring a database from the schema could result in foreign keys or check constraints being
1295
+ incorrectly validated.
969
1296
 
970
- Usage:
1297
+ *Tommy Graves*
971
1298
 
972
- ```ruby
973
- add_check_constraint :products, "price > 0", name: "price_check"
974
- remove_check_constraint :products, name: "price_check"
975
- ```
1299
+ * Adapter `#execute` methods now accept an `allow_retry` option. When set to `true`, the SQL statement will be
1300
+ retried, up to the database's configured `connection_retries` value, upon encountering connection-related errors.
976
1301
 
977
- *fatkodima*
1302
+ *Adrianna Chang*
978
1303
 
979
- * Add `ActiveRecord::Base.strict_loading_by_default` and `ActiveRecord::Base.strict_loading_by_default=`
980
- to enable/disable strict_loading mode by default for a model. The configuration's value is
981
- inheritable by subclasses, but they can override that value and it will not impact parent class.
1304
+ * Only trigger `after_commit :destroy` callbacks when a database row is deleted.
982
1305
 
983
- Usage:
1306
+ This prevents `after_commit :destroy` callbacks from being triggered again
1307
+ when `destroy` is called multiple times on the same record.
984
1308
 
985
- ```ruby
986
- class Developer < ApplicationRecord
987
- self.strict_loading_by_default = true
1309
+ *Ben Sheldon*
988
1310
 
989
- has_many :projects
990
- end
1311
+ * Fix `ciphertext_for` for yet-to-be-encrypted values.
991
1312
 
992
- dev = Developer.first
993
- dev.projects.first
994
- # => ActiveRecord::StrictLoadingViolationError Exception: Developer is marked as strict_loading and Project cannot be lazily loaded.
995
- ```
1313
+ Previously, `ciphertext_for` returned the cleartext of values that had not
1314
+ yet been encrypted, such as with an unpersisted record:
996
1315
 
997
- *bogdanvlviv*
1316
+ ```ruby
1317
+ Post.encrypts :body
998
1318
 
999
- * Deprecate passing an Active Record object to `quote`/`type_cast` directly.
1319
+ post = Post.create!(body: "Hello")
1320
+ post.ciphertext_for(:body)
1321
+ # => "{\"p\":\"abc..."
1000
1322
 
1001
- *Ryuta Kamizono*
1323
+ post.body = "World"
1324
+ post.ciphertext_for(:body)
1325
+ # => "World"
1326
+ ```
1002
1327
 
1003
- * Default engine `ENGINE=InnoDB` is no longer dumped to make schema more agnostic.
1328
+ Now, `ciphertext_for` will always return the ciphertext of encrypted
1329
+ attributes:
1004
1330
 
1005
- Before:
1331
+ ```ruby
1332
+ Post.encrypts :body
1006
1333
 
1007
- ```ruby
1008
- create_table "accounts", options: "ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci", force: :cascade do |t|
1009
- end
1010
- ```
1334
+ post = Post.create!(body: "Hello")
1335
+ post.ciphertext_for(:body)
1336
+ # => "{\"p\":\"abc..."
1011
1337
 
1012
- After:
1338
+ post.body = "World"
1339
+ post.ciphertext_for(:body)
1340
+ # => "{\"p\":\"xyz..."
1341
+ ```
1013
1342
 
1014
- ```ruby
1015
- create_table "accounts", charset: "utf8mb4", collation: "utf8mb4_0900_ai_ci", force: :cascade do |t|
1016
- end
1017
- ```
1343
+ *Jonathan Hefner*
1018
1344
 
1019
- *Ryuta Kamizono*
1345
+ * Fix a bug where using groups and counts with long table names would return incorrect results.
1020
1346
 
1021
- * Added delegated type as an alternative to single-table inheritance for representing class hierarchies.
1022
- See ActiveRecord::DelegatedType for the full description.
1347
+ *Shota Toguchi*, *Yusaku Ono*
1023
1348
 
1024
- *DHH*
1349
+ * Fix encryption of column default values.
1025
1350
 
1026
- * Deprecate aggregations with group by duplicated fields.
1351
+ Previously, encrypted attributes that used column default values appeared to
1352
+ be encrypted on create, but were not:
1027
1353
 
1028
- To migrate to Rails 7.0's behavior, use `uniq!(:group)` to deduplicate group fields.
1354
+ ```ruby
1355
+ Book.encrypts :name
1029
1356
 
1030
- ```ruby
1031
- accounts = Account.group(:firm_id)
1357
+ book = Book.create!
1358
+ book.name
1359
+ # => "<untitled>"
1360
+ book.name_before_type_cast
1361
+ # => "{\"p\":\"abc..."
1362
+ book.reload.name_before_type_cast
1363
+ # => "<untitled>"
1364
+ ```
1032
1365
 
1033
- # duplicated group fields, deprecated.
1034
- accounts.merge(accounts.where.not(credit_limit: nil)).sum(:credit_limit)
1035
- # => {
1036
- # [1, 1] => 50,
1037
- # [2, 2] => 60
1038
- # }
1366
+ Now, attributes with column default values are encrypted:
1039
1367
 
1040
- # use `uniq!(:group)` to deduplicate group fields.
1041
- accounts.merge(accounts.where.not(credit_limit: nil)).uniq!(:group).sum(:credit_limit)
1042
- # => {
1043
- # 1 => 50,
1044
- # 2 => 60
1045
- # }
1046
- ```
1368
+ ```ruby
1369
+ Book.encrypts :name
1047
1370
 
1048
- *Ryuta Kamizono*
1371
+ book = Book.create!
1372
+ book.name
1373
+ # => "<untitled>"
1374
+ book.name_before_type_cast
1375
+ # => "{\"p\":\"abc..."
1376
+ book.reload.name_before_type_cast
1377
+ # => "{\"p\":\"abc..."
1378
+ ```
1049
1379
 
1050
- * Deprecate duplicated query annotations.
1380
+ *Jonathan Hefner*
1051
1381
 
1052
- To migrate to Rails 7.0's behavior, use `uniq!(:annotate)` to deduplicate query annotations.
1382
+ * Deprecate delegation from `Base` to `connection_handler`.
1053
1383
 
1054
- ```ruby
1055
- accounts = Account.where(id: [1, 2]).annotate("david and mary")
1384
+ Calling `Base.clear_all_connections!`, `Base.clear_active_connections!`, `Base.clear_reloadable_connections!` and `Base.flush_idle_connections!` is deprecated. Please call these methods on the connection handler directly. In future Rails versions, the delegation from `Base` to the `connection_handler` will be removed.
1056
1385
 
1057
- # duplicated annotations, deprecated.
1058
- accounts.merge(accounts.rewhere(id: 3))
1059
- # SELECT accounts.* FROM accounts WHERE accounts.id = 3 /* david and mary */ /* david and mary */
1386
+ *Eileen M. Uchitelle*
1060
1387
 
1061
- # use `uniq!(:annotate)` to deduplicate annotations.
1062
- accounts.merge(accounts.rewhere(id: 3)).uniq!(:annotate)
1063
- # SELECT accounts.* FROM accounts WHERE accounts.id = 3 /* david and mary */
1064
- ```
1388
+ * Allow ActiveRecord::QueryMethods#reselect to receive hash values, similar to ActiveRecord::QueryMethods#select
1065
1389
 
1066
- *Ryuta Kamizono*
1390
+ *Sampat Badhe*
1067
1391
 
1068
- * Resolve conflict between counter cache and optimistic locking.
1392
+ * Validate options when managing columns and tables in migrations.
1069
1393
 
1070
- Bump an Active Record instance's lock version after updating its counter
1071
- cache. This avoids raising an unnecessary `ActiveRecord::StaleObjectError`
1072
- upon subsequent transactions by maintaining parity with the corresponding
1073
- database record's `lock_version` column.
1394
+ If an invalid option is passed to a migration method like `create_table` and `add_column`, an error will be raised
1395
+ instead of the option being silently ignored. Validation of the options will only be applied for new migrations
1396
+ that are created.
1074
1397
 
1075
- Fixes #16449.
1398
+ *Guo Xiang Tan*, *George Wambold*
1076
1399
 
1077
- *Aaron Lipman*
1400
+ * Update query log tags to use the [SQLCommenter](https://open-telemetry.github.io/opentelemetry-sqlcommenter/) format by default. See [#46179](https://github.com/rails/rails/issues/46179)
1078
1401
 
1079
- * Support merging option `:rewhere` to allow mergee side condition to be replaced exactly.
1402
+ To opt out of SQLCommenter-formatted query log tags, set `config.active_record.query_log_tags_format = :legacy`. By default, this is set to `:sqlcommenter`.
1080
1403
 
1081
- ```ruby
1082
- david_and_mary = Author.where(id: david.id..mary.id)
1404
+ *Modulitos* and *Iheanyi*
1083
1405
 
1084
- # both conflict conditions exists
1085
- david_and_mary.merge(Author.where(id: bob)) # => []
1406
+ * Allow any ERB in the database.yml when creating rake tasks.
1086
1407
 
1087
- # mergee side condition is replaced by rewhere
1088
- david_and_mary.merge(Author.rewhere(id: bob)) # => [bob]
1408
+ Any ERB can be used in `database.yml` even if it accesses environment
1409
+ configurations.
1089
1410
 
1090
- # mergee side condition is replaced by rewhere option
1091
- david_and_mary.merge(Author.where(id: bob), rewhere: true) # => [bob]
1092
- ```
1411
+ Deprecates `config.active_record.suppress_multiple_database_warning`.
1093
1412
 
1094
- *Ryuta Kamizono*
1413
+ *Eike Send*
1095
1414
 
1096
- * Add support for finding records based on signed ids, which are tamper-proof, verified ids that can be
1097
- set to expire and scoped with a purpose. This is particularly useful for things like password reset
1098
- or email verification, where you want the bearer of the signed id to be able to interact with the
1099
- underlying record, but usually only within a certain time period.
1415
+ * Add table to error for duplicate column definitions.
1100
1416
 
1101
- ```ruby
1102
- signed_id = User.first.signed_id expires_in: 15.minutes, purpose: :password_reset
1417
+ If a migration defines duplicate columns for a table, the error message
1418
+ shows which table it concerns.
1103
1419
 
1104
- User.find_signed signed_id # => nil, since the purpose does not match
1420
+ *Petrik de Heus*
1105
1421
 
1106
- travel 16.minutes
1107
- User.find_signed signed_id, purpose: :password_reset # => nil, since the signed id has expired
1422
+ * Fix erroneous nil default precision on virtual datetime columns.
1108
1423
 
1109
- travel_back
1110
- User.find_signed signed_id, purpose: :password_reset # => User.first
1424
+ Prior to this change, virtual datetime columns did not have the same
1425
+ default precision as regular datetime columns, resulting in the following
1426
+ being erroneously equivalent:
1111
1427
 
1112
- User.find_signed! "bad data" # => ActiveSupport::MessageVerifier::InvalidSignature
1113
- ```
1428
+ t.virtual :name, type: datetime, as: "expression"
1429
+ t.virtual :name, type: datetime, precision: nil, as: "expression"
1114
1430
 
1115
- *DHH*
1431
+ This change fixes the default precision lookup, so virtual and regular
1432
+ datetime column default precisions match.
1116
1433
 
1117
- * Support `ALGORITHM = INSTANT` DDL option for index operations on MySQL.
1434
+ *Sam Bostock*
1118
1435
 
1119
- *Ryuta Kamizono*
1436
+ * Use connection from `#with_raw_connection` in `#quote_string`.
1120
1437
 
1121
- * Fix index creation to preserve index comment in bulk change table on MySQL.
1438
+ This ensures that the string quoting is wrapped in the reconnect and retry logic
1439
+ that `#with_raw_connection` offers.
1122
1440
 
1123
- *Ryuta Kamizono*
1441
+ *Adrianna Chang*
1124
1442
 
1125
- * Allow `unscope` to be aware of table name qualified values.
1443
+ * Add `expires_at` option to `signed_id`.
1126
1444
 
1127
- It is possible to unscope only the column in the specified table.
1445
+ *Shouichi Kamiya*
1128
1446
 
1129
- ```ruby
1130
- posts = Post.joins(:comments).group(:"posts.hidden")
1131
- posts = posts.where("posts.hidden": false, "comments.hidden": false)
1447
+ * Allow applications to set retry deadline for query retries.
1132
1448
 
1133
- posts.count
1134
- # => { false => 10 }
1449
+ Building on the work done in #44576 and #44591, we extend the logic that automatically
1450
+ reconnects database connections to take into account a timeout limit. We won't retry
1451
+ a query if a given amount of time has elapsed since the query was first attempted. This
1452
+ value defaults to nil, meaning that all retryable queries are retried regardless of time elapsed,
1453
+ but this can be changed via the `retry_deadline` option in the database config.
1135
1454
 
1136
- # unscope both hidden columns
1137
- posts.unscope(where: :hidden).count
1138
- # => { false => 11, true => 1 }
1455
+ *Adrianna Chang*
1139
1456
 
1140
- # unscope only comments.hidden column
1141
- posts.unscope(where: :"comments.hidden").count
1142
- # => { false => 11 }
1143
- ```
1457
+ * Fix a case where the query cache can return wrong values. See #46044
1144
1458
 
1145
- *Ryuta Kamizono*, *Slava Korolev*
1459
+ *Aaron Patterson*
1146
1460
 
1147
- * Fix `rewhere` to truly overwrite collided where clause by new where clause.
1461
+ * Support MySQL's ssl-mode option for MySQLDatabaseTasks.
1148
1462
 
1149
- ```ruby
1150
- steve = Person.find_by(name: "Steve")
1151
- david = Author.find_by(name: "David")
1463
+ Verifying the identity of the database server requires setting the ssl-mode
1464
+ option to VERIFY_CA or VERIFY_IDENTITY. This option was previously ignored
1465
+ for MySQL database tasks like creating a database and dumping the structure.
1152
1466
 
1153
- relation = Essay.where(writer: steve)
1467
+ *Petrik de Heus*
1154
1468
 
1155
- # Before
1156
- relation.rewhere(writer: david).to_a # => []
1469
+ * Move `ActiveRecord::InternalMetadata` to an independent object.
1157
1470
 
1158
- # After
1159
- relation.rewhere(writer: david).to_a # => [david]
1160
- ```
1471
+ `ActiveRecord::InternalMetadata` no longer inherits from `ActiveRecord::Base` and is now an independent object that should be instantiated with a `connection`. This class is private and should not be used by applications directly. If you want to interact with the schema migrations table, please access it on the connection directly, for example: `ActiveRecord::Base.connection.schema_migration`.
1161
1472
 
1162
- *Ryuta Kamizono*
1473
+ *Eileen M. Uchitelle*
1163
1474
 
1164
- * Inspect time attributes with subsec and time zone offset.
1475
+ * Deprecate quoting `ActiveSupport::Duration` as an integer
1165
1476
 
1166
- ```ruby
1167
- p Knot.create
1168
- => #<Knot id: 1, created_at: "2016-05-05 01:29:47.116928000 +0000">
1477
+ Using ActiveSupport::Duration as an interpolated bind parameter in a SQL
1478
+ string template is deprecated. To avoid this warning, you should explicitly
1479
+ convert the duration to a more specific database type. For example, if you
1480
+ want to use a duration as an integer number of seconds:
1481
+ ```
1482
+ Record.where("duration = ?", 1.hour.to_i)
1483
+ ```
1484
+ If you want to use a duration as an ISO 8601 string:
1485
+ ```
1486
+ Record.where("duration = ?", 1.hour.iso8601)
1169
1487
  ```
1170
1488
 
1171
- *akinomaeni*, *Jonathan Hefner*
1489
+ *Aram Greenman*
1172
1490
 
1173
- * Deprecate passing a column to `type_cast`.
1491
+ * Allow `QueryMethods#in_order_of` to order by a string column name.
1174
1492
 
1175
- *Ryuta Kamizono*
1493
+ ```ruby
1494
+ Post.in_order_of("id", [4,2,3,1]).to_a
1495
+ Post.joins(:author).in_order_of("authors.name", ["Bob", "Anna", "John"]).to_a
1496
+ ```
1176
1497
 
1177
- * Deprecate `in_clause_length` and `allowed_index_name_length` in `DatabaseLimits`.
1498
+ *Igor Kasyanchuk*
1178
1499
 
1179
- *Ryuta Kamizono*
1500
+ * Move `ActiveRecord::SchemaMigration` to an independent object.
1180
1501
 
1181
- * Support bulk insert/upsert on relation to preserve scope values.
1502
+ `ActiveRecord::SchemaMigration` no longer inherits from `ActiveRecord::Base` and is now an independent object that should be instantiated with a `connection`. This class is private and should not be used by applications directly. If you want to interact with the schema migrations table, please access it on the connection directly, for example: `ActiveRecord::Base.connection.schema_migration`.
1182
1503
 
1183
- *Josef Šimánek*, *Ryuta Kamizono*
1504
+ *Eileen M. Uchitelle*
1505
+
1506
+ * Deprecate `all_connection_pools` and make `connection_pool_list` more explicit.
1184
1507
 
1185
- * Preserve column comment value on changing column name on MySQL.
1508
+ Following on #45924 `all_connection_pools` is now deprecated. `connection_pool_list` will either take an explicit role or applications can opt into the new behavior by passing `:all`.
1186
1509
 
1187
- *Islam Taha*
1510
+ *Eileen M. Uchitelle*
1188
1511
 
1189
- * Add support for `if_exists` option for removing an index.
1512
+ * Fix connection handler methods to operate on all pools.
1190
1513
 
1191
- The `remove_index` method can take an `if_exists` option. If this is set to true an error won't be raised if the index doesn't exist.
1514
+ `active_connections?`, `clear_active_connections!`, `clear_reloadable_connections!`, `clear_all_connections!`, and `flush_idle_connections!` now operate on all pools by default. Previously they would default to using the `current_role` or `:writing` role unless specified.
1192
1515
 
1193
1516
  *Eileen M. Uchitelle*
1194
1517
 
1195
- * Remove ibm_db, informix, mssql, oracle, and oracle12 Arel visitors which are not used in the code base.
1196
1518
 
1197
- *Ryuta Kamizono*
1519
+ * Allow ActiveRecord::QueryMethods#select to receive hash values.
1198
1520
 
1199
- * Prevent `build_association` from `touching` a parent record if the record isn't persisted for `has_one` associations.
1521
+ Currently, `select` might receive only raw sql and symbols to define columns and aliases to select.
1200
1522
 
1201
- Fixes #38219.
1523
+ With this change we can provide `hash` as argument, for example:
1202
1524
 
1203
- *Josh Brody*
1525
+ ```ruby
1526
+ Post.joins(:comments).select(posts: [:id, :title, :created_at], comments: [:id, :body, :author_id])
1527
+ #=> "SELECT \"posts\".\"id\", \"posts\".\"title\", \"posts\".\"created_at\", \"comments\".\"id\", \"comments\".\"body\", \"comments\".\"author_id\"
1528
+ # FROM \"posts\" INNER JOIN \"comments\" ON \"comments\".\"post_id\" = \"posts\".\"id\""
1204
1529
 
1205
- * Add support for `if_not_exists` option for adding index.
1530
+ Post.joins(:comments).select(posts: { id: :post_id, title: :post_title }, comments: { id: :comment_id, body: :comment_body })
1531
+ #=> "SELECT posts.id as post_id, posts.title as post_title, comments.id as comment_id, comments.body as comment_body
1532
+ # FROM \"posts\" INNER JOIN \"comments\" ON \"comments\".\"post_id\" = \"posts\".\"id\""
1533
+ ```
1534
+ *Oleksandr Holubenko*, *Josef Šimánek*, *Jean Boussier*
1206
1535
 
1207
- The `add_index` method respects `if_not_exists` option. If it is set to true
1208
- index won't be added.
1536
+ * Adapts virtual attributes on `ActiveRecord::Persistence#becomes`.
1209
1537
 
1210
- Usage:
1538
+ When source and target classes have a different set of attributes adapts
1539
+ attributes such that the extra attributes from target are added.
1211
1540
 
1212
1541
  ```ruby
1213
- add_index :users, :account_id, if_not_exists: true
1214
- ```
1542
+ class Person < ApplicationRecord
1543
+ end
1215
1544
 
1216
- The `if_not_exists` option passed to `create_table` also gets propagated to indexes
1217
- created within that migration so that if table and its indexes exist then there is no
1218
- attempt to create them again.
1545
+ class WebUser < Person
1546
+ attribute :is_admin, :boolean
1547
+ after_initialize :set_admin
1219
1548
 
1220
- *Prathamesh Sonpatki*
1549
+ def set_admin
1550
+ write_attribute(:is_admin, email =~ /@ourcompany\.com$/)
1551
+ end
1552
+ end
1221
1553
 
1222
- * Add `ActiveRecord::Base#previously_new_record?` to show if a record was new before the last save.
1554
+ person = Person.find_by(email: "email@ourcompany.com")
1555
+ person.respond_to? :is_admin
1556
+ # => false
1557
+ person.becomes(WebUser).is_admin?
1558
+ # => true
1559
+ ```
1223
1560
 
1224
- *Tom Ward*
1561
+ *Jacopo Beschi*, *Sampson Crowley*
1225
1562
 
1226
- * Support descending order for `find_each`, `find_in_batches`, and `in_batches`.
1563
+ * Fix `ActiveRecord::QueryMethods#in_order_of` to include `nil`s, to match the
1564
+ behavior of `Enumerable#in_order_of`.
1227
1565
 
1228
- Batch processing methods allow you to work with the records in batches, greatly reducing memory consumption, but records are always batched from oldest id to newest.
1566
+ For example, `Post.in_order_of(:title, [nil, "foo"])` will now include posts
1567
+ with `nil` titles, the same as `Post.all.to_a.in_order_of(:title, [nil, "foo"])`.
1229
1568
 
1230
- This change allows reversing the order, batching from newest to oldest. This is useful when you need to process newer batches of records first.
1569
+ *fatkodima*
1231
1570
 
1232
- Pass `order: :desc` to yield batches in descending order. The default remains `order: :asc`.
1571
+ * Optimize `add_timestamps` to use a single SQL statement.
1233
1572
 
1234
1573
  ```ruby
1235
- Person.find_each(order: :desc) do |person|
1236
- person.party_all_night!
1237
- end
1574
+ add_timestamps :my_table
1238
1575
  ```
1239
1576
 
1240
- *Alexey Vasiliev*
1241
-
1242
- * Fix `insert_all` with enum values.
1577
+ Now results in the following SQL:
1243
1578
 
1244
- Fixes #38716.
1245
-
1246
- *Joel Blum*
1579
+ ```sql
1580
+ ALTER TABLE "my_table" ADD COLUMN "created_at" datetime(6) NOT NULL, ADD COLUMN "updated_at" datetime(6) NOT NULL
1581
+ ```
1247
1582
 
1248
- * Add support for `db:rollback:name` for multiple database applications.
1583
+ *Iliana Hadzhiatanasova*
1249
1584
 
1250
- Multiple database applications will now raise if `db:rollback` is call and recommend using the `db:rollback:[NAME]` to rollback migrations.
1585
+ * Add `drop_enum` migration command for PostgreSQL
1251
1586
 
1252
- *Eileen M. Uchitelle*
1587
+ This does the inverse of `create_enum`. Before dropping an enum, ensure you have
1588
+ dropped columns that depend on it.
1253
1589
 
1254
- * `Relation#pick` now uses already loaded results instead of making another query.
1590
+ *Alex Ghiculescu*
1255
1591
 
1256
- *Eugene Kenny*
1592
+ * Adds support for `if_exists` option when removing a check constraint.
1257
1593
 
1258
- * Deprecate using `return`, `break` or `throw` to exit a transaction block after writes.
1594
+ The `remove_check_constraint` method now accepts an `if_exists` option. If set
1595
+ to true an error won't be raised if the check constraint doesn't exist.
1259
1596
 
1260
- *Dylan Thacker-Smith*
1597
+ *Margaret Parsa* and *Aditya Bhutani*
1261
1598
 
1262
- * Dump the schema or structure of a database when calling `db:migrate:name`.
1599
+ * `find_or_create_by` now try to find a second time if it hits a unicity constraint.
1263
1600
 
1264
- In previous versions of Rails, `rails db:migrate` would dump the schema of the database. In Rails 6, that holds true (`rails db:migrate` dumps all databases' schemas), but `rails db:migrate:name` does not share that behavior.
1601
+ `find_or_create_by` always has been inherently racy, either creating multiple
1602
+ duplicate records or failing with `ActiveRecord::RecordNotUnique` depending on
1603
+ whether a proper unicity constraint was set.
1265
1604
 
1266
- Going forward, calls to `rails db:migrate:name` will dump the schema (or structure) of the database being migrated.
1605
+ `create_or_find_by` was introduced for this use case, however it's quite wasteful
1606
+ when the record is expected to exist most of the time, as INSERT require to send
1607
+ more data than SELECT and require more work from the database. Also on some
1608
+ databases it can actually consume a primary key increment which is undesirable.
1267
1609
 
1268
- *Kyle Thompson*
1610
+ So for case where most of the time the record is expected to exist, `find_or_create_by`
1611
+ can be made race-condition free by re-trying the `find` if the `create` failed
1612
+ with `ActiveRecord::RecordNotUnique`. This assumes that the table has the proper
1613
+ unicity constraints, if not, `find_or_create_by` will still lead to duplicated records.
1269
1614
 
1270
- * Reset the `ActiveRecord::Base` connection after `rails db:migrate:name`.
1615
+ *Jean Boussier*, *Alex Kitchens*
1271
1616
 
1272
- When `rails db:migrate` has finished, it ensures the `ActiveRecord::Base` connection is reset to its original configuration. Going forward, `rails db:migrate:name` will have the same behavior.
1617
+ * Introduce a simpler constructor API for ActiveRecord database adapters.
1273
1618
 
1274
- *Kyle Thompson*
1619
+ Previously the adapter had to know how to build a new raw connection to
1620
+ support reconnect, but also expected to be passed an initial already-
1621
+ established connection.
1275
1622
 
1276
- * Disallow calling `connected_to` on subclasses of `ActiveRecord::Base`.
1623
+ When manually creating an adapter instance, it will now accept a single
1624
+ config hash, and only establish the real connection on demand.
1277
1625
 
1278
- Behavior has not changed here but the previous API could be misleading to people who thought it would switch connections for only that class. `connected_to` switches the context from which we are getting connections, not the connections themselves.
1626
+ *Matthew Draper*
1279
1627
 
1280
- *Eileen M. Uchitelle*, *John Crepezzi*
1628
+ * Avoid redundant `SELECT 1` connection-validation query during DB pool
1629
+ checkout when possible.
1281
1630
 
1282
- * Add support for horizontal sharding to `connects_to` and `connected_to`.
1631
+ If the first query run during a request is known to be idempotent, it can be
1632
+ used directly to validate the connection, saving a network round-trip.
1283
1633
 
1284
- Applications can now connect to multiple shards and switch between their shards in an application. Note that the shard swapping is still a manual process as this change does not include an API for automatic shard swapping.
1634
+ *Matthew Draper*
1285
1635
 
1286
- Usage:
1636
+ * Automatically reconnect broken database connections when safe, even
1637
+ mid-request.
1287
1638
 
1288
- Given the following configuration:
1639
+ When an error occurs while attempting to run a known-idempotent query, and
1640
+ not inside a transaction, it is safe to immediately reconnect to the
1641
+ database server and try again, so this is now the default behavior.
1289
1642
 
1290
- ```yaml
1291
- # config/database.yml
1292
- production:
1293
- primary:
1294
- database: my_database
1295
- primary_shard_one:
1296
- database: my_database_shard_one
1297
- ```
1643
+ This new default should always be safe -- to support that, it's consciously
1644
+ conservative about which queries are considered idempotent -- but if
1645
+ necessary it can be disabled by setting the `connection_retries` connection
1646
+ option to `0`.
1298
1647
 
1299
- Connect to multiple shards:
1648
+ *Matthew Draper*
1300
1649
 
1301
- ```ruby
1302
- class ApplicationRecord < ActiveRecord::Base
1303
- self.abstract_class = true
1650
+ * Avoid removing a PostgreSQL extension when there are dependent objects.
1304
1651
 
1305
- connects_to shards: {
1306
- default: { writing: :primary },
1307
- shard_one: { writing: :primary_shard_one }
1308
- }
1309
- ```
1652
+ Previously, removing an extension also implicitly removed dependent objects. Now, this will raise an error.
1310
1653
 
1311
- Swap between shards in your controller / model code:
1654
+ You can force removing the extension:
1312
1655
 
1313
1656
  ```ruby
1314
- ActiveRecord::Base.connected_to(shard: :shard_one) do
1315
- # Read from shard one
1316
- end
1657
+ disable_extension :citext, force: :cascade
1317
1658
  ```
1318
1659
 
1319
- The horizontal sharding API also supports read replicas. See guides for more details.
1660
+ Fixes #29091.
1320
1661
 
1321
- *Eileen M. Uchitelle*, *John Crepezzi*
1662
+ *fatkodima*
1322
1663
 
1323
- * Deprecate `spec_name` in favor of `name` on database configurations.
1664
+ * Allow nested functions as safe SQL string
1324
1665
 
1325
- The accessors for `spec_name` on `configs_for` and `DatabaseConfig` are deprecated. Please use `name` instead.
1666
+ *Michael Siegfried*
1326
1667
 
1327
- Deprecated behavior:
1668
+ * Allow `destroy_association_async_job=` to be configured with a class string instead of a constant.
1328
1669
 
1329
- ```ruby
1330
- db_config = ActiveRecord::Base.configurations.configs_for(env_name: "development", spec_name: "primary")
1331
- db_config.spec_name
1332
- ```
1670
+ Defers an autoloading dependency between `ActiveRecord::Base` and `ActiveJob::Base`
1671
+ and moves the configuration of `ActiveRecord::DestroyAssociationAsyncJob`
1672
+ from ActiveJob to ActiveRecord.
1333
1673
 
1334
- New behavior:
1674
+ Deprecates `ActiveRecord::ActiveJobRequiredError` and now raises a `NameError`
1675
+ if the job class is unloadable or an `ActiveRecord::ConfigurationError` if
1676
+ `dependent: :destroy_async` is declared on an association but there is no job
1677
+ class configured.
1335
1678
 
1336
- ```ruby
1337
- db_config = ActiveRecord::Base.configurations.configs_for(env_name: "development", name: "primary")
1338
- db_config.name
1339
- ```
1679
+ *Ben Sheldon*
1340
1680
 
1341
- *Eileen M. Uchitelle*
1681
+ * Fix `ActiveRecord::Store` to serialize as a regular Hash
1682
+
1683
+ Previously it would serialize as an `ActiveSupport::HashWithIndifferentAccess`
1684
+ which is wasteful and cause problem with YAML safe_load.
1342
1685
 
1343
- * Add additional database-specific rake tasks for multi-database users.
1686
+ *Jean Boussier*
1344
1687
 
1345
- Previously, `rails db:create`, `rails db:drop`, and `rails db:migrate` were the only rails tasks that could operate on a single
1346
- database. For example:
1688
+ * Add `timestamptz` as a time zone aware type for PostgreSQL
1347
1689
 
1348
- ```
1349
- rails db:create
1350
- rails db:create:primary
1351
- rails db:create:animals
1352
- rails db:drop
1353
- rails db:drop:primary
1354
- rails db:drop:animals
1355
- rails db:migrate
1356
- rails db:migrate:primary
1357
- rails db:migrate:animals
1358
- ```
1690
+ This is required for correctly parsing `timestamp with time zone` values in your database.
1359
1691
 
1360
- With these changes, `rails db:schema:dump`, `rails db:schema:load`, `rails db:structure:dump`, `rails db:structure:load` and
1361
- `rails db:test:prepare` can additionally operate on a single database. For example:
1692
+ If you don't want this, you can opt out by adding this initializer:
1362
1693
 
1363
- ```
1364
- rails db:schema:dump
1365
- rails db:schema:dump:primary
1366
- rails db:schema:dump:animals
1367
- rails db:schema:load
1368
- rails db:schema:load:primary
1369
- rails db:schema:load:animals
1370
- rails db:structure:dump
1371
- rails db:structure:dump:primary
1372
- rails db:structure:dump:animals
1373
- rails db:structure:load
1374
- rails db:structure:load:primary
1375
- rails db:structure:load:animals
1376
- rails db:test:prepare
1377
- rails db:test:prepare:primary
1378
- rails db:test:prepare:animals
1694
+ ```ruby
1695
+ ActiveRecord::Base.time_zone_aware_types -= [:timestamptz]
1379
1696
  ```
1380
1697
 
1381
- *Kyle Thompson*
1698
+ *Alex Ghiculescu*
1382
1699
 
1383
- * Add support for `strict_loading` mode on association declarations.
1700
+ * Add new `ActiveRecord::Base.generates_token_for` API.
1384
1701
 
1385
- Raise an error if attempting to load a record from an association that has been marked as `strict_loading` unless it was explicitly eager loaded.
1702
+ Currently, `signed_id` fulfills the role of generating tokens for e.g.
1703
+ resetting a password. However, signed IDs cannot reflect record state, so
1704
+ if a token is intended to be single-use, it must be tracked in a database at
1705
+ least until it expires.
1386
1706
 
1387
- Usage:
1707
+ With `generates_token_for`, a token can embed data from a record. When
1708
+ using the token to fetch the record, the data from the token and the current
1709
+ data from the record will be compared. If the two do not match, the token
1710
+ will be treated as invalid, the same as if it had expired. For example:
1388
1711
 
1389
1712
  ```ruby
1390
- class Developer < ApplicationRecord
1391
- has_many :projects, strict_loading: true
1713
+ class User < ActiveRecord::Base
1714
+ has_secure_password
1715
+
1716
+ generates_token_for :password_reset, expires_in: 15.minutes do
1717
+ # A password's BCrypt salt changes when the password is updated.
1718
+ # By embedding (part of) the salt in a token, the token will
1719
+ # expire when the password is updated.
1720
+ BCrypt::Password.new(password_digest).salt[-10..]
1721
+ end
1392
1722
  end
1393
1723
 
1394
- dev = Developer.first
1395
- dev.projects.first
1396
- # => ActiveRecord::StrictLoadingViolationError: The projects association is marked as strict_loading and cannot be lazily loaded.
1724
+ user = User.first
1725
+ token = user.generate_token_for(:password_reset)
1726
+
1727
+ User.find_by_token_for(:password_reset, token) # => user
1728
+
1729
+ user.update!(password: "new password")
1730
+ User.find_by_token_for(:password_reset, token) # => nil
1397
1731
  ```
1398
1732
 
1399
- *Kevin Deisz*
1733
+ *Jonathan Hefner*
1400
1734
 
1401
- * Add support for `strict_loading` mode to prevent lazy loading of records.
1735
+ * Optimize Active Record batching for whole table iterations.
1402
1736
 
1403
- Raise an error if a parent record is marked as `strict_loading` and attempts to lazily load its associations. This is useful for finding places you may want to preload an association and avoid additional queries.
1737
+ Previously, `in_batches` got all the ids and constructed an `IN`-based query for each batch.
1738
+ When iterating over the whole tables, this approach is not optimal as it loads unneeded ids and
1739
+ `IN` queries with lots of items are slow.
1404
1740
 
1405
- Usage:
1741
+ Now, whole table iterations use range iteration (`id >= x AND id <= y`) by default which can make iteration
1742
+ several times faster. E.g., tested on a PostgreSQL table with 10 million records: querying (`253s` vs `30s`),
1743
+ updating (`288s` vs `124s`), deleting (`268s` vs `83s`).
1744
+
1745
+ Only whole table iterations use this style of iteration by default. You can disable this behavior by passing `use_ranges: false`.
1746
+ If you iterate over the table and the only condition is, e.g., `archived_at: nil` (and only a tiny fraction
1747
+ of the records are archived), it makes sense to opt in to this approach:
1406
1748
 
1407
1749
  ```ruby
1408
- dev = Developer.strict_loading.first
1409
- dev.audit_logs.to_a
1410
- # => ActiveRecord::StrictLoadingViolationError: Developer is marked as strict_loading and AuditLog cannot be lazily loaded.
1750
+ Project.where(archived_at: nil).in_batches(use_ranges: true) do |relation|
1751
+ # do something
1752
+ end
1411
1753
  ```
1412
1754
 
1413
- *Eileen M. Uchitelle*, *Aaron Patterson*
1755
+ See #45414 for more details.
1414
1756
 
1415
- * Add support for PostgreSQL 11+ partitioned indexes when using `upsert_all`.
1757
+ *fatkodima*
1416
1758
 
1417
- *Sebastián Palma*
1759
+ * `.with` query method added. Construct common table expressions with ease and get `ActiveRecord::Relation` back.
1418
1760
 
1419
- * Adds support for `if_not_exists` to `add_column` and `if_exists` to `remove_column`.
1761
+ ```ruby
1762
+ Post.with(posts_with_comments: Post.where("comments_count > ?", 0))
1763
+ # => ActiveRecord::Relation
1764
+ # WITH posts_with_comments AS (SELECT * FROM posts WHERE (comments_count > 0)) SELECT * FROM posts
1765
+ ```
1420
1766
 
1421
- Applications can set their migrations to ignore exceptions raised when adding a column that already exists or when removing a column that does not exist.
1767
+ *Vlado Cingel*
1422
1768
 
1423
- Example Usage:
1769
+ * Don't establish a new connection if an identical pool exists already.
1424
1770
 
1425
- ```ruby
1426
- class AddColumnTitle < ActiveRecord::Migration[6.1]
1427
- def change
1428
- add_column :posts, :title, :string, if_not_exists: true
1429
- end
1430
- end
1431
- ```
1771
+ Previously, if `establish_connection` was called on a class that already had an established connection, the existing connection would be removed regardless of whether it was the same config. Now if a pool is found with the same values as the new connection, the existing connection will be returned instead of creating a new one.
1432
1772
 
1433
- ```ruby
1434
- class RemoveColumnTitle < ActiveRecord::Migration[6.1]
1435
- def change
1436
- remove_column :posts, :title, if_exists: true
1437
- end
1438
- end
1439
- ```
1773
+ This has a slight change in behavior if application code is depending on a new connection being established regardless of whether it's identical to an existing connection. If the old behavior is desirable, applications should call `ActiveRecord::Base#remove_connection` before establishing a new one. Calling `establish_connection` with a different config works the same way as it did previously.
1440
1774
 
1441
1775
  *Eileen M. Uchitelle*
1442
1776
 
1443
- * Regexp-escape table name for MS SQL Server.
1777
+ * Update `db:prepare` task to load schema when an uninitialized database exists, and dump schema after migrations.
1444
1778
 
1445
- Add `Regexp.escape` to one method in ActiveRecord, so that table names with regular expression characters in them work as expected. Since MS SQL Server uses "[" and "]" to quote table and column names, and those characters are regular expression characters, methods like `pluck` and `select` fail in certain cases when used with the MS SQL Server adapter.
1779
+ *Ben Sheldon*
1446
1780
 
1447
- *Larry Reid*
1781
+ * Fix supporting timezone awareness for `tsrange` and `tstzrange` array columns.
1448
1782
 
1449
- * Store advisory locks on their own named connection.
1783
+ ```ruby
1784
+ # In database migrations
1785
+ add_column :shops, :open_hours, :tsrange, array: true
1786
+ # In app config
1787
+ ActiveRecord::Base.time_zone_aware_types += [:tsrange]
1788
+ # In the code times are properly converted to app time zone
1789
+ Shop.create!(open_hours: [Time.current..8.hour.from_now])
1790
+ ```
1450
1791
 
1451
- Previously advisory locks were taken out against a connection when a migration started. This works fine in single database applications but doesn't work well when migrations need to open new connections which results in the lock getting dropped.
1792
+ *Wojciech Wnętrzak*
1452
1793
 
1453
- In order to fix this we are storing the advisory lock on a new connection with the connection specification name `AdvisoryLockBase`. The caveat is that we need to maintain at least 2 connections to a database while migrations are running in order to do this.
1794
+ * Introduce strategy pattern for executing migrations.
1454
1795
 
1455
- *Eileen M. Uchitelle*, *John Crepezzi*
1796
+ By default, migrations will use a strategy object that delegates the method
1797
+ to the connection adapter. Consumers can implement custom strategy objects
1798
+ to change how their migrations run.
1456
1799
 
1457
- * Allow schema cache path to be defined in the database configuration file.
1800
+ *Adrianna Chang*
1458
1801
 
1459
- For example:
1802
+ * Add adapter option disallowing foreign keys
1803
+
1804
+ This adds a new option to be added to `database.yml` which enables skipping
1805
+ foreign key constraints usage even if the underlying database supports them.
1460
1806
 
1807
+ Usage:
1461
1808
  ```yaml
1462
1809
  development:
1463
- adapter: postgresql
1464
- database: blog_development
1465
- pool: 5
1466
- schema_cache_path: tmp/schema/main.yml
1810
+ <<: *default
1811
+ database: storage/development.sqlite3
1812
+ foreign_keys: false
1467
1813
  ```
1468
1814
 
1469
- *Katrina Owen*
1815
+ *Paulo Barros*
1470
1816
 
1471
- * Deprecate `#remove_connection` in favor of `#remove_connection_pool` when called on the handler.
1817
+ * Add configurable deprecation warning for singular associations
1472
1818
 
1473
- `#remove_connection` is deprecated in order to support returning a `DatabaseConfig` object instead of a `Hash`. Use `#remove_connection_pool`, `#remove_connection` will be removed in Rails 7.0.
1819
+ This adds a deprecation warning when using the plural name of a singular associations in `where`.
1820
+ It is possible to opt into the new more performant behavior with `config.active_record.allow_deprecated_singular_associations_name = false`
1474
1821
 
1475
- *Eileen M. Uchitelle*, *John Crepezzi*
1822
+ *Adam Hess*
1476
1823
 
1477
- * Deprecate `#default_hash` and it's alias `#[]` on database configurations.
1824
+ * Run transactional callbacks on the freshest instance to save a given
1825
+ record within a transaction.
1478
1826
 
1479
- Applications should use `configs_for`. `#default_hash` and `#[]` will be removed in Rails 7.0.
1827
+ When multiple Active Record instances change the same record within a
1828
+ transaction, Rails runs `after_commit` or `after_rollback` callbacks for
1829
+ only one of them. `config.active_record.run_commit_callbacks_on_first_saved_instances_in_transaction`
1830
+ was added to specify how Rails chooses which instance receives the
1831
+ callbacks. The framework defaults were changed to use the new logic.
1480
1832
 
1481
- *Eileen M. Uchitelle*, *John Crepezzi*
1833
+ When `config.active_record.run_commit_callbacks_on_first_saved_instances_in_transaction`
1834
+ is `true`, transactional callbacks are run on the first instance to save,
1835
+ even though its instance state may be stale.
1482
1836
 
1483
- * Add scale support to `ActiveRecord::Validations::NumericalityValidator`.
1837
+ When it is `false`, which is the new framework default starting with version
1838
+ 7.1, transactional callbacks are run on the instances with the freshest
1839
+ instance state. Those instances are chosen as follows:
1484
1840
 
1485
- *Gannon McGibbon*
1841
+ - In general, run transactional callbacks on the last instance to save a
1842
+ given record within the transaction.
1843
+ - There are two exceptions:
1844
+ - If the record is created within the transaction, then updated by
1845
+ another instance, `after_create_commit` callbacks will be run on the
1846
+ second instance. This is instead of the `after_update_commit`
1847
+ callbacks that would naively be run based on that instance’s state.
1848
+ - If the record is destroyed within the transaction, then
1849
+ `after_destroy_commit` callbacks will be fired on the last destroyed
1850
+ instance, even if a stale instance subsequently performed an update
1851
+ (which will have affected 0 rows).
1486
1852
 
1487
- * Find orphans by looking for missing relations through chaining `where.missing`:
1853
+ *Cameron Bothner and Mitch Vollebregt*
1488
1854
 
1489
- Before:
1855
+ * Enable strict strings mode for `SQLite3Adapter`.
1856
+
1857
+ Configures SQLite with a strict strings mode, which disables double-quoted string literals.
1858
+
1859
+ SQLite has some quirks around double-quoted string literals.
1860
+ It first tries to consider double-quoted strings as identifier names, but if they don't exist
1861
+ it then considers them as string literals. Because of this, typos can silently go unnoticed.
1862
+ For example, it is possible to create an index for a non existing column.
1863
+ See [SQLite documentation](https://www.sqlite.org/quirks.html#double_quoted_string_literals_are_accepted) for more details.
1864
+
1865
+ If you don't want this behavior, you can disable it via:
1490
1866
 
1491
1867
  ```ruby
1492
- Post.left_joins(:author).where(authors: { id: nil })
1868
+ # config/application.rb
1869
+ config.active_record.sqlite3_adapter_strict_strings_by_default = false
1493
1870
  ```
1494
1871
 
1495
- After:
1872
+ Fixes #27782.
1873
+
1874
+ *fatkodima*, *Jean Boussier*
1875
+
1876
+ * Resolve issue where a relation cache_version could be left stale.
1877
+
1878
+ Previously, when `reset` was called on a relation object it did not reset the cache_versions
1879
+ ivar. This led to a confusing situation where despite having the correct data the relation
1880
+ still reported a stale cache_version.
1881
+
1882
+ Usage:
1496
1883
 
1497
1884
  ```ruby
1498
- Post.where.missing(:author)
1885
+ developers = Developer.all
1886
+ developers.cache_version
1887
+
1888
+ Developer.update_all(updated_at: Time.now.utc + 1.second)
1889
+
1890
+ developers.cache_version # Stale cache_version
1891
+ developers.reset
1892
+ developers.cache_version # Returns the current correct cache_version
1499
1893
  ```
1500
1894
 
1501
- *Tom Rossi*
1895
+ Fixes #45341.
1502
1896
 
1503
- * Ensure `:reading` connections always raise if a write is attempted.
1897
+ *Austen Madden*
1504
1898
 
1505
- Now Rails will raise an `ActiveRecord::ReadOnlyError` if any connection on the reading handler attempts to make a write. If your reading role needs to write you should name the role something other than `:reading`.
1899
+ * Add support for exclusion constraints (PostgreSQL-only).
1506
1900
 
1507
- *Eileen M. Uchitelle*
1901
+ ```ruby
1902
+ add_exclusion_constraint :invoices, "daterange(start_date, end_date) WITH &&", using: :gist, name: "invoices_date_overlap"
1903
+ remove_exclusion_constraint :invoices, name: "invoices_date_overlap"
1904
+ ```
1508
1905
 
1509
- * Deprecate `"primary"` as the `connection_specification_name` for `ActiveRecord::Base`.
1906
+ See PostgreSQL's [`CREATE TABLE ... EXCLUDE ...`](https://www.postgresql.org/docs/12/sql-createtable.html#SQL-CREATETABLE-EXCLUDE) documentation for more on exclusion constraints.
1510
1907
 
1511
- `"primary"` has been deprecated as the `connection_specification_name` for `ActiveRecord::Base` in favor of using `"ActiveRecord::Base"`. This change affects calls to `ActiveRecord::Base.connection_handler.retrieve_connection` and `ActiveRecord::Base.connection_handler.remove_connection`. If you're calling these methods with `"primary"`, please switch to `"ActiveRecord::Base"`.
1908
+ *Alex Robbin*
1512
1909
 
1513
- *Eileen M. Uchitelle*, *John Crepezzi*
1910
+ * `change_column_null` raises if a non-boolean argument is provided
1514
1911
 
1515
- * Add `ActiveRecord::Validations::NumericalityValidator` with
1516
- support for casting floats using a database columns' precision value.
1912
+ Previously if you provided a non-boolean argument, `change_column_null` would
1913
+ treat it as truthy and make your column nullable. This could be surprising, so now
1914
+ the input must be either `true` or `false`.
1517
1915
 
1518
- *Gannon McGibbon*
1916
+ ```ruby
1917
+ change_column_null :table, :column, true # good
1918
+ change_column_null :table, :column, false # good
1919
+ change_column_null :table, :column, from: true, to: false # raises (previously this made the column nullable)
1920
+ ```
1921
+
1922
+ *Alex Ghiculescu*
1519
1923
 
1520
- * Enforce fresh ETag header after a collection's contents change by adding
1521
- ActiveRecord::Relation#cache_key_with_version. This method will be used by
1522
- ActionController::ConditionalGet to ensure that when collection cache versioning
1523
- is enabled, requests using ConditionalGet don't return the same ETag header
1524
- after a collection is modified.
1924
+ * Enforce limit on table names length.
1525
1925
 
1526
- Fixes #38078.
1926
+ Fixes #45130.
1527
1927
 
1528
- *Aaron Lipman*
1928
+ *fatkodima*
1529
1929
 
1530
- * Skip test database when running `db:create` or `db:drop` in development
1531
- with `DATABASE_URL` set.
1930
+ * Adjust the minimum MariaDB version for check constraints support.
1532
1931
 
1533
- *Brian Buchalter*
1932
+ *Eddie Lebow*
1534
1933
 
1535
- * Don't allow mutations on the database configurations hash.
1934
+ * Fix Hstore deserialize regression.
1536
1935
 
1537
- Freeze the configurations hash to disallow directly changing it. If applications need to change the hash, for example to create databases for parallelization, they should use the `DatabaseConfig` object directly.
1936
+ *edsharp*
1538
1937
 
1539
- Before:
1938
+ * Add validity for PostgreSQL indexes.
1540
1939
 
1541
1940
  ```ruby
1542
- @db_config = ActiveRecord::Base.configurations.configs_for(env_name: "test", spec_name: "primary")
1543
- @db_config.configuration_hash.merge!(idle_timeout: "0.02")
1941
+ connection.index_exists?(:users, :email, valid: true)
1942
+ connection.indexes(:users).select(&:valid?)
1544
1943
  ```
1545
1944
 
1546
- After:
1945
+ *fatkodima*
1946
+
1947
+ * Fix eager loading for models without primary keys.
1948
+
1949
+ *Anmol Chopra*, *Matt Lawrence*, and *Jonathan Hefner*
1950
+
1951
+ * Avoid validating a unique field if it has not changed and is backed by a unique index.
1952
+
1953
+ Previously, when saving a record, Active Record will perform an extra query to check for the
1954
+ uniqueness of each attribute having a `uniqueness` validation, even if that attribute hasn't changed.
1955
+ If the database has the corresponding unique index, then this validation can never fail for persisted
1956
+ records, and we could safely skip it.
1957
+
1958
+ *fatkodima*
1959
+
1960
+ * Stop setting `sql_auto_is_null`
1961
+
1962
+ Since version 5.5 the default has been off, we no longer have to manually turn it off.
1963
+
1964
+ *Adam Hess*
1965
+
1966
+ * Fix `touch` to raise an error for readonly columns.
1967
+
1968
+ *fatkodima*
1969
+
1970
+ * Add ability to ignore tables by regexp for SQL schema dumps.
1547
1971
 
1548
1972
  ```ruby
1549
- @db_config = ActiveRecord::Base.configurations.configs_for(env_name: "test", spec_name: "primary")
1550
- config = @db_config.configuration_hash.merge(idle_timeout: "0.02")
1551
- db_config = ActiveRecord::DatabaseConfigurations::HashConfig.new(@db_config.env_name, @db_config.spec_name, config)
1973
+ ActiveRecord::SchemaDumper.ignore_tables = [/^_/]
1552
1974
  ```
1553
1975
 
1554
- *Eileen M. Uchitelle*, *John Crepezzi*
1555
-
1556
- * Remove `:connection_id` from the `sql.active_record` notification.
1976
+ *fatkodima*
1557
1977
 
1558
- *Aaron Patterson*, *Rafael Mendonça França*
1978
+ * Avoid queries when performing calculations on contradictory relations.
1559
1979
 
1560
- * The `:name` key will no longer be returned as part of `DatabaseConfig#configuration_hash`. Please use `DatabaseConfig#owner_name` instead.
1980
+ Previously calculations would make a query even when passed a
1981
+ contradiction, such as `User.where(id: []).count`. We no longer perform a
1982
+ query in that scenario.
1561
1983
 
1562
- *Eileen M. Uchitelle*, *John Crepezzi*
1984
+ This applies to the following calculations: `count`, `sum`, `average`,
1985
+ `minimum` and `maximum`
1563
1986
 
1564
- * ActiveRecord's `belongs_to_required_by_default` flag can now be set per model.
1987
+ *Luan Vieira, John Hawthorn and Daniel Colson*
1565
1988
 
1566
- You can now opt-out/opt-in specific models from having their associations required
1567
- by default.
1989
+ * Allow using aliased attributes with `insert_all`/`upsert_all`.
1568
1990
 
1569
- This change is meant to ease the process of migrating all your models to have
1570
- their association required.
1991
+ ```ruby
1992
+ class Book < ApplicationRecord
1993
+ alias_attribute :title, :name
1994
+ end
1571
1995
 
1572
- *Edouard Chin*
1996
+ Book.insert_all [{ title: "Remote", author_id: 1 }], returning: :title
1997
+ ```
1573
1998
 
1574
- * The `connection_config` method has been deprecated, please use `connection_db_config` instead which will return a `DatabaseConfigurations::DatabaseConfig` instead of a `Hash`.
1999
+ *fatkodima*
1575
2000
 
1576
- *Eileen M. Uchitelle*, *John Crepezzi*
2001
+ * Support encrypted attributes on columns with default db values.
1577
2002
 
1578
- * Retain explicit selections on the base model after applying `includes` and `joins`.
2003
+ This adds support for encrypted attributes defined on columns with default values.
2004
+ It will encrypt those values at creation time. Before, it would raise an
2005
+ error unless `config.active_record.encryption.support_unencrypted_data` was true.
1579
2006
 
1580
- Resolves #34889.
2007
+ *Jorge Manrubia* and *Dima Fatko*
1581
2008
 
1582
- *Patrick Rebsch*
2009
+ * Allow overriding `reading_request?` in `DatabaseSelector::Resolver`
1583
2010
 
1584
- * The `database` kwarg is deprecated without replacement because it can't be used for sharding and creates an issue if it's used during a request. Applications that need to create new connections should use `connects_to` instead.
2011
+ The default implementation checks if a request is a `get?` or `head?`,
2012
+ but you can now change it to anything you like. If the method returns true,
2013
+ `Resolver#read` gets called meaning the request could be served by the
2014
+ replica database.
1585
2015
 
1586
- *Eileen M. Uchitelle*, *John Crepezzi*
2016
+ *Alex Ghiculescu*
1587
2017
 
1588
- * Allow attributes to be fetched from Arel node groupings.
2018
+ * Remove `ActiveRecord.legacy_connection_handling`.
1589
2019
 
1590
- *Jeff Emminger*, *Gannon McGibbon*
2020
+ *Eileen M. Uchitelle*
1591
2021
 
1592
- * A database URL can now contain a querystring value that contains an equal sign. This is needed to support passing PostgreSQL `options`.
2022
+ * `rails db:schema:{dump,load}` now checks `ENV["SCHEMA_FORMAT"]` before config
1593
2023
 
1594
- *Joshua Flanagan*
2024
+ Since `rails db:structure:{dump,load}` was deprecated there wasn't a simple
2025
+ way to dump a schema to both SQL and Ruby formats. You can now do this with
2026
+ an environment variable. For example:
1595
2027
 
1596
- * Calling methods like `establish_connection` with a `Hash` which is invalid (eg: no `adapter`) will now raise an error the same way as connections defined in `config/database.yml`.
2028
+ ```
2029
+ SCHEMA_FORMAT=sql rake db:schema:dump
2030
+ ```
1597
2031
 
1598
- *John Crepezzi*
2032
+ *Alex Ghiculescu*
1599
2033
 
1600
- * Specifying `implicit_order_column` now subsorts the records by primary key if available to ensure deterministic results.
2034
+ * Fixed MariaDB default function support.
1601
2035
 
1602
- *Paweł Urbanek*
2036
+ Defaults would be written wrong in "db/schema.rb" and not work correctly
2037
+ if using `db:schema:load`. Further more the function name would be
2038
+ added as string content when saving new records.
1603
2039
 
1604
- * `where(attr => [])` now loads an empty result without making a query.
2040
+ *kaspernj*
1605
2041
 
1606
- *John Hawthorn*
2042
+ * Add `active_record.destroy_association_async_batch_size` configuration
1607
2043
 
1608
- * Fixed the performance regression for `primary_keys` introduced MySQL 8.0.
2044
+ This allows applications to specify the maximum number of records that will
2045
+ be destroyed in a single background job by the `dependent: :destroy_async`
2046
+ association option. By default, the current behavior will remain the same:
2047
+ when a parent record is destroyed, all dependent records will be destroyed
2048
+ in a single background job. If the number of dependent records is greater
2049
+ than this configuration, the records will be destroyed in multiple
2050
+ background jobs.
1609
2051
 
1610
- *Hiroyuki Ishii*
2052
+ *Nick Holden*
1611
2053
 
1612
- * Add support for `belongs_to` to `has_many` inversing.
2054
+ * Fix `remove_foreign_key` with `:if_exists` option when foreign key actually exists.
1613
2055
 
1614
- *Gannon McGibbon*
2056
+ *fatkodima*
1615
2057
 
1616
- * Allow length configuration for `has_secure_token` method. The minimum length
1617
- is set at 24 characters.
2058
+ * Remove `--no-comments` flag in structure dumps for PostgreSQL
1618
2059
 
1619
- Before:
2060
+ This broke some apps that used custom schema comments. If you don't want
2061
+ comments in your structure dump, you can use:
1620
2062
 
1621
2063
  ```ruby
1622
- has_secure_token :auth_token
2064
+ ActiveRecord::Tasks::DatabaseTasks.structure_dump_flags = ['--no-comments']
1623
2065
  ```
1624
2066
 
1625
- After:
2067
+ *Alex Ghiculescu*
1626
2068
 
1627
- ```ruby
1628
- has_secure_token :default_token # 24 characters
1629
- has_secure_token :auth_token, length: 36 # 36 characters
1630
- has_secure_token :invalid_token, length: 12 # => ActiveRecord::SecureToken::MinimumLengthError
1631
- ```
2069
+ * Reduce the memory footprint of fixtures accessors.
1632
2070
 
1633
- *Bernardo de Araujo*
2071
+ Until now fixtures accessors were eagerly defined using `define_method`.
2072
+ So the memory usage was directly dependent of the number of fixtures and
2073
+ test suites.
1634
2074
 
1635
- * Deprecate `DatabaseConfigurations#to_h`. These connection hashes are still available via `ActiveRecord::Base.configurations.configs_for`.
2075
+ Instead fixtures accessors are now implemented with `method_missing`,
2076
+ so they incur much less memory and CPU overhead.
1636
2077
 
1637
- *Eileen Uchitelle*, *John Crepezzi*
2078
+ *Jean Boussier*
1638
2079
 
1639
- * Add `DatabaseConfig#configuration_hash` to return database configuration hashes with symbol keys, and use all symbol-key configuration hashes internally. Deprecate `DatabaseConfig#config` which returns a String-keyed `Hash` with the same values.
2080
+ * Fix `config.active_record.destroy_association_async_job` configuration
1640
2081
 
1641
- *John Crepezzi*, *Eileen Uchitelle*
2082
+ `config.active_record.destroy_association_async_job` should allow
2083
+ applications to specify the job that will be used to destroy associated
2084
+ records in the background for `has_many` associations with the
2085
+ `dependent: :destroy_async` option. Previously, that was ignored, which
2086
+ meant the default `ActiveRecord::DestroyAssociationAsyncJob` always
2087
+ destroyed records in the background.
1642
2088
 
1643
- * Allow column names to be passed to `remove_index` positionally along with other options.
2089
+ *Nick Holden*
1644
2090
 
1645
- Passing other options can be necessary to make `remove_index` correctly reversible.
2091
+ * Fix `change_column_comment` to preserve column's AUTO_INCREMENT in the MySQL adapter
1646
2092
 
1647
- Before:
2093
+ *fatkodima*
1648
2094
 
1649
- add_index :reports, :report_id # => works
1650
- add_index :reports, :report_id, unique: true # => works
1651
- remove_index :reports, :report_id # => works
1652
- remove_index :reports, :report_id, unique: true # => ArgumentError
2095
+ * Fix quoting of `ActiveSupport::Duration` and `Rational` numbers in the MySQL adapter.
1653
2096
 
1654
- After:
2097
+ *Kevin McPhillips*
1655
2098
 
1656
- remove_index :reports, :report_id, unique: true # => works
2099
+ * Allow column name with COLLATE (e.g., title COLLATE "C") as safe SQL string
1657
2100
 
1658
- *Eugene Kenny*
2101
+ *Shugo Maeda*
1659
2102
 
1660
- * Allow bulk `ALTER` statements to drop and recreate indexes with the same name.
2103
+ * Permit underscores in the VERSION argument to database rake tasks.
1661
2104
 
1662
- *Eugene Kenny*
2105
+ *Eddie Lebow*
1663
2106
 
1664
- * `insert`, `insert_all`, `upsert`, and `upsert_all` now clear the query cache.
2107
+ * Reversed the order of `INSERT` statements in `structure.sql` dumps
1665
2108
 
1666
- *Eugene Kenny*
2109
+ This should decrease the likelihood of merge conflicts. New migrations
2110
+ will now be added at the top of the list.
1667
2111
 
1668
- * Call `while_preventing_writes` directly from `connected_to`.
2112
+ For existing apps, there will be a large diff the next time `structure.sql`
2113
+ is generated.
1669
2114
 
1670
- In some cases application authors want to use the database switching middleware and make explicit calls with `connected_to`. It's possible for an app to turn off writes and not turn them back on by the time we call `connected_to(role: :writing)`.
2115
+ *Alex Ghiculescu*, *Matt Larraz*
1671
2116
 
1672
- This change allows apps to fix this by assuming if a role is writing we want to allow writes, except in the case it's explicitly turned off.
2117
+ * Fix PG.connect keyword arguments deprecation warning on ruby 2.7
1673
2118
 
1674
- *Eileen M. Uchitelle*
2119
+ Fixes #44307.
2120
+
2121
+ *Nikita Vasilevsky*
1675
2122
 
1676
- * Improve detection of ActiveRecord::StatementTimeout with mysql2 adapter in the edge case when the query is terminated during filesort.
2123
+ * Fix dropping DB connections after serialization failures and deadlocks.
1677
2124
 
1678
- *Kir Shatrov*
2125
+ Prior to 6.1.4, serialization failures and deadlocks caused rollbacks to be
2126
+ issued for both real transactions and savepoints. This breaks MySQL which
2127
+ disallows rollbacks of savepoints following a deadlock.
1679
2128
 
1680
- * Stop trying to read yaml file fixtures when loading Active Record fixtures.
2129
+ 6.1.4 removed these rollbacks, for both transactions and savepoints, causing
2130
+ the DB connection to be left in an unknown state and thus discarded.
1681
2131
 
1682
- *Gannon McGibbon*
2132
+ These rollbacks are now restored, except for savepoints on MySQL.
1683
2133
 
1684
- * Deprecate `.reorder(nil)` with `.first` / `.first!` taking non-deterministic result.
2134
+ *Thomas Morgan*
1685
2135
 
1686
- To continue taking non-deterministic result, use `.take` / `.take!` instead.
2136
+ * Make `ActiveRecord::ConnectionPool` Fiber-safe
1687
2137
 
1688
- *Ryuta Kamizono*
2138
+ When `ActiveSupport::IsolatedExecutionState.isolation_level` is set to `:fiber`,
2139
+ the connection pool now supports multiple Fibers from the same Thread checking
2140
+ out connections from the pool.
1689
2141
 
1690
- * Preserve user supplied joins order as much as possible.
2142
+ *Alex Matchneer*
1691
2143
 
1692
- Fixes #36761, #34328, #24281, #12953.
2144
+ * Add `update_attribute!` to `ActiveRecord::Persistence`
1693
2145
 
1694
- *Ryuta Kamizono*
2146
+ Similar to `update_attribute`, but raises `ActiveRecord::RecordNotSaved` when a `before_*` callback throws `:abort`.
1695
2147
 
1696
- * Allow `matches_regex` and `does_not_match_regexp` on the MySQL Arel visitor.
2148
+ ```ruby
2149
+ class Topic < ActiveRecord::Base
2150
+ before_save :check_title
1697
2151
 
1698
- *James Pearson*
2152
+ def check_title
2153
+ throw(:abort) if title == "abort"
2154
+ end
2155
+ end
1699
2156
 
1700
- * Allow specifying fixtures to be ignored by setting `ignore` in YAML file's '_fixture' section.
2157
+ topic = Topic.create(title: "Test Title")
2158
+ # #=> #<Topic title: "Test Title">
2159
+ topic.update_attribute!(:title, "Another Title")
2160
+ # #=> #<Topic title: "Another Title">
2161
+ topic.update_attribute!(:title, "abort")
2162
+ # raises ActiveRecord::RecordNotSaved
2163
+ ```
1701
2164
 
1702
- *Tongfei Gao*
2165
+ *Drew Tempelmeyer*
1703
2166
 
1704
- * Make the DATABASE_URL env variable only affect the primary connection. Add new env variables for multiple databases.
2167
+ * Avoid loading every record in `ActiveRecord::Relation#pretty_print`
1705
2168
 
1706
- *John Crepezzi*, *Eileen Uchitelle*
2169
+ ```ruby
2170
+ # Before
2171
+ pp Foo.all # Loads the whole table.
1707
2172
 
1708
- * Add a warning for enum elements with 'not_' prefix.
2173
+ # After
2174
+ pp Foo.all # Shows 10 items and an ellipsis.
2175
+ ```
1709
2176
 
1710
- class Foo
1711
- enum status: [:sent, :not_sent]
1712
- end
2177
+ *Ulysse Buonomo*
1713
2178
 
1714
- *Edu Depetris*
2179
+ * Change `QueryMethods#in_order_of` to drop records not listed in values.
1715
2180
 
1716
- * Make currency symbols optional for money column type in PostgreSQL.
2181
+ `in_order_of` now filters down to the values provided, to match the behavior of the `Enumerable` version.
1717
2182
 
1718
- *Joel Schneider*
2183
+ *Kevin Newton*
1719
2184
 
1720
- * Add support for beginless ranges, introduced in Ruby 2.7.
2185
+ * Allow named expression indexes to be revertible.
1721
2186
 
1722
- *Josh Goodall*
2187
+ Previously, the following code would raise an error in a reversible migration executed while rolling back, due to the index name not being used in the index removal.
1723
2188
 
1724
- * Add `database_exists?` method to connection adapters to check if a database exists.
2189
+ ```ruby
2190
+ add_index(:settings, "(data->'property')", using: :gin, name: :index_settings_data_property)
2191
+ ```
1725
2192
 
1726
- *Guilherme Mansur*
2193
+ Fixes #43331.
1727
2194
 
1728
- * Loading the schema for a model that has no `table_name` raises a `TableNotSpecified` error.
2195
+ *Oliver Günther*
1729
2196
 
1730
- *Guilherme Mansur*, *Eugene Kenny*
2197
+ * Fix incorrect argument in PostgreSQL structure dump tasks.
1731
2198
 
1732
- * PostgreSQL: Fix GROUP BY with ORDER BY virtual count attribute.
2199
+ Updating the `--no-comment` argument added in Rails 7 to the correct `--no-comments` argument.
1733
2200
 
1734
- Fixes #36022.
2201
+ *Alex Dent*
1735
2202
 
1736
- *Ryuta Kamizono*
2203
+ * Fix migration compatibility to create SQLite references/belongs_to column as integer when migration version is 6.0.
1737
2204
 
1738
- * Make ActiveRecord `ConnectionPool.connections` method thread-safe.
2205
+ Reference/belongs_to in migrations with version 6.0 were creating columns as
2206
+ bigint instead of integer for the SQLite Adapter.
2207
+
2208
+ *Marcelo Lauxen*
2209
+
2210
+ * Fix `QueryMethods#in_order_of` to handle empty order list.
1739
2211
 
1740
- Fixes #36465.
2212
+ ```ruby
2213
+ Post.in_order_of(:id, []).to_a
2214
+ ```
1741
2215
 
1742
- *Jeff Doering*
2216
+ Also more explicitly set the column as secondary order, so that any other
2217
+ value is still ordered.
2218
+
2219
+ *Jean Boussier*
1743
2220
 
1744
- * Add support for multiple databases to `rails db:abort_if_pending_migrations`.
2221
+ * Fix quoting of column aliases generated by calculation methods.
1745
2222
 
1746
- *Mark Lee*
2223
+ Since the alias is derived from the table name, we can't assume the result
2224
+ is a valid identifier.
1747
2225
 
1748
- * Fix sqlite3 collation parsing when using decimal columns.
2226
+ ```ruby
2227
+ class Test < ActiveRecord::Base
2228
+ self.table_name = '1abc'
2229
+ end
2230
+ Test.group(:id).count
2231
+ # syntax error at or near "1" (ActiveRecord::StatementInvalid)
2232
+ # LINE 1: SELECT COUNT(*) AS count_all, "1abc"."id" AS 1abc_id FROM "1...
2233
+ ```
1749
2234
 
1750
- *Martin R. Schuster*
2235
+ *Jean Boussier*
1751
2236
 
1752
- * Fix invalid schema when primary key column has a comment.
2237
+ * Add `authenticate_by` when using `has_secure_password`.
1753
2238
 
1754
- Fixes #29966.
2239
+ `authenticate_by` is intended to replace code like the following, which
2240
+ returns early when a user with a matching email is not found:
1755
2241
 
1756
- *Guilherme Goettems Schneider*
2242
+ ```ruby
2243
+ User.find_by(email: "...")&.authenticate("...")
2244
+ ```
1757
2245
 
1758
- * Fix table comment also being applied to the primary key column.
2246
+ Such code is vulnerable to timing-based enumeration attacks, wherein an
2247
+ attacker can determine if a user account with a given email exists. After
2248
+ confirming that an account exists, the attacker can try passwords associated
2249
+ with that email address from other leaked databases, in case the user
2250
+ re-used a password across multiple sites (a common practice). Additionally,
2251
+ knowing an account email address allows the attacker to attempt a targeted
2252
+ phishing ("spear phishing") attack.
1759
2253
 
1760
- *Guilherme Goettems Schneider*
2254
+ `authenticate_by` addresses the vulnerability by taking the same amount of
2255
+ time regardless of whether a user with a matching email is found:
1761
2256
 
1762
- * Allow generated `create_table` migrations to include or skip timestamps.
2257
+ ```ruby
2258
+ User.authenticate_by(email: "...", password: "...")
2259
+ ```
1763
2260
 
1764
- *Michael Duchemin*
2261
+ *Jonathan Hefner*
1765
2262
 
1766
2263
 
1767
- Please check [6-0-stable](https://github.com/rails/rails/blob/6-0-stable/activerecord/CHANGELOG.md) for previous changes.
2264
+ Please check [7-0-stable](https://github.com/rails/rails/blob/7-0-stable/activerecord/CHANGELOG.md) for previous changes.