activerecord 7.0.2.4 → 7.0.4

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 (75) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +172 -0
  3. data/lib/active_record/associations/collection_association.rb +1 -2
  4. data/lib/active_record/associations/collection_proxy.rb +2 -2
  5. data/lib/active_record/associations/has_many_association.rb +7 -4
  6. data/lib/active_record/associations/join_dependency.rb +17 -13
  7. data/lib/active_record/associations.rb +15 -15
  8. data/lib/active_record/attribute_methods/serialization.rb +34 -50
  9. data/lib/active_record/attribute_methods/time_zone_conversion.rb +4 -0
  10. data/lib/active_record/attribute_methods.rb +1 -1
  11. data/lib/active_record/base.rb +3 -3
  12. data/lib/active_record/coders/yaml_column.rb +10 -2
  13. data/lib/active_record/connection_adapters/abstract/connection_handler.rb +1 -1
  14. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +4 -0
  15. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +3 -3
  16. data/lib/active_record/connection_adapters/abstract_adapter.rb +5 -5
  17. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +9 -1
  18. data/lib/active_record/connection_adapters/mysql/quoting.rb +3 -1
  19. data/lib/active_record/connection_adapters/mysql/schema_statements.rb +19 -1
  20. data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +2 -2
  21. data/lib/active_record/connection_adapters/postgresql/quoting.rb +1 -1
  22. data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +3 -1
  23. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +2 -0
  24. data/lib/active_record/connection_adapters/postgresql_adapter.rb +4 -3
  25. data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +2 -2
  26. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +7 -2
  27. data/lib/active_record/connection_handling.rb +2 -2
  28. data/lib/active_record/core.rb +3 -3
  29. data/lib/active_record/delegated_type.rb +1 -1
  30. data/lib/active_record/encryption/configurable.rb +8 -2
  31. data/lib/active_record/encryption/contexts.rb +3 -3
  32. data/lib/active_record/encryption/derived_secret_key_provider.rb +1 -1
  33. data/lib/active_record/encryption/deterministic_key_provider.rb +1 -1
  34. data/lib/active_record/encryption/encryptable_record.rb +2 -4
  35. data/lib/active_record/encryption/encrypted_attribute_type.rb +2 -2
  36. data/lib/active_record/encryption/encryptor.rb +7 -7
  37. data/lib/active_record/encryption/envelope_encryption_key_provider.rb +3 -3
  38. data/lib/active_record/encryption/extended_deterministic_queries.rb +4 -4
  39. data/lib/active_record/encryption/message.rb +1 -1
  40. data/lib/active_record/encryption/properties.rb +1 -1
  41. data/lib/active_record/encryption/scheme.rb +1 -1
  42. data/lib/active_record/enum.rb +1 -1
  43. data/lib/active_record/fixtures.rb +4 -4
  44. data/lib/active_record/gem_version.rb +3 -3
  45. data/lib/active_record/locking/pessimistic.rb +3 -3
  46. data/lib/active_record/log_subscriber.rb +10 -5
  47. data/lib/active_record/middleware/database_selector.rb +13 -6
  48. data/lib/active_record/middleware/shard_selector.rb +4 -4
  49. data/lib/active_record/migration/command_recorder.rb +3 -3
  50. data/lib/active_record/migration/compatibility.rb +7 -26
  51. data/lib/active_record/migration.rb +5 -4
  52. data/lib/active_record/model_schema.rb +22 -10
  53. data/lib/active_record/persistence.rb +9 -8
  54. data/lib/active_record/querying.rb +1 -1
  55. data/lib/active_record/railtie.rb +20 -16
  56. data/lib/active_record/railties/databases.rake +16 -11
  57. data/lib/active_record/reflection.rb +6 -0
  58. data/lib/active_record/relation/batches.rb +3 -3
  59. data/lib/active_record/relation/query_methods.rb +27 -6
  60. data/lib/active_record/relation.rb +7 -6
  61. data/lib/active_record/sanitization.rb +6 -5
  62. data/lib/active_record/scoping/default.rb +5 -7
  63. data/lib/active_record/serialization.rb +5 -0
  64. data/lib/active_record/signed_id.rb +2 -2
  65. data/lib/active_record/store.rb +7 -2
  66. data/lib/active_record/tasks/database_tasks.rb +26 -21
  67. data/lib/active_record/tasks/postgresql_database_tasks.rb +1 -2
  68. data/lib/active_record/test_fixtures.rb +12 -5
  69. data/lib/active_record/translation.rb +1 -1
  70. data/lib/active_record/validations/associated.rb +3 -3
  71. data/lib/active_record/validations/presence.rb +2 -2
  72. data/lib/active_record/validations/uniqueness.rb +3 -3
  73. data/lib/active_record/version.rb +1 -1
  74. data/lib/active_record.rb +14 -0
  75. metadata +10 -10
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: e29d479c2e518da1d71d9d4af8fd0a29f3d525c76b8b6da432bf92b4f3fc5937
4
- data.tar.gz: 6ae42cea0de42d900282043d6f8b46d32063afc1e7b07c62e709bdb4790b9098
3
+ metadata.gz: 18986b8f256d988204ff7b48287980a88e138a4280d637cf28310e551082987d
4
+ data.tar.gz: 8054f80c87f48a264d08f006b789e2c3680155e0ed7fb5a5698d962f7ff0d8bb
5
5
  SHA512:
6
- metadata.gz: 68b23c7d23af6259f29df0bcdde5c3cd16d2a9912c6984cfdc490eedf7b607925282d99e26291d4685e13962a33d358d2044dce7fd13dbed25cb4ae988cb371b
7
- data.tar.gz: 28bddb773ff8bdafb4f0663f2a56598f4450cdcf00372a779ca7e3c46a6c1348350c38a07b40f91ff8f6256297415d8c71b8d3f56ac1fba31b1e72edcd6c91b5
6
+ metadata.gz: 8a01f7c0f730da3cfc0bfcda6f7c9a2e3f4d2747137f87175671d79021643f09f34fcf373cb400f247159d6551589f51de73241f10ac3373159865db6e04f0fc
7
+ data.tar.gz: a4aa9659e71f1e8c11914727eacd07061128f8d68b0f609c08b272025c9923419a3a58f6d789da6a467258cad69795e3e0aa265f34ffcce4b39d8bd0cb5d8386
data/CHANGELOG.md CHANGED
@@ -1,3 +1,175 @@
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
+
1
173
  ## Rails 7.0.2.4 (April 26, 2022) ##
2
174
 
3
175
  * No changes.
@@ -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)
@@ -432,7 +432,7 @@ module ActiveRecord
432
432
  #
433
433
  # == Cardinality and associations
434
434
  #
435
- # 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
436
436
  # relationships between models. Each model uses an association to describe its role in
437
437
  # the relation. The #belongs_to association is always used in the model that has
438
438
  # the foreign key.
@@ -586,7 +586,7 @@ module ActiveRecord
586
586
  # has_many :birthday_events, ->(user) { where(starts_on: user.birthday) }, class_name: 'Event'
587
587
  # end
588
588
  #
589
- # 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.
590
590
  # These operations happen before instance creation and the scope will be called with a +nil+ argument.
591
591
  #
592
592
  # == Association callbacks
@@ -618,7 +618,7 @@ module ActiveRecord
618
618
  # after_remove: :log_after_remove
619
619
  # end
620
620
  #
621
- # 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+.
622
622
  #
623
623
  # If any of the +before_add+ callbacks throw an exception, the object will not be
624
624
  # added to the collection.
@@ -628,15 +628,15 @@ module ActiveRecord
628
628
  #
629
629
  # Note: To trigger remove callbacks, you must use +destroy+ / +destroy_all+ methods. For example:
630
630
  #
631
- # * <tt>firm.clients.destroy(client)</tt>
632
- # * <tt>firm.clients.destroy(*clients)</tt>
633
- # * <tt>firm.clients.destroy_all</tt>
631
+ # * <tt>firm.clients.destroy(client)</tt>
632
+ # * <tt>firm.clients.destroy(*clients)</tt>
633
+ # * <tt>firm.clients.destroy_all</tt>
634
634
  #
