activerecord 7.0.0.alpha2 → 7.0.0.rc1

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of activerecord might be problematic. Click here for more details.

Files changed (102) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +504 -10
  3. data/lib/active_record/associations/association.rb +2 -8
  4. data/lib/active_record/associations/builder/collection_association.rb +9 -2
  5. data/lib/active_record/associations/collection_association.rb +10 -2
  6. data/lib/active_record/associations/preloader/association.rb +68 -48
  7. data/lib/active_record/associations/preloader/batch.rb +3 -6
  8. data/lib/active_record/associations/preloader/through_association.rb +19 -9
  9. data/lib/active_record/associations/preloader.rb +14 -24
  10. data/lib/active_record/associations/through_association.rb +2 -2
  11. data/lib/active_record/associations.rb +16 -3
  12. data/lib/active_record/asynchronous_queries_tracker.rb +3 -0
  13. data/lib/active_record/attribute_methods/dirty.rb +9 -1
  14. data/lib/active_record/attribute_methods.rb +7 -5
  15. data/lib/active_record/autosave_association.rb +3 -3
  16. data/lib/active_record/connection_adapters/abstract/connection_handler.rb +6 -26
  17. data/lib/active_record/connection_adapters/abstract/connection_pool/queue.rb +2 -2
  18. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +18 -5
  19. data/lib/active_record/connection_adapters/abstract/database_limits.rb +0 -17
  20. data/lib/active_record/connection_adapters/abstract/database_statements.rb +1 -1
  21. data/lib/active_record/connection_adapters/abstract/quoting.rb +33 -70
  22. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +4 -0
  23. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +9 -2
  24. data/lib/active_record/connection_adapters/abstract/transaction.rb +12 -19
  25. data/lib/active_record/connection_adapters/abstract_adapter.rb +37 -8
  26. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +1 -0
  27. data/lib/active_record/connection_adapters/column.rb +4 -0
  28. data/lib/active_record/connection_adapters/mysql/database_statements.rb +2 -2
  29. data/lib/active_record/connection_adapters/mysql/quoting.rb +23 -24
  30. data/lib/active_record/connection_adapters/mysql/schema_statements.rb +1 -1
  31. data/lib/active_record/connection_adapters/pool_config.rb +7 -5
  32. data/lib/active_record/connection_adapters/postgresql/column.rb +17 -1
  33. data/lib/active_record/connection_adapters/postgresql/quoting.rb +44 -44
  34. data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +21 -1
  35. data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +18 -1
  36. data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +25 -0
  37. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +15 -4
  38. data/lib/active_record/connection_adapters/postgresql_adapter.rb +48 -5
  39. data/lib/active_record/connection_adapters/schema_cache.rb +3 -1
  40. data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +2 -2
  41. data/lib/active_record/connection_adapters/sqlite3/quoting.rb +15 -16
  42. data/lib/active_record/connection_handling.rb +31 -19
  43. data/lib/active_record/core.rb +13 -24
  44. data/lib/active_record/database_configurations/connection_url_resolver.rb +2 -1
  45. data/lib/active_record/database_configurations/database_config.rb +0 -9
  46. data/lib/active_record/database_configurations/hash_config.rb +40 -8
  47. data/lib/active_record/database_configurations.rb +2 -27
  48. data/lib/active_record/delegated_type.rb +19 -0
  49. data/lib/active_record/encryption/encrypted_attribute_type.rb +1 -1
  50. data/lib/active_record/encryption/extended_deterministic_uniqueness_validator.rb +1 -2
  51. data/lib/active_record/encryption/message_serializer.rb +11 -1
  52. data/lib/active_record/encryption/scheme.rb +1 -1
  53. data/lib/active_record/enum.rb +8 -1
  54. data/lib/active_record/errors.rb +1 -1
  55. data/lib/active_record/explain_registry.rb +11 -6
  56. data/lib/active_record/fixture_set/table_row.rb +1 -1
  57. data/lib/active_record/fixtures.rb +1 -9
  58. data/lib/active_record/future_result.rb +2 -2
  59. data/lib/active_record/gem_version.rb +1 -1
  60. data/lib/active_record/insert_all.rb +52 -15
  61. data/lib/active_record/integration.rb +3 -2
  62. data/lib/active_record/legacy_yaml_adapter.rb +2 -39
  63. data/lib/active_record/locking/pessimistic.rb +9 -3
  64. data/lib/active_record/log_subscriber.rb +8 -1
  65. data/lib/active_record/middleware/shard_selector.rb +60 -0
  66. data/lib/active_record/model_schema.rb +1 -28
  67. data/lib/active_record/nested_attributes.rb +11 -10
  68. data/lib/active_record/no_touching.rb +1 -1
  69. data/lib/active_record/persistence.rb +99 -21
  70. data/lib/active_record/query_logs.rb +18 -83
  71. data/lib/active_record/railtie.rb +11 -1
  72. data/lib/active_record/railties/databases.rake +4 -91
  73. data/lib/active_record/reflection.rb +22 -6
  74. data/lib/active_record/relation/calculations.rb +1 -10
  75. data/lib/active_record/relation/finder_methods.rb +0 -13
  76. data/lib/active_record/relation/query_methods.rb +5 -14
  77. data/lib/active_record/relation/record_fetch_warning.rb +5 -7
  78. data/lib/active_record/relation/where_clause.rb +2 -15
  79. data/lib/active_record/relation.rb +11 -13
  80. data/lib/active_record/result.rb +0 -5
  81. data/lib/active_record/runtime_registry.rb +10 -12
  82. data/lib/active_record/schema_dumper.rb +7 -0
  83. data/lib/active_record/scoping.rb +34 -22
  84. data/lib/active_record/suppressor.rb +11 -15
  85. data/lib/active_record/tasks/database_tasks.rb +18 -44
  86. data/lib/active_record/tasks/postgresql_database_tasks.rb +5 -1
  87. data/lib/active_record/validations/uniqueness.rb +1 -1
  88. data/lib/active_record.rb +41 -33
  89. data/lib/arel/crud.rb +12 -2
  90. data/lib/arel/delete_manager.rb +16 -0
  91. data/lib/arel/filter_predications.rb +9 -0
  92. data/lib/arel/nodes/delete_statement.rb +5 -1
  93. data/lib/arel/nodes/filter.rb +10 -0
  94. data/lib/arel/nodes/function.rb +1 -0
  95. data/lib/arel/nodes/update_statement.rb +5 -1
  96. data/lib/arel/nodes.rb +1 -0
  97. data/lib/arel/predications.rb +10 -2
  98. data/lib/arel/update_manager.rb +16 -0
  99. data/lib/arel/visitors/mysql.rb +2 -1
  100. data/lib/arel/visitors/to_sql.rb +15 -0
  101. data/lib/arel.rb +1 -0
  102. metadata +14 -10
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 2c726656eedc83ae6194a4d9ce8a59f0a584cdd619a576681acde6f238446601
4
- data.tar.gz: e7e4936dc0f4aa4e5d359d0c240548aed4a83045a1920ae4c748a0f95c7e6fc0
3
+ metadata.gz: c1a1968982fd2d7c0361ac7cfa9241a02c4ff558cc8fba93545800194274ac90
4
+ data.tar.gz: e19875a1df942ea1488aff91d0026e8584945504b14f9021660a1b55831f2ad2
5
5
  SHA512:
