activerecord 7.0.0 → 7.0.4

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 (90) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +357 -0
  3. data/MIT-LICENSE +1 -1
  4. data/lib/active_record/associations/collection_association.rb +1 -2
  5. data/lib/active_record/associations/collection_proxy.rb +2 -2
  6. data/lib/active_record/associations/has_many_association.rb +7 -4
  7. data/lib/active_record/associations/join_dependency.rb +17 -13
  8. data/lib/active_record/associations.rb +38 -17
  9. data/lib/active_record/attribute_methods/serialization.rb +34 -50
  10. data/lib/active_record/attribute_methods/time_zone_conversion.rb +4 -0
  11. data/lib/active_record/attribute_methods.rb +2 -2
  12. data/lib/active_record/autosave_association.rb +2 -2
  13. data/lib/active_record/base.rb +3 -3
  14. data/lib/active_record/coders/yaml_column.rb +10 -2
  15. data/lib/active_record/connection_adapters/abstract/connection_handler.rb +1 -1
  16. data/lib/active_record/connection_adapters/abstract/quoting.rb +1 -1
  17. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +8 -4
  18. data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +14 -1
  19. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +12 -7
  20. data/lib/active_record/connection_adapters/abstract_adapter.rb +5 -5
  21. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +10 -2
  22. data/lib/active_record/connection_adapters/mysql/database_statements.rb +1 -1
  23. data/lib/active_record/connection_adapters/mysql/quoting.rb +3 -1
  24. data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +7 -1
  25. data/lib/active_record/connection_adapters/mysql/schema_statements.rb +20 -1
  26. data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +2 -2
  27. data/lib/active_record/connection_adapters/postgresql/oid/timestamp_with_time_zone.rb +2 -0
  28. data/lib/active_record/connection_adapters/postgresql/quoting.rb +1 -1
  29. data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +3 -1
  30. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +10 -3
  31. data/lib/active_record/connection_adapters/postgresql_adapter.rb +6 -5
  32. data/lib/active_record/connection_adapters/sqlite3/quoting.rb +13 -0
  33. data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +14 -14
  34. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +35 -2
  35. data/lib/active_record/connection_handling.rb +2 -2
  36. data/lib/active_record/core.rb +3 -3
  37. data/lib/active_record/database_configurations/connection_url_resolver.rb +1 -0
  38. data/lib/active_record/database_configurations.rb +1 -1
  39. data/lib/active_record/delegated_type.rb +1 -1
  40. data/lib/active_record/encryption/configurable.rb +9 -3
  41. data/lib/active_record/encryption/contexts.rb +3 -3
  42. data/lib/active_record/encryption/derived_secret_key_provider.rb +1 -1
  43. data/lib/active_record/encryption/deterministic_key_provider.rb +1 -1
  44. data/lib/active_record/encryption/encryptable_record.rb +2 -4
  45. data/lib/active_record/encryption/encrypted_attribute_type.rb +2 -2
  46. data/lib/active_record/encryption/encryptor.rb +7 -7
  47. data/lib/active_record/encryption/envelope_encryption_key_provider.rb +3 -3
  48. data/lib/active_record/encryption/extended_deterministic_queries.rb +28 -28
  49. data/lib/active_record/encryption/message.rb +1 -1
  50. data/lib/active_record/encryption/properties.rb +1 -1
  51. data/lib/active_record/encryption/scheme.rb +1 -1
  52. data/lib/active_record/enum.rb +1 -1
  53. data/lib/active_record/fixtures.rb +5 -5
  54. data/lib/active_record/gem_version.rb +2 -2
  55. data/lib/active_record/integration.rb +2 -2
  56. data/lib/active_record/locking/pessimistic.rb +3 -3
  57. data/lib/active_record/log_subscriber.rb +10 -5
  58. data/lib/active_record/middleware/database_selector.rb +13 -6
  59. data/lib/active_record/middleware/shard_selector.rb +4 -4
  60. data/lib/active_record/migration/command_recorder.rb +3 -3
  61. data/lib/active_record/migration/compatibility.rb +10 -7
  62. data/lib/active_record/migration.rb +6 -5
  63. data/lib/active_record/model_schema.rb +22 -10
  64. data/lib/active_record/persistence.rb +9 -8
  65. data/lib/active_record/querying.rb +1 -1
  66. data/lib/active_record/railtie.rb +22 -18
  67. data/lib/active_record/railties/databases.rake +16 -11
  68. data/lib/active_record/reflection.rb +7 -1
  69. data/lib/active_record/relation/batches.rb +3 -3
  70. data/lib/active_record/relation/calculations.rb +3 -2
  71. data/lib/active_record/relation/delegation.rb +1 -1
  72. data/lib/active_record/relation/query_methods.rb +46 -11
  73. data/lib/active_record/relation.rb +22 -6
  74. data/lib/active_record/sanitization.rb +6 -5
  75. data/lib/active_record/schema.rb +38 -23
  76. data/lib/active_record/schema_dumper.rb +15 -16
  77. data/lib/active_record/scoping/default.rb +5 -7
  78. data/lib/active_record/serialization.rb +5 -0
  79. data/lib/active_record/signed_id.rb +2 -2
  80. data/lib/active_record/store.rb +7 -2
  81. data/lib/active_record/tasks/database_tasks.rb +32 -23
  82. data/lib/active_record/tasks/postgresql_database_tasks.rb +1 -2
  83. data/lib/active_record/test_fixtures.rb +12 -5
  84. data/lib/active_record/translation.rb +1 -1
  85. data/lib/active_record/validations/associated.rb +3 -3
  86. data/lib/active_record/validations/presence.rb +2 -2
  87. data/lib/active_record/validations/uniqueness.rb +3 -3
  88. data/lib/active_record/version.rb +1 -1
  89. data/lib/active_record.rb +15 -1
  90. metadata +13 -13
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: ebfa716fe92ae11e586b89a89661980f107b3501dcbc64be179a191645046e2a
4
- data.tar.gz: 0eb8e39ca0252342714ad4791d5a17127697a7047b4ed2c7d48a867774f8470b
3
+ metadata.gz: 18986b8f256d988204ff7b48287980a88e138a4280d637cf28310e551082987d
4
+ data.tar.gz: 8054f80c87f48a264d08f006b789e2c3680155e0ed7fb5a5698d962f7ff0d8bb
5
5
  SHA512:
6
- metadata.gz: 74365d846a7f543a82e61c3784aad30dd1de0e2a43e09ed4459a4b7b0fe9a14839a53122e12536c63d3bdcb638391390b83e6ffa4eb6a09f8713e1986674cda9
7
- data.tar.gz: a1379b0d243f97f6827df6ff2af3a7936164ad57ad60ded0aac71aeb45def6d7cee19571de89f8d93eeeaabfc6d193b9695879b8dac5c9f7d473e85617d15bea
6
+ metadata.gz: 8a01f7c0f730da3cfc0bfcda6f7c9a2e3f4d2747137f87175671d79021643f09f34fcf373cb400f247159d6551589f51de73241f10ac3373159865db6e04f0fc
7
+ data.tar.gz: a4aa9659e71f1e8c11914727eacd07061128f8d68b0f609c08b272025c9923419a3a58f6d789da6a467258cad69795e3e0aa265f34ffcce4b39d8bd0cb5d8386
data/CHANGELOG.md CHANGED
@@ -1,3 +1,358 @@
1
+ ## Rails 7.0.4 (September 09, 2022) ##
2
+
3
+ * Symbol is allowed by default for YAML columns
4
+
5
+ *Étienne Barrié*
6
+
7
+ * Fix `ActiveRecord::Store` to serialize as a regular Hash
8
+
9
+ Previously it would serialize as an `ActiveSupport::HashWithIndifferentAccess`
10
+ which is wasteful and cause problem with YAML safe_load.
11
+
12
+ *Jean Boussier*
13
+
14
+ * Add `timestamptz` as a time zone aware type for PostgreSQL
15
+
16
+ This is required for correctly parsing `timestamp with time zone` values in your database.
17
+
18
+ If you don't want this, you can opt out by adding this initializer:
19
+
20
+ ```ruby
21
+ ActiveRecord::Base.time_zone_aware_types -= [:timestamptz]
22
+ ```
23
+
24
+ *Alex Ghiculescu*
25
+
26
+ * Fix supporting timezone awareness for `tsrange` and `tstzrange` array columns.
27
+
28
+ ```ruby
29
+ # In database migrations
30
+ add_column :shops, :open_hours, :tsrange, array: true
31
+ # In app config
32
+ ActiveRecord::Base.time_zone_aware_types += [:tsrange]
33
+ # In the code times are properly converted to app time zone
34
+ Shop.create!(open_hours: [Time.current..8.hour.from_now])
35
+ ```
36
+
37
+ *Wojciech Wnętrzak*
38
+
39
+ * Resolve issue where a relation cache_version could be left stale.
40
+
41
+ Previously, when `reset` was called on a relation object it did not reset the cache_versions
42
+ ivar. This led to a confusing situation where despite having the correct data the relation
43
+ still reported a stale cache_version.
44
+
45
+ Usage:
46
+
47
+ ```ruby
48
+ developers = Developer.all
49
+ developers.cache_version
50
+
51
+ Developer.update_all(updated_at: Time.now.utc + 1.second)
52
+
53
+ developers.cache_version # Stale cache_version
54
+ developers.reset
55
+ developers.cache_version # Returns the current correct cache_version
56
+ ```
57
+
58
+ Fixes #45341.
59
+
60
+ *Austen Madden*
61
+
62
+ * Fix `load_async` when called on an association proxy.
63
+
64
+ Calling `load_async` directly an association would schedule
65
+ a query but never use it.
66
+
67
+ ```ruby
68
+ comments = post.comments.load_async # schedule a query
69
+ comments.to_a # perform an entirely new sync query
70
+ ```
71
+
72
+ Now it does use the async query, however note that it doesn't
73
+ cause the association to be loaded.
74
+
75
+ *Jean Boussier*
76
+
77
+ * Fix eager loading for models without primary keys.
78
+
79
+ *Anmol Chopra*, *Matt Lawrence*, and *Jonathan Hefner*
80
+
81
+ * `rails db:schema:{dump,load}` now checks `ENV["SCHEMA_FORMAT"]` before config
82
+
83
+ Since `rails db:structure:{dump,load}` was deprecated there wasn't a simple
84
+ way to dump a schema to both SQL and Ruby formats. You can now do this with
85
+ an environment variable. For example:
86
+
87
+ ```
88
+ SCHEMA_FORMAT=sql rake db:schema:dump
89
+ ```
90
+
91
+ *Alex Ghiculescu*
92
+
93
+ * Fix Hstore deserialize regression.
94
+
95
+ *edsharp*
96
+
97
+
98
+ ## Rails 7.0.3.1 (July 12, 2022) ##
99
+
100
+ * Change ActiveRecord::Coders::YAMLColumn default to safe_load
101
+
102
+ This adds two new configuration options The configuration options are as
103
+ follows:
104
+
105
+ * `config.active_storage.use_yaml_unsafe_load`
106
+
107
+ When set to true, this configuration option tells Rails to use the old
108
+ "unsafe" YAML loading strategy, maintaining the existing behavior but leaving
109
+ the possible escalation vulnerability in place. Setting this option to true
110
+ is *not* recommended, but can aid in upgrading.
111
+
112
+ * `config.active_record.yaml_column_permitted_classes`
113
+
114
+ The "safe YAML" loading method does not allow all classes to be deserialized
115
+ by default. This option allows you to specify classes deemed "safe" in your
116
+ application. For example, if your application uses Symbol and Time in
117
+ serialized data, you can add Symbol and Time to the allowed list as follows:
118
+
119
+ ```
120
+ config.active_record.yaml_column_permitted_classes = [Symbol, Date, Time]
121
+ ```
122
+
123
+ [CVE-2022-32224]
124
+
125
+
126
+ ## Rails 7.0.3 (May 09, 2022) ##
127
+
128
+ * Some internal housekeeping on reloads could break custom `respond_to?`
129
+ methods in class objects that referenced reloadable constants. See
130
+ [#44125](https://github.com/rails/rails/issues/44125) for details.
131
+
132
+ *Xavier Noria*
133
+
134
+ * Fixed MariaDB default function support.
135
+
136
+ Defaults would be written wrong in "db/schema.rb" and not work correctly
137
+ if using `db:schema:load`. Further more the function name would be
138
+ added as string content when saving new records.
139
+
140
+ *kaspernj*
141
+
142
+ * Fix `remove_foreign_key` with `:if_exists` option when foreign key actually exists.
143
+
144
+ *fatkodima*
145
+
146
+ * Remove `--no-comments` flag in structure dumps for PostgreSQL
147
+
148
+ This broke some apps that used custom schema comments. If you don't want
149
+ comments in your structure dump, you can use:
150
+
151
+ ```ruby
152
+ ActiveRecord::Tasks::DatabaseTasks.structure_dump_flags = ['--no-comments']
153
+ ```
154
+
155
+ *Alex Ghiculescu*
156
+
157
+ * Use the model name as a prefix when filtering encrypted attributes from logs.
158
+
159
+ For example, when encrypting `Person#name` it will add `person.name` as a filter
160
+ parameter, instead of just `name`. This prevents unintended filtering of parameters
161
+ with a matching name in other models.
162
+
163
+ *Jorge Manrubia*
164
+
165
+ * Fix quoting of `ActiveSupport::Duration` and `Rational` numbers in the MySQL adapter.
166
+
167
+ *Kevin McPhillips*
168
+
169
+ * Fix `change_column_comment` to preserve column's AUTO_INCREMENT in the MySQL adapter
170
+
171
+ *fatkodima*
172
+
173
+ ## Rails 7.0.2.4 (April 26, 2022) ##
174
+
175
+ * No changes.
176
+
177
+
178
+ ## Rails 7.0.2.3 (March 08, 2022) ##
179
+
180
+ * No changes.
181
+
182
+
183
+ ## Rails 7.0.2.2 (February 11, 2022) ##
184
+
185
+ * No changes.
186
+
187
+
188
+ ## Rails 7.0.2.1 (February 11, 2022) ##
189
+
190
+ * No changes.
191
+
192
+
193
+ ## Rails 7.0.2 (February 08, 2022) ##
194
+
195
+ * Fix `PG.connect` keyword arguments deprecation warning on ruby 2.7.
196
+
197
+ *Nikita Vasilevsky*
198
+
199
+ * Fix the ability to exclude encryption params from being autofiltered.
200
+
201
+ *Mark Gangl*
202
+
203
+ * Dump the precision for datetime columns following the new defaults.
204
+
205
+ *Rafael Mendonça França*
206
+
207
+ * Make sure encrypted attributes are not being filtered twice.
208
+
209
+ *Nikita Vasilevsky*
210
+
211
+ * Dump the database schema containing the current Rails version.
212
+
213
+ Since https://github.com/rails/rails/pull/42297, Rails now generate datetime columns
214
+ with a default precision of 6. This means that users upgrading to Rails 7.0 from 6.1,
215
+ when loading the database schema, would get the new precision value, which would not match
216
+ the production schema.
217
+
218
+ To avoid this the schema dumper will generate the new format which will include the Rails
219
+ version and will look like this:
220
+
221
+ ```
222
+ ActiveRecord::Schema[7.0].define
223
+ ```
224
+
225
+ When upgrading from Rails 6.1 to Rails 7.0, you can run the `rails app:update` task that will
226
+ set the current schema version to 6.1.
227
+
228
+ *Rafael Mendonça França*
229
+
230
+ * Fix parsing expression for PostgreSQL generated column.
231
+
232
+ *fatkodima*
233
+
234
+ * Fix `Mysql2::Error: Commands out of sync; you can't run this command now`
235
+ when bulk-inserting fixtures that exceed `max_allowed_packet` configuration.
236
+
237
+ *Nikita Vasilevsky*
238
+
239
+ * Fix error when saving an association with a relation named `record`.
240
+
241
+ *Dorian Marié*
242
+
243
+ * Fix `MySQL::SchemaDumper` behavior about datetime precision value.
244
+
245
+ *y0t4*
246
+
247
+ * Improve associated with no reflection error.
248
+
249
+ *Nikolai*
250
+
251
+ * Fix PG.connect keyword arguments deprecation warning on ruby 2.7.
252
+
253
+ Fixes #44307.
254
+
255
+ *Nikita Vasilevsky*
256
+
257
+ * Fix passing options to `check_constraint` from `change_table`.
258
+
259
+ *Frederick Cheung*
260
+
261
+
262
+ ## Rails 7.0.1 (January 06, 2022) ##
263
+
264
+
265
+ * Change `QueryMethods#in_order_of` to drop records not listed in values.
266
+
267
+ `in_order_of` now filters down to the values provided, to match the behavior of the `Enumerable` version.
268
+
269
+ *Kevin Newton*
270
+
271
+ * Allow named expression indexes to be revertible.
272
+
273
+ 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.
274
+
275
+ ```ruby
276
+ add_index(:settings, "(data->'property')", using: :gin, name: :index_settings_data_property)
277
+ ```
278
+
279
+ Fixes #43331.
280
+
281
+ *Oliver Günther*
282
+
283
+ * Better error messages when association name is invalid in the argument of `ActiveRecord::QueryMethods::WhereChain#missing`.
284
+
285
+ *ykpythemind*
286
+
287
+ * Fix ordered migrations for single db in multi db environment.
288
+
289
+ *Himanshu*
290
+
291
+ * Extract `on update CURRENT_TIMESTAMP` for mysql2 adapter.
292
+
293
+ *Kazuhiro Masuda*
294
+
295
+ * Fix incorrect argument in PostgreSQL structure dump tasks.
296
+
297
+ Updating the `--no-comment` argument added in Rails 7 to the correct `--no-comments` argument.
298
+
299
+ *Alex Dent*
300
+
301
+ * Fix schema dumping column default SQL values for sqlite3.
302
+
303
+ *fatkodima*
304
+
305
+ * Correctly parse complex check constraint expressions for PostgreSQL.
306
+
307
+ *fatkodima*
308
+
309
+ * Fix `timestamptz` attributes on PostgreSQL handle blank inputs.
310
+
311
+ *Alex Ghiculescu*
312
+
313
+ * Fix migration compatibility to create SQLite references/belongs_to column as integer when migration version is 6.0.
314
+
315
+ Reference/belongs_to in migrations with version 6.0 were creating columns as
316
+ bigint instead of integer for the SQLite Adapter.
317
+
318
+ *Marcelo Lauxen*
319
+
320
+ * Fix joining through a polymorphic association.
321
+
322
+ *Alexandre Ruban*
323
+
324
+ * Fix `QueryMethods#in_order_of` to handle empty order list.
325
+
326
+ ```ruby
327
+ Post.in_order_of(:id, []).to_a
328
+ ```
329
+
330
+ Also more explicitly set the column as secondary order, so that any other
331
+ value is still ordered.
332
+
333
+ *Jean Boussier*
334
+
335
+ * Fix `rails dbconsole` for 3-tier config.
336
+
337
+ *Eileen M. Uchitelle*
338
+
339
+ * Fix quoting of column aliases generated by calculation methods.
340
+
341
+ Since the alias is derived from the table name, we can't assume the result
342
+ is a valid identifier.
343
+
344
+ ```ruby
345
+ class Test < ActiveRecord::Base
346
+ self.table_name = '1abc'
347
+ end
348
+ Test.group(:id).count
349
+ # syntax error at or near "1" (ActiveRecord::StatementInvalid)
350
+ # LINE 1: SELECT COUNT(*) AS count_all, "1abc"."id" AS 1abc_id FROM "1...
351
+ ```
352
+
353
+ *Jean Boussier*
354
+
355
+
1
356
  ## Rails 7.0.0 (December 15, 2021) ##
2
357
 
3
358
  * Better handle SQL queries with invalid encoding.
@@ -20,6 +375,7 @@
20
375
 
21
376
  *Eileen M. Uchitelle*
22
377
 
378
+
23
379
  ## Rails 7.0.0.rc3 (December 14, 2021) ##
24
380
 
25
381
  * No changes.
@@ -29,6 +385,7 @@
29
385
 
30
386
  * No changes.
31
387
 
388
+
32
389
  ## Rails 7.0.0.rc1 (December 06, 2021) ##
33
390
 
34
391
  * Remove deprecated `ActiveRecord::DatabaseConfigurations::DatabaseConfig#spec_name`.
data/MIT-LICENSE CHANGED
@@ -1,4 +1,4 @@
1
- Copyright (c) 2004-2021 David Heinemeier Hansson
1
+ Copyright (c) 2004-2022 David Heinemeier Hansson
2
2
 
3
3
  Arel originally copyright (c) 2007-2016 Nick Kallen, Bryan Helmkamp, Emilio Tagua, Aaron Patterson
4
4
 
@@ -180,7 +180,7 @@ module ActiveRecord
180
180
  end
181
181
 
182
182
  # Deletes the +records+ and removes them from this association calling
183
- # +before_remove+ , +after_remove+ , +before_destroy+ and +after_destroy+ callbacks.
183
+ # +before_remove+, +after_remove+, +before_destroy+ and +after_destroy+ callbacks.
184
184
  #
185
185
  # Note that this method removes records from the database ignoring the
186
186
  # +:dependent+ option.
@@ -320,7 +320,6 @@ module ActiveRecord
320
320
  # * Otherwise, attributes should have the value found in the database
321
321
  def merge_target_lists(persisted, memory)
322
322
  return persisted if memory.empty?
323
- return memory if persisted.empty?
324
323
 
325
324
  persisted.map! do |record|
326
325
  if mem_record = memory.delete(record)
@@ -475,7 +475,7 @@ module ActiveRecord
475
475
 
476
476
  # Deletes the records of the collection directly from the database
477
477
  # ignoring the +:dependent+ option. Records are instantiated and it
478
- # invokes +before_remove+, +after_remove+ , +before_destroy+ and
478
+ # invokes +before_remove+, +after_remove+, +before_destroy+, and
479
479
  # +after_destroy+ callbacks.
480
480
  #
481
481
  # class Person < ActiveRecord::Base
@@ -1108,7 +1108,7 @@ module ActiveRecord
1108
1108
  ].flat_map { |klass|
1109
1109
  klass.public_instance_methods(false)
1110
1110
  } - self.public_instance_methods(false) - [:select] + [
1111
- :scoping, :values, :insert, :insert_all, :insert!, :insert_all!, :upsert, :upsert_all
1111
+ :scoping, :values, :insert, :insert_all, :insert!, :insert_all!, :upsert, :upsert_all, :load_async
1112
1112
  ]