635
635
  # +delete+ / +delete_all+ methods like the following do *not* trigger remove callbacks:
636
636
  #
637
- # * <tt>firm.clients.delete(client)</tt>
638
- # * <tt>firm.clients.delete(*clients)</tt>
639
- # * <tt>firm.clients.delete_all</tt>
637
+ # * <tt>firm.clients.delete(client)</tt>
638
+ # * <tt>firm.clients.delete(*clients)</tt>
639
+ # * <tt>firm.clients.delete_all</tt>
640
640
  #
641
641
  # == Association extensions
642
642
  #
@@ -1332,7 +1332,7 @@ module ActiveRecord
1332
1332
  # === Extensions
1333
1333
  #
1334
1334
  # The +extension+ argument allows you to pass a block into a has_many
1335
- # association. This is useful for adding new finders, creators and other
1335
+ # association. This is useful for adding new finders, creators, and other
1336
1336
  # factory-type methods to be used as part of the association.
1337
1337
  #
1338
1338
  # Extension examples:
@@ -1415,8 +1415,8 @@ module ActiveRecord
1415
1415
  # [:disable_joins]
1416
1416
  # Specifies whether joins should be skipped for an association. If set to true, two or more queries
1417
1417
  # will be generated. Note that in some cases, if order or limit is applied, it will be done in-memory
1418
- # due to database limitations. This option is only applicable on `has_many :through` associations as
1419
- # `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.
1420
1420
  # [:source]
1421
1421
  # Specifies the source association name used by #has_many <tt>:through</tt> queries.
1422
1422
  # Only use it if the name cannot be inferred from the association.
@@ -1580,8 +1580,8 @@ module ActiveRecord
1580
1580
  # [:disable_joins]
1581
1581
  # Specifies whether joins should be skipped for an association. If set to true, two or more queries
1582
1582
  # will be generated. Note that in some cases, if order or limit is applied, it will be done in-memory
1583
- # due to database limitations. This option is only applicable on `has_one :through` associations as
1584
- # `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.
1585
1585
  # [:source]
1586
1586
  # Specifies the source association name used by #has_one <tt>:through</tt> queries.
1587
1587
  # Only use it if the name cannot be inferred from the association.
@@ -1904,7 +1904,7 @@ module ActiveRecord
1904
1904
  #
1905
1905
  # The +extension+ argument allows you to pass a block into a
1906
1906
  # has_and_belongs_to_many association. This is useful for adding new
1907
- # 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
1908
1908
  # the association.
1909
1909
  #
1910
1910
  # Extension examples:
@@ -24,38 +24,6 @@ module ActiveRecord
24
24
  # The serialization format may be YAML, JSON, or any custom format using a
25
25
  # custom coder class.
26
26
  #
27
- # === Serialization formats
28
- #
29
- # serialize attr_name [, class_name_or_coder]
30
- #
31
- # | | database storage |
32
- # class_name_or_coder | attribute read/write type | serialized | NULL |
33
- # ---------------------+---------------------------+------------+--------+
34
- # <not given> | any value that supports | YAML | |
35
- # | .to_yaml | | |
36
- # | | | |
37
- # Array | Array ** | YAML | [] |
38
- # | | | |
39
- # Hash | Hash ** | YAML | {} |
40
- # | | | |
41
- # JSON | any value that supports | JSON | |
42
- # | .to_json | | |
43
- # | | | |
44
- # <custom coder class> | any value supported by | custom | custom |
45
- # | the custom coder class | | |
46
- #
47
- # ** If +class_name_or_coder+ is +Array+ or +Hash+, values retrieved will
48
- # always be of that type, and any value assigned must be of that type or
49
- # +SerializationTypeMismatch+ will be raised.
50
- #
51
- # ==== Custom coders
52
- # A custom coder class or module may be given. This must have +self.load+
53
- # and +self.dump+ class/module methods. <tt>self.dump(object)</tt> will be called
54
- # to serialize an object and should return the serialized value to be
55
- # stored in the database (+nil+ to store as +NULL+). <tt>self.load(string)</tt>
56
- # will be called to reverse the process and load (unserialize) from the
57
- # database.
58
- #
59
27
  # Keep in mind that database adapters handle certain serialization tasks
