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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +172 -0
- data/lib/active_record/associations/collection_association.rb +1 -2
- data/lib/active_record/associations/collection_proxy.rb +2 -2
- data/lib/active_record/associations/has_many_association.rb +7 -4
- data/lib/active_record/associations/join_dependency.rb +17 -13
- data/lib/active_record/associations.rb +15 -15
- data/lib/active_record/attribute_methods/serialization.rb +34 -50
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +4 -0
- data/lib/active_record/attribute_methods.rb +1 -1
- data/lib/active_record/base.rb +3 -3
- data/lib/active_record/coders/yaml_column.rb +10 -2
- data/lib/active_record/connection_adapters/abstract/connection_handler.rb +1 -1
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +4 -0
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +3 -3
- data/lib/active_record/connection_adapters/abstract_adapter.rb +5 -5
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +9 -1
- data/lib/active_record/connection_adapters/mysql/quoting.rb +3 -1
- data/lib/active_record/connection_adapters/mysql/schema_statements.rb +19 -1
- data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +2 -2
- data/lib/active_record/connection_adapters/postgresql/quoting.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +3 -1
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +2 -0
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +4 -3
- data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +2 -2
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +7 -2
- data/lib/active_record/connection_handling.rb +2 -2
- data/lib/active_record/core.rb +3 -3
- data/lib/active_record/delegated_type.rb +1 -1
- data/lib/active_record/encryption/configurable.rb +8 -2
- data/lib/active_record/encryption/contexts.rb +3 -3
- data/lib/active_record/encryption/derived_secret_key_provider.rb +1 -1
- data/lib/active_record/encryption/deterministic_key_provider.rb +1 -1
- data/lib/active_record/encryption/encryptable_record.rb +2 -4
- data/lib/active_record/encryption/encrypted_attribute_type.rb +2 -2
- data/lib/active_record/encryption/encryptor.rb +7 -7
- data/lib/active_record/encryption/envelope_encryption_key_provider.rb +3 -3
- data/lib/active_record/encryption/extended_deterministic_queries.rb +4 -4
- data/lib/active_record/encryption/message.rb +1 -1
- data/lib/active_record/encryption/properties.rb +1 -1
- data/lib/active_record/encryption/scheme.rb +1 -1
- data/lib/active_record/enum.rb +1 -1
- data/lib/active_record/fixtures.rb +4 -4
- data/lib/active_record/gem_version.rb +3 -3
- data/lib/active_record/locking/pessimistic.rb +3 -3
- data/lib/active_record/log_subscriber.rb +10 -5
- data/lib/active_record/middleware/database_selector.rb +13 -6
- data/lib/active_record/middleware/shard_selector.rb +4 -4
- data/lib/active_record/migration/command_recorder.rb +3 -3
- data/lib/active_record/migration/compatibility.rb +7 -26
- data/lib/active_record/migration.rb +5 -4
- data/lib/active_record/model_schema.rb +22 -10
- data/lib/active_record/persistence.rb +9 -8
- data/lib/active_record/querying.rb +1 -1
- data/lib/active_record/railtie.rb +20 -16
- data/lib/active_record/railties/databases.rake +16 -11
- data/lib/active_record/reflection.rb +6 -0
- data/lib/active_record/relation/batches.rb +3 -3
- data/lib/active_record/relation/query_methods.rb +27 -6
- data/lib/active_record/relation.rb +7 -6
- data/lib/active_record/sanitization.rb +6 -5
- data/lib/active_record/scoping/default.rb +5 -7
- data/lib/active_record/serialization.rb +5 -0
- data/lib/active_record/signed_id.rb +2 -2
- data/lib/active_record/store.rb +7 -2
- data/lib/active_record/tasks/database_tasks.rb +26 -21
- data/lib/active_record/tasks/postgresql_database_tasks.rb +1 -2
- data/lib/active_record/test_fixtures.rb +12 -5
- data/lib/active_record/translation.rb +1 -1
- data/lib/active_record/validations/associated.rb +3 -3
- data/lib/active_record/validations/presence.rb +2 -2
- data/lib/active_record/validations/uniqueness.rb +3 -3
- data/lib/active_record/version.rb +1 -1
- data/lib/active_record.rb +14 -0
- metadata +10 -10
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 18986b8f256d988204ff7b48287980a88e138a4280d637cf28310e551082987d
|
4
|
+
data.tar.gz: 8054f80c87f48a264d08f006b789e2c3680155e0ed7fb5a5698d962f7ff0d8bb
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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
|
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
|
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
|
83
|
-
#
|
84
|
-
#
|
85
|
-
|
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
|
-
|
256
|
-
|
257
|
-
|
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
|
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
|
-
#
|
632
|
-
#
|
633
|
-
#
|
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
|
-
#
|
638
|
-
#
|
639
|
-
#
|
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
|
1419
|
-
#
|
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
|
1584
|
-
#
|
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
|
71
|
-
# * +class_name_or_coder+ - Optional
|
72
|
-
#
|
73
|
-
#
|
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
|
-
#
|
78
|
-
# is not passed, the previous default value (if any) will
|
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
|
-
#
|
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
|
-
#
|
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
|
-
#
|
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
|
-
#
|
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
|
-
# #
|
105
|
-
# def self.dump(
|
106
|
-
# ActiveSupport::JSON.
|
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
|
-
# #
|
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.
|
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
|
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
|
data/lib/active_record/base.rb
CHANGED
@@ -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
|
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
|
155
|
-
# user.admin? # => false, due to the getter
|
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
|
-
|
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
|
-
|
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
|
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
|
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
|
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)
|
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 (
|
228
|
-
# non-multi role application,
|
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 (
|
234
|
-
# a non-sharded application,
|
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
|