1113
1113
 
1114
1114
  delegate(*delegate_methods, to: :scope)
@@ -79,10 +79,13 @@ module ActiveRecord
79
79
  scope.count(:all)
80
80
  end
81
81
 
82
- # If there's nothing in the database and @target has no new records
83
- # we are certain the current target is an empty array. This is a
84
- # documented side-effect of the method that may avoid an extra SELECT.
85
- loaded! if count == 0
82
+ # If there's nothing in the database, @target should only contain new
83
+ # records or be an empty array. This is a documented side-effect of
84
+ # the method that may avoid an extra SELECT.
85
+ if count == 0
86
+ target.select!(&:new_record?)
87
+ loaded!
88
+ end
86
89
 
87
90
  [association_scope.limit_value, count].compact.min
88
91
  end
@@ -252,35 +252,39 @@ module ActiveRecord
252
252
  next
253
253
  end
254
254
 
255
- key = aliases.column_alias(node, node.primary_key)
256
- id = row[key]
257
- if id.nil?
255
+ if node.primary_key
256
+ key = aliases.column_alias(node, node.primary_key)
257
+ id = row[key]
258
+ else
259
+ key = aliases.column_alias(node, node.reflection.join_primary_key.to_s)
260
+ id = nil # Avoid id-based model caching.
261
+ end
262
+
263
+ if row[key].nil?
258
264
  nil_association = ar_parent.association(node.reflection.name)