6
- metadata.gz: 789244fd0de0167502dd616d255a1d7ab35c8651a26c2a368449aa004265406705f8e26499bbd9ea7c40173b3ef9c7de4208e8ea247c1d0486560291fc530f3e
7
- data.tar.gz: b2072dea21d7eda209b0192c32725cb871b3ee3bcec49a4e3cf61e3b7c50d833cb2d843069cc6998bb4da285ec45ee4db5658db2490f637e82f92f6f37594fa3
6
+ metadata.gz: 17e093b64278febf6fa7db08a4184650581efeabdc2b32c652c2818951fa9608cd2bd804ba51304cbace26ffb2d83873ea416f29d600017161b607968e4fbe7e
7
+ data.tar.gz: cffe209fcb1de322ef8089a95b24940db52ac4cc5086c6fc7a749646a2e14f83a15384785a2bb390c149b770a17e9597789d12ceffb38e925e6067772d8a0556
data/CHANGELOG.md CHANGED
@@ -1,3 +1,497 @@
1
+ * Remove deprecated `ActiveRecord::DatabaseConfigurations::DatabaseConfig#spec_name`.
2
+
3
+ *Rafael Mendonça França*
4
+
5
+ * Remove deprecated `ActiveRecord::Connection#in_clause_length`.
6
+
7
+ *Rafael Mendonça França*
8
+
9
+ * Remove deprecated `ActiveRecord::Connection#allowed_index_name_length`.
10
+
11
+ *Rafael Mendonça França*
12
+
13
+ * Remove deprecated `ActiveRecord::Base#remove_connection`.
14
+
15
+ *Rafael Mendonça França*
16
+
17
+ * Load STI Models in fixtures
18
+
19
+ Data from Fixtures now loads based on the specific class for models with
20
+ Single Table Inheritance. This affects enums defined in subclasses, previously
21
+ the value of these fields was not parsed and remained `nil`
22
+
23
+ *Andres Howard*
24
+
25
+ * `#authenticate` returns false when the password is blank instead of raising an error.
26
+
27
+ *Muhammad Muhammad Ibrahim*
28
+
29
+ * Fix `ActiveRecord::QueryMethods#in_order_of` behavior for integer enums.
30
+
31
+ `ActiveRecord::QueryMethods#in_order_of` didn't work as expected for enums stored as integers in the database when passing an array of strings or symbols as the order argument. This unexpected behavior occurred because the string or symbol values were not casted to match the integers in the database.
32
+
33
+ The following example now works as expected:
34
+
35
+ ```ruby
36
+ class Book < ApplicationRecord
37
+ enum status: [:proposed, :written, :published]
38
+ end
39
+
40
+ Book.in_order_of(:status, %w[written published proposed])
41
+ ```
42
+
43
+ *Alexandre Ruban*
44
+
45
+ * Ignore persisted in-memory records when merging target lists.
46
+
47
+ *Kevin Sjöberg*
48
+
49
+ * Add a new option `:update_only` to `upsert_all` to configure the list of columns to update in case of conflict.
50
+
51
+ Before, you could only customize the update SQL sentence via `:on_duplicate`. There is now a new option `:update_only` that lets you provide a list of columns to update in case of conflict:
52
+
53
+ ```ruby
54
+ Commodity.upsert_all(
55
+ [
56
+ { id: 2, name: "Copper", price: 4.84 },
57
+ { id: 4, name: "Gold", price: 1380.87 },
58
+ { id: 6, name: "Aluminium", price: 0.35 }
59
+ ],
60
+ update_only: [:price] # Only prices will be updated
61
+ )
62
+ ```
63
+
64
+ *Jorge Manrubia*
65
+
66
+ * Remove deprecated `ActiveRecord::Result#map!` and `ActiveRecord::Result#collect!`.
67
+
68
+ *Rafael Mendonça França*
69
+
70
+ * Remove deprecated `ActiveRecord::Base.configurations.to_h`.
71
+
72
+ *Rafael Mendonça França*
73
+
74
+ * Remove deprecated `ActiveRecord::Base.configurations.default_hash`.
75
+
76
+ *Rafael Mendonça França*
77
+
78
+ * Remove deprecated `ActiveRecord::Base.arel_attribute`.
79
+
80
+ *Rafael Mendonça França*
81
+
82
+ * Remove deprecated `ActiveRecord::Base.connection_config`.
83
+
84
+ *Rafael Mendonça França*
85
+
86
+ * Filter attributes in SQL logs
87
+
88
+ Previously, SQL queries in logs containing `ActiveRecord::Base.filter_attributes` were not filtered.
89
+
90
+ Now, the filter attributes will be masked `[FILTERED]` in the logs when `prepared_statement` is enabled.
91
+
92
+ ```
93
+ # Before:
94
+ Foo Load (0.2ms) SELECT "foos".* FROM "foos" WHERE "foos"."passw" = ? LIMIT ? [["passw", "hello"], ["LIMIT", 1]]
95
+
96
+ # After:
97
+ Foo Load (0.5ms) SELECT "foos".* FROM "foos" WHERE "foos"."passw" = ? LIMIT ? [["passw", "[FILTERED]"], ["LIMIT", 1]]
98
+ ```
99
+
100
+ *Aishwarya Subramanian*
101
+
102
+ * Remove deprecated `Tasks::DatabaseTasks.spec`.
103
+
104
+ *Rafael Mendonça França*
105
+
106
+ * Remove deprecated `Tasks::DatabaseTasks.current_config`.
107
+
108
+ *Rafael Mendonça França*
109
+
110
+ * Deprecate `Tasks::DatabaseTasks.schema_file_type`.
111
+
112
+ *Rafael Mendonça França*
113
+
114
+ * Remove deprecated `Tasks::DatabaseTasks.dump_filename`.
115
+
116
+ *Rafael Mendonça França*
117
+
118
+ * Remove deprecated `Tasks::DatabaseTasks.schema_file`.
119
+
120
+ *Rafael Mendonça França*
121
+
122
+ * Remove deprecated `environment` and `name` arguments from `Tasks::DatabaseTasks.schema_up_to_date?`.
123
+
124
+ *Rafael Mendonça França*
125
+
126
+ * Merging conditions on the same column no longer maintain both conditions,
127
+ and will be consistently replaced by the latter condition.
128
+
129
+ ```ruby
130
+ # Rails 6.1 (IN clause is replaced by merger side equality condition)
131
+ Author.where(id: [david.id, mary.id]).merge(Author.where(id: bob)) # => [bob]
132
+ # Rails 6.1 (both conflict conditions exists, deprecated)
133
+ Author.where(id: david.id..mary.id).merge(Author.where(id: bob)) # => []
134
+ # Rails 6.1 with rewhere to migrate to Rails 7.0's behavior
135
+ Author.where(id: david.id..mary.id).merge(Author.where(id: bob), rewhere: true) # => [bob]
136
+ # Rails 7.0 (same behavior with IN clause, mergee side condition is consistently replaced)
137
+ Author.where(id: [david.id, mary.id]).merge(Author.where(id: bob)) # => [bob]
138
+ Author.where(id: david.id..mary.id).merge(Author.where(id: bob)) # => [bob]
139
+
140
+ *Rafael Mendonça França*
141
+
142
+ * Remove deprecated support to `Model.reorder(nil).first` to search using non-deterministic order.
143
+
144
+ *Rafael Mendonça França*
145
+
146
+ * Remove deprecated rake tasks:
147
+
148
+ * `db:schema:load_if_ruby`
149
+ * `db:structure:dump`
150
+ * `db:structure:load`
151
+ * `db:structure:load_if_sql`
152
+ * `db:structure:dump:#{name}`
153
+ * `db:structure:load:#{name}`
154
+ * `db:test:load_structure`
155
+ * `db:test:load_structure:#{name}`
156
+
157
+ *Rafael Mendonça França*
158
+
159
+ * Remove deprecated `DatabaseConfig#config` method.
160
+
161
+ *Rafael Mendonça França*
162
+
163
+ * Rollback transactions when the block returns earlier than expected.
164
+
165
+ Before this change, when a transaction block returned early, the transaction would be committed.
166
+
167
+ The problem is that timeouts triggered inside the transaction block was also making the incomplete transaction
168
+ to be committed, so in order to avoid this mistake, the transaction block is rolled back.
169
+
170
+ *Rafael Mendonça França*
171
+
172
+ * Add middleware for automatic shard swapping.
173
+
174
+ Provides a basic middleware to perform automatic shard swapping. Applications will provide a resolver which will determine for an individual request which shard should be used. Example:
175
+
176
+ ```ruby
177
+ config.active_record.shard_resolver = ->(request) {
178
+ subdomain = request.subdomain
179
+ tenant = Tenant.find_by_subdomain!(subdomain)
180
+ tenant.shard
181
+ }
182
+ ```
183
+
184
+ See guides for more details.
185
+
186
+ *Eileen M. Uchitelle*, *John Crepezzi*
187
+
188
+ * Remove deprecated support to pass a column to `type_cast`.
189
+
190
+ *Rafael Mendonça França*
191
+
192
+ * Remove deprecated support to type cast to database values `ActiveRecord::Base` objects.
193
+
194
+ *Rafael Mendonça França*
195
+
196
+ * Remove deprecated support to quote `ActiveRecord::Base` objects.
197
+
198
+ *Rafael Mendonça França*
199
+
200
+ * Remove deprecacated support to resolve connection using `"primary"` as connection specification name.
201
+
202
+ *Rafael Mendonça França*
203
+
204
+ * Remove deprecation warning when using `:interval` column is used in PostgreSQL database.
205
+
206
+ Now, interval columns will return `ActiveSupport::Duration` objects instead of strings.
207
+
208
+ To keep the old behavior, you can add this line to your model:
209
+
210
+ ```ruby
211
+ attribute :column, :string
212
+ ```
213
+
214
+ *Rafael Mendonça França*
215
+
216
+ * Remove deprecated support to YAML load `ActiveRecord::Base` instance in the Rails 4.2 and 4.1 formats.
217
+
218
+ *Rafael Mendonça França*
219
+
220
+ * Remove deprecated option `:spec_name` in the `configs_for` method.
221
+
222
+ *Rafael Mendonça França*
223
+
224
+ * Remove deprecated `ActiveRecord::Base.allow_unsafe_raw_sql`.
225
+
226
+ *Rafael Mendonça França*
227
+
228
+ * Fix regression bug that caused ignoring additional conditions for preloading has_many-through relations.
229
+
230
+ Fixes #43132
231
+
232
+ *Alexander Pauly*
233
+
234
+ * Fix `has_many` inversing recursion on models with recursive associations.
235
+
236
+ *Gannon McGibbon*
237
+
238
+ * Add `accepts_nested_attributes_for` support for `delegated_type`
239
+
240
+ ```ruby
241
+ class Entry < ApplicationRecord
242
+ delegated_type :entryable, types: %w[ Message Comment ]
243
+ accepts_nested_attributes_for :entryable
244
+ end
245
+
246
+ entry = Entry.create(entryable_type: 'Message', entryable_attributes: { content: 'Hello world' })
247
+ # => #<Entry:0x00>
248
+ # id: 1
249
+ # entryable_id: 1,
250
+ # entryable_type: 'Message'
251
+ # ...>
252
+
253
+ entry.entryable
254
+ # => #<Message:0x01>
255
+ # id: 1
256
+ # content: 'Hello world'
257
+ # ...>
258
+ ```
259
+
260
+ Previously it would raise an error:
261
+
262
+ ```ruby
263
+ Entry.create(entryable_type: 'Message', entryable_attributes: { content: 'Hello world' })
264
+ # ArgumentError: Cannot build association `entryable'. Are you trying to build a polymorphic one-to-one association?
265
+ ```
266
+
267
+ *Sjors Baltus*
268
+
269
+ * Use subquery for DELETE with GROUP_BY and HAVING clauses.
270
+
271
+ Prior to this change, deletes with GROUP_BY and HAVING were returning an error.
272
+
273
+ After this change, GROUP_BY and HAVING are valid clauses in DELETE queries, generating the following query:
274
+
275
+ ```sql
276
+ DELETE FROM "posts" WHERE "posts"."id" IN (
277
+ SELECT "posts"."id" FROM "posts" INNER JOIN "comments" ON "comments"."post_id" = "posts"."id" GROUP BY "posts"."id" HAVING (count(comments.id) >= 2))
278
+ ) [["flagged", "t"]]
279
+ ```
280
+
281
+ *Ignacio Chiazzo Cardarello*
282
+
283
+ * Use subquery for UPDATE with GROUP_BY and HAVING clauses.
284
+
285
+ Prior to this change, updates with GROUP_BY and HAVING were being ignored, generating a SQL like this:
286
+
287
+ ```sql
288
+ UPDATE "posts" SET "flagged" = ? WHERE "posts"."id" IN (
289
+ SELECT "posts"."id" FROM "posts" INNER JOIN "comments" ON "comments"."post_id" = "posts"."id"
290
+ ) [["flagged", "t"]]
291
+ ```
292
+
293
+ After this change, GROUP_BY and HAVING clauses are used as a subquery in updates, like this:
294
+
295
+ ```sql
296
+ UPDATE "posts" SET "flagged" = ? WHERE "posts"."id" IN (
297
+ SELECT "posts"."id" FROM "posts" INNER JOIN "comments" ON "comments"."post_id" = "posts"."id"
298
+ GROUP BY posts.id HAVING (count(comments.id) >= 2)
299
+ ) [["flagged", "t"]]
300
+ ```
301
+
302
+ *Ignacio Chiazzo Cardarello*
303
+
304
+ * Add support for setting the filename of the schema or structure dump in the database config.
305
+
306
+ Applications may now set their the filename or path of the schema / structure dump file in their database configuration.
307
+
308
+
309
+ ```yaml
310
+ production:
311
+ primary:
312
+ database: my_db
313
+ schema_dump: my_schema_dump_filename.rb
314
+ animals:
315
+ database: animals_db
316
+ schema_dump: false
317
+ ```
318
+
319
+ The filename set in `schema_dump` will be used by the application. If set to `false` the schema will not be dumped. The database tasks are responsible for adding the database directory to the filename. If a full path is provided, the Rails tasks will use that instead of `ActiveRecord::DatabaseTasks.db_dir`.
320
+
321
+ *Eileen M. Uchitelle*, *Ryan Kerr*
322
+
323
+ * Add `ActiveRecord::Base.prohibit_shard_swapping` to prevent attempts to change the shard within a block.
324
+
325
+ *John Crepezzi*, *Eileen M. Uchitelle*
326
+
327
+ * Filter unchanged attributes with default function from insert query when `partial_inserts` is disabled.
328
+
329
+ *Akshay Birajdar*, *Jacopo Beschi*
330
+
331
+ * Add support for FILTER clause (SQL:2003) to Arel.
332
+
333
+ Currently supported by PostgreSQL 9.4+ and SQLite 3.30+.
334
+
335
+ *Andrey Novikov*
336
+
337
+ * Automatically set timestamps on record creation during bulk insert/upsert
338
+
339
+ Prior to this change, only updates during an upsert operation (e.g. `upsert_all`) would touch timestamps (`updated_{at,on}`). Now, record creations also touch timestamp columns (`{created,updated}_{at,on}`).
340
+
341
+ This behaviour is controlled by the `<model>.record_timestamps` config, matching the behaviour of `create`, `update`, etc. It can also be overridden by using the `record_timestamps:` keyword argument.
342
+
343
+ Note that this means `upsert_all` on models with `record_timestamps = false` will no longer touch `updated_{at,on}` automatically.
344
+
345
+ *Sam Bostock*
346
+
347
+ * Don't require `role` when passing `shard` to `connected_to`.
348
+
349
+ `connected_to` can now be called with a `shard` only. Note that `role` is still inherited if `connected_to` calls are nested.
350
+
351
+ *Eileen M. Uchitelle*
352
+
353
+ * Add option to lazily load the schema cache on the connection.
354
+
355
+ Previously, the only way to load the schema cache in Active Record was through the Railtie on boot. This option provides the ability to load the schema cache on the connection after it's been established. Loading the cache lazily on the connection can be beneficial for Rails applications that use multiple databases because it will load the cache at the time the connection is established. Currently Railties doesn't have access to the connections before boot.
356
+
357
+ To use the cache, set `config.active_record.lazily_load_schema_cache = true` in your application configuration. In addition a `schema_cache_path` should be set in your database configuration if you don't want to use the default "db/schema_cache.yml" path.
358
+
359
+ *Eileen M. Uchitelle*
360
+
361
+ * Allow automatic `inverse_of` detection for associations with scopes.
362
+
363
+ Automatic `inverse_of` detection now works for associations with scopes. For
364
+ example, the `comments` association here now automatically detects
365
+ `inverse_of: :post`, so we don't need to pass that option:
366
+
367
+ ```ruby
368
+ class Post < ActiveRecord::Base
369
+ has_many :comments, -> { visible }
370
+ end
371
+
372
+ class Comment < ActiveRecord::Base
373
+ belongs_to :post
374
+ end
375
+ ```
376
+
377
+ Note that the automatic detection still won't work if the inverse
378
+ association has a scope. In this example a scope on the `post` association
379
+ would still prevent Rails from finding the inverse for the `comments`
380
+ association.
381
+
382
+ This will be the default for new apps in Rails 7. To opt in:
383
+
384
+ ```ruby
385
+ config.active_record.automatic_scope_inversing = true
386
+ ```
387
+
388
+ *Daniel Colson*, *Chris Bloom*
389
+
390
+ * Accept optional transaction args to `ActiveRecord::Locking::Pessimistic#with_lock`
391
+
392
+ `#with_lock` now accepts transaction options like `requires_new:`,
393
+ `isolation:`, and `joinable:`
394
+
395
+ * Adds support for deferrable foreign key constraints in PostgreSQL.
396
+
397
+ By default, foreign key constraints in PostgreSQL are checked after each statement. This works for most use cases,
398
+ but becomes a major limitation when creating related records before the parent record is inserted into the database.
399
+ One example of this is looking up / creating a person via one or more unique alias.
400
+
401
+ ```ruby
402
+ Person.transaction do
403
+ alias = Alias
404
+ .create_with(user_id: SecureRandom.uuid)
405
+ .create_or_find_by(name: "DHH")
406
+
407
+ person = Person
408
+ .create_with(name: "David Heinemeier Hansson")
409
+ .create_or_find_by(id: alias.user_id)
410
+ end
411
+ ```
412
+
413
+ Using the default behavior, the transaction would fail when executing the first `INSERT` statement.
414
+
415
+ By passing the `:deferrable` option to the `add_foreign_key` statement in migrations, it's possible to defer this
416
+ check.
417
+
418
+ ```ruby
419
+ add_foreign_key :aliases, :person, deferrable: true
420
+ ```
421
+
422
+ Passing `deferrable: true` doesn't change the default behavior, but allows manually deferring the check using
423
+ `SET CONSTRAINTS ALL DEFERRED` within a transaction. This will cause the foreign keys to be checked after the
424
+ transaction.
425
+
426
+ It's also possible to adjust the default behavior from an immediate check (after the statement), to a deferred check
427
+ (after the transaction):
428
+
429
+ ```ruby
430
+ add_foreign_key :aliases, :person, deferrable: :deferred
431
+ ```
432
+
433
+ *Benedikt Deicke*
434
+
435
+ * Allow configuring Postgres password through the socket URL.
436
+
437
+ For example:
438
+ ```ruby
439
+ ActiveRecord::DatabaseConfigurations::UrlConfig.new(
440
+ :production, :production, 'postgres:///?user=user&password=secret&dbname=app', {}
441
+ ).configuration_hash
442
+ ```
443
+
444
+ will now return,
445
+
446
+ ```ruby
447
+ { :user=>"user", :password=>"secret", :dbname=>"app", :adapter=>"postgresql" }
448
+ ```
449
+
450
+ *Abeid Ahmed*
451
+
452
+ * PostgreSQL: support custom enum types
453
+
454
+ In migrations, use `create_enum` to add a new enum type, and `t.enum` to add a column.
455
+
456
+ ```ruby
457
+ def up
458
+ create_enum :mood, ["happy", "sad"]
459
+
460
+ change_table :cats do |t|
461
+ t.enum :current_mood, enum_type: "mood", default: "happy", null: false
462
+ end
463
+ end
464
+ ```
465
+
466
+ Enums will be presented correctly in `schema.rb`. Note that this is only supported by
467
+ the PostgreSQL adapter.
468
+
469
+ *Alex Ghiculescu*
470
+
471
+ * Avoid COMMENT statements in PostgreSQL structure dumps
472
+
473
+ COMMENT statements are now omitted from the output of `db:structure:dump` when using PostgreSQL >= 11.
474
+ This allows loading the dump without a pgsql superuser account.
475
+
476
+ Fixes #36816, #43107.
477
+
478
+ *Janosch Müller*
479
+
480
+ * Add support for generated columns in PostgreSQL adapter
481
+
482
+ Generated columns are supported since version 12.0 of PostgreSQL. This adds
483
+ support of those to the PostgreSQL adapter.
484
+
485
+ ```ruby
486
+ create_table :users do |t|
487
+ t.string :name
488
+ t.virtual :name_upcased, type: :string, as: 'upper(name)', stored: true
489
+ end
490
+ ```
491
+
492
+ *Michał Begejowicz*
493
+
494
+
1
495
  ## Rails 7.0.0.alpha2 (September 15, 2021) ##
