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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +504 -10
- data/lib/active_record/associations/association.rb +2 -8
- data/lib/active_record/associations/builder/collection_association.rb +9 -2
- data/lib/active_record/associations/collection_association.rb +10 -2
- data/lib/active_record/associations/preloader/association.rb +68 -48
- data/lib/active_record/associations/preloader/batch.rb +3 -6
- data/lib/active_record/associations/preloader/through_association.rb +19 -9
- data/lib/active_record/associations/preloader.rb +14 -24
- data/lib/active_record/associations/through_association.rb +2 -2
- data/lib/active_record/associations.rb +16 -3
- data/lib/active_record/asynchronous_queries_tracker.rb +3 -0
- data/lib/active_record/attribute_methods/dirty.rb +9 -1
- data/lib/active_record/attribute_methods.rb +7 -5
- data/lib/active_record/autosave_association.rb +3 -3
- data/lib/active_record/connection_adapters/abstract/connection_handler.rb +6 -26
- data/lib/active_record/connection_adapters/abstract/connection_pool/queue.rb +2 -2
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +18 -5
- data/lib/active_record/connection_adapters/abstract/database_limits.rb +0 -17
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +1 -1
- data/lib/active_record/connection_adapters/abstract/quoting.rb +33 -70
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +4 -0
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +9 -2
- data/lib/active_record/connection_adapters/abstract/transaction.rb +12 -19
- data/lib/active_record/connection_adapters/abstract_adapter.rb +37 -8
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +1 -0
- data/lib/active_record/connection_adapters/column.rb +4 -0
- data/lib/active_record/connection_adapters/mysql/database_statements.rb +2 -2
- data/lib/active_record/connection_adapters/mysql/quoting.rb +23 -24
- data/lib/active_record/connection_adapters/mysql/schema_statements.rb +1 -1
- data/lib/active_record/connection_adapters/pool_config.rb +7 -5
- data/lib/active_record/connection_adapters/postgresql/column.rb +17 -1
- data/lib/active_record/connection_adapters/postgresql/quoting.rb +44 -44
- data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +21 -1
- data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +18 -1
- data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +25 -0
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +15 -4
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +48 -5
- data/lib/active_record/connection_adapters/schema_cache.rb +3 -1
- data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +2 -2
- data/lib/active_record/connection_adapters/sqlite3/quoting.rb +15 -16
- data/lib/active_record/connection_handling.rb +31 -19
- data/lib/active_record/core.rb +13 -24
- data/lib/active_record/database_configurations/connection_url_resolver.rb +2 -1
- data/lib/active_record/database_configurations/database_config.rb +0 -9
- data/lib/active_record/database_configurations/hash_config.rb +40 -8
- data/lib/active_record/database_configurations.rb +2 -27
- data/lib/active_record/delegated_type.rb +19 -0
- data/lib/active_record/encryption/encrypted_attribute_type.rb +1 -1
- data/lib/active_record/encryption/extended_deterministic_uniqueness_validator.rb +1 -2
- data/lib/active_record/encryption/message_serializer.rb +11 -1
- data/lib/active_record/encryption/scheme.rb +1 -1
- data/lib/active_record/enum.rb +8 -1
- data/lib/active_record/errors.rb +1 -1
- data/lib/active_record/explain_registry.rb +11 -6
- data/lib/active_record/fixture_set/table_row.rb +1 -1
- data/lib/active_record/fixtures.rb +1 -9
- data/lib/active_record/future_result.rb +2 -2
- data/lib/active_record/gem_version.rb +1 -1
- data/lib/active_record/insert_all.rb +52 -15
- data/lib/active_record/integration.rb +3 -2
- data/lib/active_record/legacy_yaml_adapter.rb +2 -39
- data/lib/active_record/locking/pessimistic.rb +9 -3
- data/lib/active_record/log_subscriber.rb +8 -1
- data/lib/active_record/middleware/shard_selector.rb +60 -0
- data/lib/active_record/model_schema.rb +1 -28
- data/lib/active_record/nested_attributes.rb +11 -10
- data/lib/active_record/no_touching.rb +1 -1
- data/lib/active_record/persistence.rb +99 -21
- data/lib/active_record/query_logs.rb +18 -83
- data/lib/active_record/railtie.rb +11 -1
- data/lib/active_record/railties/databases.rake +4 -91
- data/lib/active_record/reflection.rb +22 -6
- data/lib/active_record/relation/calculations.rb +1 -10
- data/lib/active_record/relation/finder_methods.rb +0 -13
- data/lib/active_record/relation/query_methods.rb +5 -14
- data/lib/active_record/relation/record_fetch_warning.rb +5 -7
- data/lib/active_record/relation/where_clause.rb +2 -15
- data/lib/active_record/relation.rb +11 -13
- data/lib/active_record/result.rb +0 -5
- data/lib/active_record/runtime_registry.rb +10 -12
- data/lib/active_record/schema_dumper.rb +7 -0
- data/lib/active_record/scoping.rb +34 -22
- data/lib/active_record/suppressor.rb +11 -15
- data/lib/active_record/tasks/database_tasks.rb +18 -44
- data/lib/active_record/tasks/postgresql_database_tasks.rb +5 -1
- data/lib/active_record/validations/uniqueness.rb +1 -1
- data/lib/active_record.rb +41 -33
- data/lib/arel/crud.rb +12 -2
- data/lib/arel/delete_manager.rb +16 -0
- data/lib/arel/filter_predications.rb +9 -0
- data/lib/arel/nodes/delete_statement.rb +5 -1
- data/lib/arel/nodes/filter.rb +10 -0
- data/lib/arel/nodes/function.rb +1 -0
- data/lib/arel/nodes/update_statement.rb +5 -1
- data/lib/arel/nodes.rb +1 -0
- data/lib/arel/predications.rb +10 -2
- data/lib/arel/update_manager.rb +16 -0
- data/lib/arel/visitors/mysql.rb +2 -1
- data/lib/arel/visitors/to_sql.rb +15 -0
- data/lib/arel.rb +1 -0
- metadata +14 -10
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: c1a1968982fd2d7c0361ac7cfa9241a02c4ff558cc8fba93545800194274ac90
|
4
|
+
data.tar.gz: e19875a1df942ea1488aff91d0026e8584945504b14f9021660a1b55831f2ad2
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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
|
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
|
-
|
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
|
-
|
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
|
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
|
-
|
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 =
|
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.
|
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)
|