259
265
  nil_association.loaded!
260
266
  next
261
267
  end
262
268
 
263
- model = seen[ar_parent][node][id]
264
-
265
- if model
266
- construct(model, node, row, seen, model_cache, strict_loading_value)
267
- else
269
+ unless model = seen[ar_parent][node][id]
268
270
  model = construct_model(ar_parent, node, row, model_cache, id, strict_loading_value)
269
-
270
- seen[ar_parent][node][id] = model
271
- construct(model, node, row, seen, model_cache, strict_loading_value)
271
+ seen[ar_parent][node][id] = model if id
272
272
  end
273
+
274
+ construct(model, node, row, seen, model_cache, strict_loading_value)
273
275
  end
274
276
  end
275
277
 
276
278
  def construct_model(record, node, row, model_cache, id, strict_loading_value)
277
279
  other = record.association(node.reflection.name)
278
280
 
279
- model = model_cache[node][id] ||=
280
- node.instantiate(row, aliases.column_aliases(node)) do |m|
281
+ unless model = model_cache[node][id]
282
+ model = node.instantiate(row, aliases.column_aliases(node)) do |m|
281
283
  m.strict_loading! if strict_loading_value
282
284
  other.set_inverse_instance(m)
283
285
  end
286
+ model_cache[node][id] = model if id
287
+ end
284
288
 