2
496
 
3
497
  * No changes.
@@ -98,10 +592,10 @@
98
592
 
99
593
  The behavior now is:
100
594
 
101
- `columns`: (unchanged) raises a db error if the table does not exist
102
- `columns_hash`: (unchanged) raises a db error if the table does not exist
103
- `primary_keys`: (unchanged) returns `nil` if the table does not exist
104
- `indexes`: (changed for mysql2) returns `[]` if the table does not exist
595
+ `columns`: (unchanged) raises a db error if the table does not exist.
596
+ `columns_hash`: (unchanged) raises a db error if the table does not exist.
597
+ `primary_keys`: (unchanged) returns `nil` if the table does not exist.
598
+ `indexes`: (changed for mysql2) returns `[]` if the table does not exist.
105
599
 
106
600
  *Eileen M. Uchitelle*
107
601
 
@@ -246,7 +740,7 @@
246
740
  * Add option to disable schema dump per-database.
247
741
 
248
742
  Dumping the schema is on by default for all databases in an application. To turn it off for a
249
- specific database use the `schema_dump` option:
743
+ specific database, use the `schema_dump` option:
250
744
 
251
745
  ```yaml
252
746
  # config/database.yml
@@ -283,7 +777,7 @@
283
777
  config.active_record.partial_inserts = true
284
778
  ```