60
28
  # for you. For instance: +json+ and +jsonb+ types in PostgreSQL will be
61
29
  # converted between JSON object/array syntax and Ruby +Hash+ or +Array+
@@ -67,55 +35,71 @@ module ActiveRecord
67
35
  #
68
36
  # ==== Parameters
69
37
  #
70
- # * +attr_name+ - The field name that should be serialized.
71
- # * +class_name_or_coder+ - Optional, may be be +Array+ or +Hash+ or
72
- # +JSON+ or a custom coder class or module which responds to +.load+
73
- # and +.dump+. See table above.
38
+ # * +attr_name+ - The name of the attribute to serialize.
39
+ # * +class_name_or_coder+ - Optional. May be one of the following:
40
+ # * <em>default</em> - The attribute value will be serialized as YAML.
41
+ # The attribute value must respond to +to_yaml+.
42
+ # * +Array+ - The attribute value will be serialized as YAML, but an
43
+ # empty +Array+ will be serialized as +NULL+. The attribute value
44
+ # must be an +Array+.
45
+ # * +Hash+ - The attribute value will be serialized as YAML, but an
46
+ # empty +Hash+ will be serialized as +NULL+. The attribute value
47
+ # must be a +Hash+.
48
+ # * +JSON+ - The attribute value will be serialized as JSON. The
49
+ # attribute value must respond to +to_json+.
50
+ # * <em>custom coder</em> - The attribute value will be serialized
51
+ # using the coder's <tt>dump(value)</tt> method, and will be
52
+ # deserialized using the coder's <tt>load(string)</tt> method. The
53
+ # +dump+ method may return +nil+ to serialize the value as +NULL+.
74
54
  #
75
55
  # ==== Options
76
56
  #
77
- # +default+ The default value to use when no value is provided. If this option
78
- # is not passed, the previous default value (if any) will be used.
79
- # Otherwise, the default will be +nil+.
57
+ # * +:default+ - The default value to use when no value is provided. If
58
+ # this option is not passed, the previous default value (if any) will
59
+ # be used. Otherwise, the default will be +nil+.
60
+ #
61
+ # ==== Examples
80
62
  #
81
- # ==== Example
63
+ # ===== Serialize the +preferences+ attribute using YAML
82
64
  #
83
- # # Serialize a preferences attribute using YAML coder.
84
65
  # class User < ActiveRecord::Base
85
66
  # serialize :preferences
86
67
  # end
87
68
  #
88
- # # Serialize preferences using JSON as coder.
69
+ # ===== Serialize the +preferences+ attribute using JSON
70
+ #
89
71
  # class User < ActiveRecord::Base
90
72
  # serialize :preferences, JSON
91
73
  # end
92
74
  #
93
- # # Serialize preferences as Hash using YAML coder.
75
+ # ===== Serialize the +preferences+ +Hash+ using YAML
76
+ #
94
77
  # class User < ActiveRecord::Base
95
78
  # serialize :preferences, Hash
96
79
  # end
97
80
  #
98
- # # Serialize preferences using a custom coder.
81
+ # ===== Serialize the +preferences+ attribute using a custom coder
82
+ #
99
83
  # class Rot13JSON
100
84
  # def self.rot13(string)
101
85
  # string.tr("a-zA-Z", "n-za-mN-ZA-M")
102
86
  # end
103
87
  #
104
- # # returns serialized string that will be stored in the database
105
- # def self.dump(object)
106
- # ActiveSupport::JSON.encode(object).rot13
88
+ # # Serializes an attribute value to a string that will be stored in the database.
89
+ # def self.dump(value)
90
+ # rot13(ActiveSupport::JSON.dump(value))
107
91
  # end