285
289
  if node.reflection.collection?
286
290
  other.target.push(model)
@@ -290,6 +290,7 @@ module ActiveRecord
290
290
  def self.eager_load!
291
291
  super
292
292
  Preloader.eager_load!
293
+ JoinDependency.eager_load!
293
294
  end
294
295
 
295
296
  # Returns the association instance for the given name, instantiating it if it doesn't already exist
@@ -431,7 +432,7 @@ module ActiveRecord
431
432
  #
432
433
  # == Cardinality and associations
433
434
  #
434
- # Active Record associations can be used to describe one-to-one, one-to-many and many-to-many
435
+ # Active Record associations can be used to describe one-to-one, one-to-many, and many-to-many
435
436
  # relationships between models. Each model uses an association to describe its role in
436
437
  # the relation. The #belongs_to association is always used in the model that has
437
438
  # the foreign key.
@@ -585,7 +586,7 @@ module ActiveRecord
585
586
  # has_many :birthday_events, ->(user) { where(starts_on: user.birthday) }, class_name: 'Event'
586
587
  # end
587
588
  #
588
- # Note: Joining, eager loading and preloading of these associations is not possible.
589
+ # Note: Joining, eager loading, and preloading of these associations is not possible.
589
590
  # These operations happen before instance creation and the scope will be called with a +nil+ argument.