285
779
 
286
- If a migration remove the default value of a column, this option
780
+ If a migration removes the default value of a column, this option
287
781
  would cause old processes to no longer be able to create new records.
288
782
 
289
783
  If you need to remove a column, you should first use `ignored_columns`
@@ -445,7 +939,7 @@
445
939
 
446
940
  * Fix compatibility with `psych >= 4`.
447
941
 
448
- Starting in Psych 4.0.0 `YAML.load` behaves like `YAML.safe_load`. To preserve compatibility
942
+ Starting in Psych 4.0.0 `YAML.load` behaves like `YAML.safe_load`. To preserve compatibility,
449
943
  Active Record's schema cache loader and `YAMLColumn` now uses `YAML.unsafe_load` if available.
450
944
 
451
945
  *Jean Boussier*
@@ -499,7 +993,7 @@
499
993
 
500
994
  ```ruby
501
995
  class Person
502
- belongs_to :dog
996
+ has_one :dog
503
997
  has_one :veterinarian, through: :dog, disable_joins: true
504
998
  end
505
999
  ```
@@ -975,8 +1469,8 @@
975
1469
 
976
1470
  *Eileen M. Uchitelle*, *John Crepezzi*
977
1471
 
978
- * Support hash config for `structure_dump_flags` and `structure_load_flags` flags
979
- Now that Active Record supports multiple databases configuration
1472
+ * Support hash config for `structure_dump_flags` and `structure_load_flags` flags.
1473
+ Now that Active Record supports multiple databases configuration,
980
1474
  we need a way to pass specific flags for dump/load databases since