108
92
  #
109
- # # reverses the above, turning the serialized string from the database
110
- # # back into its original value
93
+ # # Deserializes a string from the database to an attribute value.
111
94
  # def self.load(string)
112
- # ActiveSupport::JSON.decode(string.rot13)
95
+ # ActiveSupport::JSON.load(rot13(string))
113
96
  # end
114
97
  # end
115
98
  #
116
99
  # class User < ActiveRecord::Base
117
100
  # serialize :preferences, Rot13JSON
118
101
  # end
102
+ #
119
103
  def serialize(attr_name, class_name_or_coder = Object, **options)
120
104
  # When ::JSON is used, force it to go through the Active Support JSON encoder
121
105
  # to ensure special objects (e.g. Active Record models) are dumped correctly
@@ -19,6 +19,8 @@ module ActiveRecord
19
19
 
20
20
  if value.is_a?(Hash)
21
21
  set_time_zone_without_conversion(super)
22
+ elsif value.is_a?(Range)
23
+ Range.new(user_input_in_time_zone(value.begin), user_input_in_time_zone(value.end), value.exclude_end?)
22
24
  elsif value.respond_to?(:in_time_zone)
23
25
  begin
24
26
  super(user_input_in_time_zone(value)) || super
@@ -40,6 +42,8 @@ module ActiveRecord
40
42
  value.in_time_zone
41
43
  elsif value.respond_to?(:infinite?) && value.infinite?
42
44
  value
45
+ elsif value.is_a?(Range)
46
+ Range.new(convert_time_to_time_zone(value.begin), convert_time_to_time_zone(value.end), value.exclude_end?)
43
47
  else
44
48
  map_avoiding_infinite_recursion(value) { |v| convert_time_to_time_zone(v) }
45
49
  end
@@ -97,7 +97,7 @@ module ActiveRecord
97
97
  super
98
98
  else
99
99
  # If ThisClass < ... < SomeSuperClass < ... < Base and SomeSuperClass
100
- # defines its own attribute method, then we don't want to overwrite that.
100
+ # defines its own attribute method, then we don't want to override that.
101
101
  defined = method_defined_within?(method_name, superclass, Base) &&
102
102
  ! superclass.instance_method(method_name).owner.is_a?(GeneratedAttributeMethods)
103
103
  defined || super
@@ -137,7 +137,7 @@ module ActiveRecord # :nodoc:
137
137
  # anonymous = User.new(name: "")
138
138
  # anonymous.name? # => false
139
139
  #
140
- # Query methods will also respect any overwrites of default accessors:
140
+ # Query methods will also respect any overrides of default accessors:
141
141
  #
142
142
  # class User
143
143
  # # Has admin boolean column
@@ -151,8 +151,8 @@ module ActiveRecord # :nodoc:
151
151
  # user.read_attribute(:admin) # => true, gets the column value
152
152
  # user[:admin] # => true, also gets the column value
153
153
  #
154
- # user.admin # => false, due to the getter overwrite
155
- # user.admin? # => false, due to the getter overwrite
154
+ # user.admin # => false, due to the getter override
155
+ # user.admin? # => false, due to the getter override
156
156
  #
157
157
  # == Accessing attributes before they have been typecasted
158
158
  #
@@ -47,11 +47,19 @@ module ActiveRecord
47
47
 
48
48
  if YAML.respond_to?(:unsafe_load)
49
49
  def yaml_load(payload)
50
- YAML.unsafe_load(payload)
50
+ if ActiveRecord.use_yaml_unsafe_load
51
+ YAML.unsafe_load(payload)
52
+ else
53
+ YAML.safe_load(payload, permitted_classes: ActiveRecord.yaml_column_permitted_classes, aliases: true)
54
+ end
51
55
  end
52
56
  else
53
57
  def yaml_load(payload)
54
- YAML.load(payload)
58
+ if ActiveRecord.use_yaml_unsafe_load
59
+ YAML.load(payload)
60
+ else
61
+ YAML.safe_load(payload, permitted_classes: ActiveRecord.yaml_column_permitted_classes, aliases: true)
62
+ end
55
63
  end