590
591
  #
591
592
  # == Association callbacks
@@ -594,22 +595,30 @@ module ActiveRecord
594
595
  # you can also define callbacks that get triggered when you add an object to or remove an
595
596
  # object from an association collection.
596
597
  #
597
- # class Project
598
- # has_and_belongs_to_many :developers, after_add: :evaluate_velocity
598
+ # class Firm < ActiveRecord::Base
599
+ # has_many :clients,
600
+ # dependent: :destroy,
601
+ # after_add: :congratulate_client,
602
+ # after_remove: :log_after_remove
599
603
  #
600
- # def evaluate_velocity(developer)
601
- # ...
604
+ # def congratulate_client(record)
605
+ # # ...
606
+ # end
607
+ #
608
+ # def log_after_remove(record)
609
+ # # ...
602
610
  # end
603
- # end
604
611
  #
605
612
  # It's possible to stack callbacks by passing them as an array. Example:
606
613
  #
607
- # class Project
608
- # has_and_belongs_to_many :developers,
609
- # after_add: [:evaluate_velocity, Proc.new { |p, d| p.shipping_date = Time.now}]
614
+ # class Firm < ActiveRecord::Base
615
+ # has_many :clients,
616
+ # dependent: :destroy,
617
+ # after_add: [:congratulate_client, -> (firm, record) { firm.log << "after_adding#{record.id}" }],
618
+ # after_remove: :log_after_remove
610
619
  # end