981
1475
  the options are not the same for different adapters.
982
1476
  We can use in the original way:
@@ -52,7 +52,6 @@ module ActiveRecord
52
52
  @loaded = false
53
53
  @target = nil
54
54
  @stale_state = nil
55
- @inversed = false
56
55
  end
57
56
 
58
57
  def reset_negative_cache # :nodoc:
@@ -78,7 +77,6 @@ module ActiveRecord
78
77
  def loaded!
79
78
  @loaded = true
80
79
  @stale_state = stale_state
81
- @inversed = false
82
80
  end
83
81
 
84
82
  # The target is stale if the target no longer points to the record(s) that the
@@ -88,7 +86,7 @@ module ActiveRecord
88
86
  #
89
87
  # Note that if the target has not been loaded, it is not considered stale.
90
88
  def stale_target?
91
- !@inversed && loaded? && @stale_state != stale_state
89
+ loaded? && @stale_state != stale_state
92
90
  end
93
91
 
94
92
  # Sets the target of this association to <tt>\target</tt>, and the \loaded flag to +true+.
@@ -137,15 +135,11 @@ module ActiveRecord
137
135
 
138
136
  def inversed_from(record)
139
137
  self.target = record
140
- @inversed = !!record
141
138
  end
142
139
 
143
140
  def inversed_from_queries(record)