56
64
  end
57
65
  end
@@ -40,7 +40,7 @@ module ActiveRecord
40
40
  # but the Book model connects to a separate database called "library_db"
41
41
  # (this can even be a database on a different machine).
42
42
  #
43
- # Book, ScaryBook and GoodBook will all use the same connection pool to
43
+ # Book, ScaryBook, and GoodBook will all use the same connection pool to
44
44
  # "library_db" while Author, BankAccount, and any other models you create
45
45
  # will use the default connection pool to "my_application".
46
46
  #
@@ -202,6 +202,10 @@ module ActiveRecord
202
202
 
203
203
  def index_options(table_name)
204
204
  index_options = as_options(index)
205
+
206
+ # legacy reference index names are used on versions 6.0 and earlier
207
+ return index_options if options[:_uses_legacy_reference_index_name]
208
+
205
209
  index_options[:name] ||= polymorphic_index_name(table_name) if polymorphic
206
210
  index_options
207
211
  end
@@ -1071,9 +1071,9 @@ module ActiveRecord
1071
1071
  # [<tt>:name</tt>]
1072
1072
  # The constraint name. Defaults to <tt>fk_rails_<identifier></tt>.
1073
1073
  # [<tt>:on_delete</tt>]
1074
- # Action that happens <tt>ON DELETE</tt>. Valid values are +:nullify+, +:cascade+ and +:restrict+
1074
+ # Action that happens <tt>ON DELETE</tt>. Valid values are +:nullify+, +:cascade+, and +:restrict+
1075
1075
  # [<tt>:on_update</tt>]
1076
- # Action that happens <tt>ON UPDATE</tt>. Valid values are +:nullify+, +:cascade+ and +:restrict+
1076
+ # Action that happens <tt>ON UPDATE</tt>. Valid values are +:nullify+, +:cascade+, and +:restrict+
1077
1077
  # [<tt>:if_not_exists</tt>]
1078
1078
  # Specifies if the foreign key already exists to not try to re-add it. This will avoid
1079
1079
  # duplicate column errors.
@@ -1125,7 +1125,7 @@ module ActiveRecord
1125
1125
  # The name of the table that contains the referenced primary key.
1126
1126
  def remove_foreign_key(from_table, to_table = nil, **options)
1127
1127
  return unless supports_foreign_keys?
1128
- return if options[:if_exists] == true && !foreign_key_exists?(from_table, to_table)
1128
+ return if options.delete(:if_exists) == true && !foreign_key_exists?(from_table, to_table)
1129
1129
 
1130
1130
  fk_name_to_delete = foreign_key_for!(from_table, to_table: to_table, **options).name
1131
1131
 
@@ -36,7 +36,7 @@ module ActiveRecord
36
36
  include Savepoints
37
37
 
38
38
  SIMPLE_INT = /\A\d+\z/
39
- COMMENT_REGEX = %r{(?:--.*\n)*|/\*(?:[^*]|\*[^/])*\*/}m
39
+ COMMENT_REGEX = %r{(?:--.*\n)|/\*(?:[^*]|\*[^/])*\*/}m
40
40
 
41
41
  attr_accessor :pool
42
42
  attr_reader :visitor, :owner, :logger, :lock
@@ -224,14 +224,14 @@ module ActiveRecord
224
224
  @pool.connection_class
225
225
  end
226
226
 
227
- # The role (ie :writing) for the current connection. In a
228
- # non-multi role application, `:writing` is returned.
227
+ # The role (e.g. +:writing+) for the current connection. In a
228
+ # non-multi role application, +:writing+ is returned.
229
229
  def role
230
230
  @pool.role
231
231
  end
232
232
 
233
- # The shard (ie :default) for the current connection. In
234
- # a non-sharded application, `:default` is returned.
233
+ # The shard (e.g. +:default+) for the current connection. In
234
+ # a non-sharded application, +:default+ is returned.
235
235
  def shard
236
236
  @pool.shard
237
237
  end