611
620
  #
612
- # Possible callbacks are: +before_add+, +after_add+, +before_remove+ and +after_remove+.
621
+ # Possible callbacks are: +before_add+, +after_add+, +before_remove+, and +after_remove+.
613
622
  #
614
623
  # If any of the +before_add+ callbacks throw an exception, the object will not be
615
624
  # added to the collection.
@@ -617,6 +626,18 @@ module ActiveRecord
617
626
  # Similarly, if any of the +before_remove+ callbacks throw an exception, the object
618
627
  # will not be removed from the collection.
619
628
  #
629
+ # Note: To trigger remove callbacks, you must use +destroy+ / +destroy_all+ methods. For example:
630
+ #
631
+ # * <tt>firm.clients.destroy(client)</tt>
632
+ # * <tt>firm.clients.destroy(*clients)</tt>
633
+ # * <tt>firm.clients.destroy_all</tt>
634
+ #
635
+ # +delete+ / +delete_all+ methods like the following do *not* trigger remove callbacks:
636
+ #
637
+ # * <tt>firm.clients.delete(client)</tt>
638
+ # * <tt>firm.clients.delete(*clients)</tt>
639
+ # * <tt>firm.clients.delete_all</tt>
640
+ #
620
641
  # == Association extensions
621
642
  #