144
141
  if inversable?(record)
145
142
  self.target = record
146
- @inversed = true
147
- else
148
- @inversed = false
149
143
  end
150
144
  end
151
145
 
@@ -295,7 +289,7 @@ module ActiveRecord
295
289
 
296
290
  # Raises ActiveRecord::AssociationTypeMismatch unless +record+ is of
297
291
  # the kind of the class of the associated objects. Meant to be used as
298
- # a sanity check when you are about to assign an associated record.
292
+ # a safety check when you are about to assign an associated record.
299
293
  def raise_on_type_mismatch!(record)
300
294
  unless record.is_a?(reflection.klass)
301
295
  fresh_class = reflection.class_name.safe_constantize
@@ -30,11 +30,18 @@ module ActiveRecord::Associations::Builder # :nodoc:
30
30
  def self.define_callback(model, callback_name, name, options)
31
31
  full_callback_name = "#{callback_name}_for_#{name}"
32
32
 
33
- unless model.method_defined?(full_callback_name)
33
+ callback_values = Array(options[callback_name.to_sym])
34
+ method_defined = model.respond_to?(full_callback_name)
35
+
36
+ # If there are no callbacks, we must also check if a superclass had
37
+ # previously defined this association
38
+ return if callback_values.empty? && !method_defined
39
+
40
+ unless method_defined
34
41
  model.class_attribute(full_callback_name, instance_accessor: false, instance_predicate: false)
35
42
  end
36
43
 
37
- callbacks = Array(options[callback_name.to_sym]).map do |callback|
44
+ callbacks = callback_values.map do |callback|
38
45
  case callback
39
46
  when Symbol
40
47
  ->(method, owner, record) { owner.send(callback, record) }
@@ -335,7 +335,7 @@ module ActiveRecord
335
335
  end
336
336
  end
337
337
 
338
- persisted + memory
338
+ persisted + memory.reject(&:persisted?)
339
339
  end
340
340
 
341
341
  def _create_record(attributes, raise = false, &block)
@@ -456,6 +456,10 @@ module ActiveRecord
456
456
 
457
457
  yield(record) if block_given?
458
458
 
459
+ if !index && @replaced_or_added_targets.include?(record)
460
+ index = @target.index(record)
461
+ end
462
+
459
463
  @replaced_or_added_targets << record if inversing || index || record.new_record?
460
464
 
461
465
  if index
@@ -480,7 +484,11 @@ module ActiveRecord
480
484
 
481
485
  def callbacks_for(callback_name)
482
486
  full_callback_name = "#{callback_name}_for_#{reflection.name}"
483
- owner.class.send(full_callback_name)
487
+ if owner.class.respond_to?(full_callback_name)
488
+ owner.class.send(full_callback_name)
489
+ else
490
+ []
491
+ end
484
492
  end
485
493
 
486
494
  def include_in_memory?(record)