622
643
  # The proxy objects that control the access to associations can be extended through anonymous
@@ -1311,7 +1332,7 @@ module ActiveRecord
1311
1332
  # === Extensions
1312
1333
  #
1313
1334
  # The +extension+ argument allows you to pass a block into a has_many
1314
- # association. This is useful for adding new finders, creators and other
1335
+ # association. This is useful for adding new finders, creators, and other
1315
1336
  # factory-type methods to be used as part of the association.
1316
1337
  #
1317
1338
  # Extension examples:
@@ -1394,8 +1415,8 @@ module ActiveRecord
1394
1415
  # [:disable_joins]
1395
1416
  # Specifies whether joins should be skipped for an association. If set to true, two or more queries
1396
1417
  # will be generated. Note that in some cases, if order or limit is applied, it will be done in-memory
1397
- # due to database limitations. This option is only applicable on `has_many :through` associations as
1398
- # `has_many` alone do not perform a join.
1418
+ # due to database limitations. This option is only applicable on <tt>has_many :through</tt> associations as
1419
+ # +has_many+ alone do not perform a join.
1399
1420
  # [:source]
1400
1421
  # Specifies the source association name used by #has_many <tt>:through</tt> queries.
1401
1422
  # Only use it if the name cannot be inferred from the association.
@@ -1559,8 +1580,8 @@ module ActiveRecord
1559
1580
  # [:disable_joins]
1560
1581
  # Specifies whether joins should be skipped for an association. If set to true, two or more queries
1561
1582
  # will be generated. Note that in some cases, if order or limit is applied, it will be done in-memory
1562
- # due to database limitations. This option is only applicable on `has_one :through` associations as
1563
- # `has_one` alone does not perform a join.
1583
+ # due to database limitations. This option is only applicable on <tt>has_one :through</tt> associations as
1584
+ # +has_one+ alone does not perform a join.
1564
1585
  # [:source]
1565
1586
  # Specifies the source association name used by #has_one <tt>:through</tt> queries.
1566
1587
  # Only use it if the name cannot be inferred from the association.
@@ -1883,7 +1904,7 @@ module ActiveRecord
1883
1904
  #
1884
1905
  # The +extension+ argument allows you to pass a block into a
1885
1906
  # has_and_belongs_to_many association. This is useful for adding new
1886
- # finders, creators and other factory-type methods to be used as part of
1907
+ # finders, creators, and other factory-type methods to be used as part of
1887
1908
  # the association.
1888
1909
  #
1889
1910
  # Extension examples: