activerecord 6.1.7.10 → 7.0.0.alpha1
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 +726 -1404
- data/MIT-LICENSE +1 -1
- data/README.rdoc +1 -1
- data/lib/active_record/aggregations.rb +1 -1
- data/lib/active_record/association_relation.rb +0 -10
- data/lib/active_record/associations/association.rb +31 -9
- data/lib/active_record/associations/association_scope.rb +1 -3
- data/lib/active_record/associations/belongs_to_association.rb +15 -4
- data/lib/active_record/associations/belongs_to_polymorphic_association.rb +10 -2
- data/lib/active_record/associations/builder/association.rb +8 -2
- data/lib/active_record/associations/builder/belongs_to.rb +19 -6
- data/lib/active_record/associations/builder/collection_association.rb +1 -1
- data/lib/active_record/associations/builder/has_many.rb +3 -2
- data/lib/active_record/associations/builder/has_one.rb +2 -1
- data/lib/active_record/associations/builder/singular_association.rb +2 -2
- data/lib/active_record/associations/collection_association.rb +14 -23
- data/lib/active_record/associations/collection_proxy.rb +8 -3
- data/lib/active_record/associations/disable_joins_association_scope.rb +59 -0
- data/lib/active_record/associations/has_many_association.rb +1 -1
- data/lib/active_record/associations/has_many_through_association.rb +2 -1
- data/lib/active_record/associations/has_one_association.rb +10 -7
- data/lib/active_record/associations/has_one_through_association.rb +1 -1
- data/lib/active_record/associations/preloader/association.rb +161 -47
- data/lib/active_record/associations/preloader/batch.rb +51 -0
- data/lib/active_record/associations/preloader/branch.rb +147 -0
- data/lib/active_record/associations/preloader/through_association.rb +37 -11
- data/lib/active_record/associations/preloader.rb +46 -110
- data/lib/active_record/associations/singular_association.rb +8 -2
- data/lib/active_record/associations/through_association.rb +1 -1
- data/lib/active_record/associations.rb +76 -81
- data/lib/active_record/asynchronous_queries_tracker.rb +57 -0
- data/lib/active_record/attribute_assignment.rb +1 -1
- data/lib/active_record/attribute_methods/before_type_cast.rb +7 -2
- data/lib/active_record/attribute_methods/dirty.rb +41 -16
- data/lib/active_record/attribute_methods/primary_key.rb +2 -2
- data/lib/active_record/attribute_methods/query.rb +2 -2
- data/lib/active_record/attribute_methods/read.rb +7 -5
- data/lib/active_record/attribute_methods/serialization.rb +66 -12
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +4 -3
- data/lib/active_record/attribute_methods/write.rb +7 -10
- data/lib/active_record/attribute_methods.rb +6 -9
- data/lib/active_record/attributes.rb +24 -35
- data/lib/active_record/autosave_association.rb +3 -18
- data/lib/active_record/base.rb +19 -1
- data/lib/active_record/callbacks.rb +2 -2
- data/lib/active_record/coders/yaml_column.rb +2 -14
- data/lib/active_record/connection_adapters/abstract/connection_handler.rb +312 -0
- data/lib/active_record/connection_adapters/abstract/connection_pool/queue.rb +209 -0
- data/lib/active_record/connection_adapters/abstract/connection_pool/reaper.rb +76 -0
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +31 -558
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +45 -21
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +24 -12
- data/lib/active_record/connection_adapters/abstract/quoting.rb +12 -14
- data/lib/active_record/connection_adapters/abstract/schema_creation.rb +4 -17
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +30 -13
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +60 -16
- data/lib/active_record/connection_adapters/abstract/transaction.rb +3 -3
- data/lib/active_record/connection_adapters/abstract_adapter.rb +112 -66
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +96 -81
- data/lib/active_record/connection_adapters/mysql/database_statements.rb +33 -23
- data/lib/active_record/connection_adapters/mysql/quoting.rb +16 -1
- data/lib/active_record/connection_adapters/mysql/schema_statements.rb +1 -1
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +12 -6
- data/lib/active_record/connection_adapters/pool_config.rb +1 -3
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +19 -14
- data/lib/active_record/connection_adapters/postgresql/oid/date.rb +8 -0
- data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +5 -0
- data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +53 -14
- data/lib/active_record/connection_adapters/postgresql/oid/range.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/oid/timestamp.rb +15 -0
- data/lib/active_record/connection_adapters/postgresql/oid/timestamp_with_time_zone.rb +28 -0
- data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +18 -6
- data/lib/active_record/connection_adapters/postgresql/oid.rb +2 -0
- data/lib/active_record/connection_adapters/postgresql/quoting.rb +6 -32
- data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +32 -0
- data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +5 -1
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +12 -12
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +159 -102
- data/lib/active_record/connection_adapters/schema_cache.rb +36 -37
- data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +23 -19
- data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +4 -2
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +61 -30
- data/lib/active_record/connection_adapters.rb +6 -5
- data/lib/active_record/connection_handling.rb +20 -38
- data/lib/active_record/core.rb +111 -125
- data/lib/active_record/database_configurations/connection_url_resolver.rb +0 -1
- data/lib/active_record/database_configurations/database_config.rb +12 -0
- data/lib/active_record/database_configurations/hash_config.rb +27 -1
- data/lib/active_record/database_configurations/url_config.rb +2 -2
- data/lib/active_record/database_configurations.rb +17 -9
- data/lib/active_record/delegated_type.rb +33 -11
- data/lib/active_record/destroy_association_async_job.rb +1 -1
- data/lib/active_record/disable_joins_association_relation.rb +39 -0
- data/lib/active_record/dynamic_matchers.rb +1 -1
- data/lib/active_record/encryption/cipher/aes256_gcm.rb +98 -0
- data/lib/active_record/encryption/cipher.rb +53 -0
- data/lib/active_record/encryption/config.rb +44 -0
- data/lib/active_record/encryption/configurable.rb +61 -0
- data/lib/active_record/encryption/context.rb +35 -0
- data/lib/active_record/encryption/contexts.rb +72 -0
- data/lib/active_record/encryption/derived_secret_key_provider.rb +12 -0
- data/lib/active_record/encryption/deterministic_key_provider.rb +14 -0
- data/lib/active_record/encryption/encryptable_record.rb +208 -0
- data/lib/active_record/encryption/encrypted_attribute_type.rb +140 -0
- data/lib/active_record/encryption/encrypted_fixtures.rb +38 -0
- data/lib/active_record/encryption/encrypting_only_encryptor.rb +12 -0
- data/lib/active_record/encryption/encryptor.rb +155 -0
- data/lib/active_record/encryption/envelope_encryption_key_provider.rb +55 -0
- data/lib/active_record/encryption/errors.rb +15 -0
- data/lib/active_record/encryption/extended_deterministic_queries.rb +160 -0
- data/lib/active_record/encryption/extended_deterministic_uniqueness_validator.rb +29 -0
- data/lib/active_record/encryption/key.rb +28 -0
- data/lib/active_record/encryption/key_generator.rb +42 -0
- data/lib/active_record/encryption/key_provider.rb +46 -0
- data/lib/active_record/encryption/message.rb +33 -0
- data/lib/active_record/encryption/message_serializer.rb +80 -0
- data/lib/active_record/encryption/null_encryptor.rb +21 -0
- data/lib/active_record/encryption/properties.rb +76 -0
- data/lib/active_record/encryption/read_only_null_encryptor.rb +24 -0
- data/lib/active_record/encryption/scheme.rb +99 -0
- data/lib/active_record/encryption.rb +55 -0
- data/lib/active_record/enum.rb +41 -41
- data/lib/active_record/errors.rb +66 -3
- data/lib/active_record/fixture_set/file.rb +15 -1
- data/lib/active_record/fixture_set/table_row.rb +40 -5
- data/lib/active_record/fixture_set/table_rows.rb +4 -4
- data/lib/active_record/fixtures.rb +16 -11
- data/lib/active_record/future_result.rb +139 -0
- data/lib/active_record/gem_version.rb +4 -4
- data/lib/active_record/inheritance.rb +55 -17
- data/lib/active_record/insert_all.rb +34 -5
- data/lib/active_record/integration.rb +1 -1
- data/lib/active_record/internal_metadata.rb +1 -5
- data/lib/active_record/locking/optimistic.rb +10 -9
- data/lib/active_record/log_subscriber.rb +6 -2
- data/lib/active_record/middleware/database_selector/resolver.rb +6 -10
- data/lib/active_record/middleware/database_selector.rb +8 -3
- data/lib/active_record/migration/command_recorder.rb +4 -4
- data/lib/active_record/migration/compatibility.rb +89 -10
- data/lib/active_record/migration/join_table.rb +1 -1
- data/lib/active_record/migration.rb +109 -79
- data/lib/active_record/model_schema.rb +45 -31
- data/lib/active_record/nested_attributes.rb +3 -3
- data/lib/active_record/no_touching.rb +2 -2
- data/lib/active_record/null_relation.rb +2 -6
- data/lib/active_record/persistence.rb +134 -45
- data/lib/active_record/query_cache.rb +2 -2
- data/lib/active_record/query_logs.rb +203 -0
- data/lib/active_record/querying.rb +15 -5
- data/lib/active_record/railtie.rb +117 -17
- data/lib/active_record/railties/controller_runtime.rb +1 -1
- data/lib/active_record/railties/databases.rake +72 -48
- data/lib/active_record/readonly_attributes.rb +11 -0
- data/lib/active_record/reflection.rb +45 -44
- data/lib/active_record/relation/batches/batch_enumerator.rb +19 -5
- data/lib/active_record/relation/batches.rb +3 -3
- data/lib/active_record/relation/calculations.rb +39 -26
- data/lib/active_record/relation/delegation.rb +6 -6
- data/lib/active_record/relation/finder_methods.rb +31 -22
- data/lib/active_record/relation/merger.rb +20 -13
- data/lib/active_record/relation/predicate_builder.rb +1 -6
- data/lib/active_record/relation/query_attribute.rb +5 -11
- data/lib/active_record/relation/query_methods.rb +230 -49
- data/lib/active_record/relation/record_fetch_warning.rb +2 -2
- data/lib/active_record/relation/spawn_methods.rb +2 -2
- data/lib/active_record/relation/where_clause.rb +8 -4
- data/lib/active_record/relation.rb +166 -77
- data/lib/active_record/result.rb +17 -2
- data/lib/active_record/runtime_registry.rb +2 -4
- data/lib/active_record/sanitization.rb +11 -7
- data/lib/active_record/schema_dumper.rb +3 -3
- data/lib/active_record/schema_migration.rb +0 -4
- data/lib/active_record/scoping/default.rb +61 -12
- data/lib/active_record/scoping/named.rb +3 -11
- data/lib/active_record/scoping.rb +40 -22
- data/lib/active_record/serialization.rb +1 -1
- data/lib/active_record/signed_id.rb +1 -1
- data/lib/active_record/store.rb +1 -6
- data/lib/active_record/tasks/database_tasks.rb +106 -22
- data/lib/active_record/tasks/mysql_database_tasks.rb +1 -1
- data/lib/active_record/tasks/postgresql_database_tasks.rb +14 -11
- data/lib/active_record/test_databases.rb +1 -1
- data/lib/active_record/test_fixtures.rb +9 -13
- data/lib/active_record/timestamp.rb +3 -4
- data/lib/active_record/transactions.rb +9 -14
- data/lib/active_record/translation.rb +2 -2
- data/lib/active_record/type/adapter_specific_registry.rb +32 -7
- data/lib/active_record/type/hash_lookup_type_map.rb +34 -1
- data/lib/active_record/type/internal/timezone.rb +2 -2
- data/lib/active_record/type/serialized.rb +1 -1
- data/lib/active_record/type/type_map.rb +17 -20
- data/lib/active_record/type.rb +1 -2
- data/lib/active_record/validations/associated.rb +1 -1
- data/lib/active_record.rb +170 -2
- data/lib/arel/attributes/attribute.rb +0 -8
- data/lib/arel/crud.rb +18 -22
- data/lib/arel/delete_manager.rb +2 -4
- data/lib/arel/insert_manager.rb +2 -3
- data/lib/arel/nodes/casted.rb +1 -1
- data/lib/arel/nodes/delete_statement.rb +8 -13
- data/lib/arel/nodes/insert_statement.rb +2 -2
- data/lib/arel/nodes/select_core.rb +2 -2
- data/lib/arel/nodes/select_statement.rb +2 -2
- data/lib/arel/nodes/update_statement.rb +3 -2
- data/lib/arel/predications.rb +1 -1
- data/lib/arel/select_manager.rb +10 -4
- data/lib/arel/table.rb +0 -1
- data/lib/arel/tree_manager.rb +0 -12
- data/lib/arel/update_manager.rb +2 -4
- data/lib/arel/visitors/dot.rb +80 -90
- data/lib/arel/visitors/mysql.rb +6 -1
- data/lib/arel/visitors/postgresql.rb +0 -10
- data/lib/arel/visitors/to_sql.rb +43 -2
- data/lib/arel.rb +1 -1
- data/lib/rails/generators/active_record/application_record/templates/application_record.rb.tt +1 -1
- data/lib/rails/generators/active_record/model/templates/abstract_base_class.rb.tt +1 -1
- data/lib/rails/generators/active_record/model/templates/model.rb.tt +1 -1
- data/lib/rails/generators/active_record/model/templates/module.rb.tt +2 -2
- metadata +52 -14
@@ -29,8 +29,8 @@ module ActiveRecord
|
|
29
29
|
extend ActiveSupport::Concern
|
30
30
|
|
31
31
|
included do
|
32
|
-
attribute_method_suffix "_before_type_cast", "_for_database"
|
33
|
-
attribute_method_suffix "_came_from_user?"
|
32
|
+
attribute_method_suffix "_before_type_cast", "_for_database", parameters: false
|
33
|
+
attribute_method_suffix "_came_from_user?", parameters: false
|
34
34
|
end
|
35
35
|
|
36
36
|
# Returns the value of the attribute identified by +attr_name+ before
|
@@ -66,6 +66,11 @@ module ActiveRecord
|
|
66
66
|
@attributes.values_before_type_cast
|
67
67
|
end
|
68
68
|
|
69
|
+
# Returns a hash of attributes for assignment to the database.
|
70
|
+
def attributes_for_database
|
71
|
+
@attributes.values_for_database
|
72
|
+
end
|
73
|
+
|
69
74
|
private
|
70
75
|
# Dispatch target for <tt>*_before_type_cast</tt> attribute methods.
|
71
76
|
def attribute_before_type_cast(attr_name)
|
@@ -14,16 +14,43 @@ module ActiveRecord
|
|
14
14
|
raise "You cannot include Dirty after Timestamp"
|
15
15
|
end
|
16
16
|
|
17
|
-
class_attribute :
|
17
|
+
class_attribute :partial_updates, instance_writer: false, default: true
|
18
|
+
class_attribute :partial_inserts, instance_writer: false, default: true
|
18
19
|
|
19
20
|
# Attribute methods for "changed in last call to save?"
|
20
|
-
attribute_method_affix(prefix: "saved_change_to_", suffix: "?")
|
21
|
-
attribute_method_prefix("saved_change_to_")
|
22
|
-
attribute_method_suffix("_before_last_save")
|
21
|
+
attribute_method_affix(prefix: "saved_change_to_", suffix: "?", parameters: "**options")
|
22
|
+
attribute_method_prefix("saved_change_to_", parameters: false)
|
23
|
+
attribute_method_suffix("_before_last_save", parameters: false)
|
23
24
|
|
24
25
|
# Attribute methods for "will change if I call save?"
|
25
|
-
attribute_method_affix(prefix: "will_save_change_to_", suffix: "?")
|
26
|
-
attribute_method_suffix("_change_to_be_saved", "_in_database")
|
26
|
+
attribute_method_affix(prefix: "will_save_change_to_", suffix: "?", parameters: "**options")
|
27
|
+
attribute_method_suffix("_change_to_be_saved", "_in_database", parameters: false)
|
28
|
+
end
|
29
|
+
|
30
|
+
module ClassMethods
|
31
|
+
def partial_writes
|
32
|
+
ActiveSupport::Deprecation.warn(<<-MSG.squish)
|
33
|
+
ActiveRecord::Base.partial_writes is deprecated and will be removed in Rails 7.1.
|
34
|
+
Use `partial_updates` and `partial_inserts` instead.
|
35
|
+
MSG
|
36
|
+
partial_updates && partial_inserts
|
37
|
+
end
|
38
|
+
|
39
|
+
def partial_writes?
|
40
|
+
ActiveSupport::Deprecation.warn(<<-MSG.squish)
|
41
|
+
`ActiveRecord::Base.partial_writes?` is deprecated and will be removed in Rails 7.1.
|
42
|
+
Use `partial_updates?` and `partial_inserts?` instead.
|
43
|
+
MSG
|
44
|
+
partial_updates? && partial_inserts?
|
45
|
+
end
|
46
|
+
|
47
|
+
def partial_writes=(value)
|
48
|
+
ActiveSupport::Deprecation.warn(<<-MSG.squish)
|
49
|
+
`ActiveRecord::Base.partial_writes=` is deprecated and will be removed in Rails 7.1.
|
50
|
+
Use `partial_updates=` and `partial_inserts=` instead.
|
51
|
+
MSG
|
52
|
+
self.partial_updates = self.partial_inserts = value
|
53
|
+
end
|
27
54
|
end
|
28
55
|
|
29
56
|
# <tt>reload</tt> the record and clears changed attributes.
|
@@ -156,12 +183,6 @@ module ActiveRecord
|
|
156
183
|
end
|
157
184
|
|
158
185
|
private
|
159
|
-
def write_attribute_without_type_cast(attr_name, value)
|
160
|
-
result = super
|
161
|
-
clear_attribute_change(attr_name)
|
162
|
-
result
|
163
|
-
end
|
164
|
-
|
165
186
|
def _touch_row(attribute_names, time)
|
166
187
|
@_touch_attr_names = Set.new(attribute_names)
|
167
188
|
|
@@ -191,20 +212,24 @@ module ActiveRecord
|
|
191
212
|
@_touch_attr_names, @_skip_dirty_tracking = nil, nil
|
192
213
|
end
|
193
214
|
|
194
|
-
def _update_record(attribute_names =
|
215
|
+
def _update_record(attribute_names = attribute_names_for_partial_updates)
|
195
216
|
affected_rows = super
|
196
217
|
changes_applied
|
197
218
|
affected_rows
|
198
219
|
end
|
199
220
|
|
200
|
-
def _create_record(attribute_names =
|
221
|
+
def _create_record(attribute_names = attribute_names_for_partial_inserts)
|
201
222
|
id = super
|
202
223
|
changes_applied
|
203
224
|
id
|
204
225
|
end
|
205
226
|
|
206
|
-
def
|
207
|
-
|
227
|
+
def attribute_names_for_partial_updates
|
228
|
+
partial_updates? ? changed_attribute_names_to_save : attribute_names
|
229
|
+
end
|
230
|
+
|
231
|
+
def attribute_names_for_partial_inserts
|
232
|
+
partial_inserts? ? changed_attribute_names_to_save : attribute_names
|
208
233
|
end
|
209
234
|
end
|
210
235
|
end
|
@@ -78,7 +78,7 @@ module ActiveRecord
|
|
78
78
|
@quoted_primary_key ||= connection.quote_column_name(primary_key)
|
79
79
|
end
|
80
80
|
|
81
|
-
def reset_primary_key
|
81
|
+
def reset_primary_key # :nodoc:
|
82
82
|
if base_class?
|
83
83
|
self.primary_key = get_primary_key(base_class.name)
|
84
84
|
else
|
@@ -86,7 +86,7 @@ module ActiveRecord
|
|
86
86
|
end
|
87
87
|
end
|
88
88
|
|
89
|
-
def get_primary_key(base_name)
|
89
|
+
def get_primary_key(base_name) # :nodoc:
|
90
90
|
if base_name && primary_key_prefix_type == :table_name
|
91
91
|
base_name.foreign_key(false)
|
92
92
|
elsif base_name && primary_key_prefix_type == :table_name_with_underscore
|
@@ -6,11 +6,11 @@ module ActiveRecord
|
|
6
6
|
extend ActiveSupport::Concern
|
7
7
|
|
8
8
|
included do
|
9
|
-
attribute_method_suffix "?"
|
9
|
+
attribute_method_suffix "?", parameters: false
|
10
10
|
end
|
11
11
|
|
12
12
|
def query_attribute(attr_name)
|
13
|
-
value = self
|
13
|
+
value = self.public_send(attr_name)
|
14
14
|
|
15
15
|
case value
|
16
16
|
when true then true
|
@@ -11,10 +11,12 @@ module ActiveRecord
|
|
11
11
|
ActiveModel::AttributeMethods::AttrNames.define_attribute_accessor_method(
|
12
12
|
owner, name
|
13
13
|
) do |temp_method_name, attr_name_expr|
|
14
|
-
owner
|
15
|
-
|
16
|
-
|
17
|
-
|
14
|
+
owner.define_cached_method(name, as: temp_method_name, namespace: :active_record) do |batch|
|
15
|
+
batch <<
|
16
|
+
"def #{temp_method_name}" <<
|
17
|
+
" _read_attribute(#{attr_name_expr}) { |n| missing_attribute(n, caller) }" <<
|
18
|
+
"end"
|
19
|
+
end
|
18
20
|
end
|
19
21
|
end
|
20
22
|
end
|
@@ -32,7 +34,7 @@ module ActiveRecord
|
|
32
34
|
|
33
35
|
# This method exists to avoid the expensive primary_key check internally, without
|
34
36
|
# breaking compatibility with the read_attribute API
|
35
|
-
def _read_attribute(attr_name, &block) # :nodoc
|
37
|
+
def _read_attribute(attr_name, &block) # :nodoc:
|
36
38
|
@attributes.fetch_value(attr_name, &block)
|
37
39
|
end
|
38
40
|
|
@@ -16,15 +16,45 @@ module ActiveRecord
|
|
16
16
|
end
|
17
17
|
|
18
18
|
module ClassMethods
|
19
|
-
# If you have an attribute that needs to be saved to the database as
|
20
|
-
# object, and retrieved
|
21
|
-
# attribute using this method and
|
22
|
-
#
|
23
|
-
# serialized object must be of that class on assignment and retrieval.
|
24
|
-
# Otherwise SerializationTypeMismatch will be raised.
|
19
|
+
# If you have an attribute that needs to be saved to the database as a
|
20
|
+
# serialized object, and retrieved by deserializing into the same object,
|
21
|
+
# then specify the name of that attribute using this method and serialization
|
22
|
+
# will be handled automatically.
|
25
23
|
#
|
26
|
-
#
|
27
|
-
#
|
24
|
+
# The serialization format may be YAML, JSON, or any custom format using a
|
25
|
+
# custom coder class.
|
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.
|
28
58
|
#
|
29
59
|
# Keep in mind that database adapters handle certain serialization tasks
|
30
60
|
# for you. For instance: +json+ and +jsonb+ types in PostgreSQL will be
|
@@ -38,8 +68,9 @@ module ActiveRecord
|
|
38
68
|
# ==== Parameters
|
39
69
|
#
|
40
70
|
# * +attr_name+ - The field name that should be serialized.
|
41
|
-
# * +class_name_or_coder+ - Optional,
|
42
|
-
# or a
|
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.
|
43
74
|
#
|
44
75
|
# ==== Options
|
45
76
|
#
|
@@ -49,7 +80,7 @@ module ActiveRecord
|
|
49
80
|
#
|
50
81
|
# ==== Example
|
51
82
|
#
|
52
|
-
# # Serialize a preferences attribute.
|
83
|
+
# # Serialize a preferences attribute using YAML coder.
|
53
84
|
# class User < ActiveRecord::Base
|
54
85
|
# serialize :preferences
|
55
86
|
# end
|
@@ -63,6 +94,28 @@ module ActiveRecord
|
|
63
94
|
# class User < ActiveRecord::Base
|
64
95
|
# serialize :preferences, Hash
|
65
96
|
# end
|
97
|
+
#
|
98
|
+
# # Serialize preferences using a custom coder.
|
99
|
+
# class Rot13JSON
|
100
|
+
# def self.rot13(string)
|
101
|
+
# string.tr("a-zA-Z", "n-za-mN-ZA-M")
|
102
|
+
# end
|
103
|
+
#
|
104
|
+
# # returns serialized string that will be stored in the database
|
105
|
+
# def self.dump(object)
|
106
|
+
# ActiveSupport::JSON.encode(object).rot13
|
107
|
+
# end
|
108
|
+
#
|
109
|
+
# # reverses the above, turning the serialized string from the database
|
110
|
+
# # back into its original value
|
111
|
+
# def self.load(string)
|
112
|
+
# ActiveSupport::JSON.decode(string.rot13)
|
113
|
+
# end
|
114
|
+
# end
|
115
|
+
#
|
116
|
+
# class User < ActiveRecord::Base
|
117
|
+
# serialize :preferences, Rot13JSON
|
118
|
+
# end
|
66
119
|
def serialize(attr_name, class_name_or_coder = Object, **options)
|
67
120
|
# When ::JSON is used, force it to go through the Active Support JSON encoder
|
68
121
|
# to ensure special objects (e.g. Active Record models) are dumped correctly
|
@@ -75,11 +128,12 @@ module ActiveRecord
|
|
75
128
|
Coders::YAMLColumn.new(attr_name, class_name_or_coder)
|
76
129
|
end
|
77
130
|
|
78
|
-
|
131
|
+
attribute(attr_name, **options) do |cast_type|
|
79
132
|
if type_incompatible_with_serialize?(cast_type, class_name_or_coder)
|
80
133
|
raise ColumnNotSerializableError.new(attr_name, cast_type)
|
81
134
|
end
|
82
135
|
|
136
|
+
cast_type = cast_type.subtype if Type::Serialized === cast_type
|
83
137
|
Type::Serialized.new(cast_type, coder)
|
84
138
|
end
|
85
139
|
end
|
@@ -25,6 +25,8 @@ module ActiveRecord
|
|
25
25
|
rescue ArgumentError
|
26
26
|
nil
|
27
27
|
end
|
28
|
+
elsif value.respond_to?(:infinite?) && value.infinite?
|
29
|
+
value
|
28
30
|
else
|
29
31
|
map_avoiding_infinite_recursion(super) { |v| cast(v) }
|
30
32
|
end
|
@@ -36,7 +38,7 @@ module ActiveRecord
|
|
36
38
|
|
37
39
|
if value.acts_like?(:time)
|
38
40
|
value.in_time_zone
|
39
|
-
elsif value.
|
41
|
+
elsif value.respond_to?(:infinite?) && value.infinite?
|
40
42
|
value
|
41
43
|
else
|
42
44
|
map_avoiding_infinite_recursion(value) { |v| convert_time_to_time_zone(v) }
|
@@ -61,8 +63,7 @@ module ActiveRecord
|
|
61
63
|
extend ActiveSupport::Concern
|
62
64
|
|
63
65
|
included do
|
64
|
-
|
65
|
-
|
66
|
+
class_attribute :time_zone_aware_attributes, instance_writer: false, default: false
|
66
67
|
class_attribute :skip_time_zone_conversion_for_attributes, instance_writer: false, default: []
|
67
68
|
class_attribute :time_zone_aware_types, instance_writer: false, default: [ :datetime, :time ]
|
68
69
|
end
|
@@ -6,7 +6,7 @@ module ActiveRecord
|
|
6
6
|
extend ActiveSupport::Concern
|
7
7
|
|
8
8
|
included do
|
9
|
-
attribute_method_suffix "="
|
9
|
+
attribute_method_suffix "=", parameters: "value"
|
10
10
|
end
|
11
11
|
|
12
12
|
module ClassMethods # :nodoc:
|
@@ -15,10 +15,12 @@ module ActiveRecord
|
|
15
15
|
ActiveModel::AttributeMethods::AttrNames.define_attribute_accessor_method(
|
16
16
|
owner, name, writer: true,
|
17
17
|
) do |temp_method_name, attr_name_expr|
|
18
|
-
owner
|
19
|
-
|
20
|
-
|
21
|
-
|
18
|
+
owner.define_cached_method("#{name}=", as: temp_method_name, namespace: :active_record) do |batch|
|
19
|
+
batch <<
|
20
|
+
"def #{temp_method_name}(value)" <<
|
21
|
+
" _write_attribute(#{attr_name_expr}, value)" <<
|
22
|
+
"end"
|
23
|
+
end
|
22
24
|
end
|
23
25
|
end
|
24
26
|
end
|
@@ -42,11 +44,6 @@ module ActiveRecord
|
|
42
44
|
|
43
45
|
alias :attribute= :_write_attribute
|
44
46
|
private :attribute=
|
45
|
-
|
46
|
-
private
|
47
|
-
def write_attribute_without_type_cast(attr_name, value)
|
48
|
-
@attributes.write_cast_value(attr_name, value)
|
49
|
-
end
|
50
47
|
end
|
51
48
|
end
|
52
49
|
end
|
@@ -23,7 +23,7 @@ module ActiveRecord
|
|
23
23
|
|
24
24
|
RESTRICTED_CLASS_METHODS = %w(private public protected allocate new name parent superclass)
|
25
25
|
|
26
|
-
class GeneratedAttributeMethods < Module
|
26
|
+
class GeneratedAttributeMethods < Module # :nodoc:
|
27
27
|
include Mutex_m
|
28
28
|
end
|
29
29
|
|
@@ -39,7 +39,7 @@ module ActiveRecord
|
|
39
39
|
end
|
40
40
|
|
41
41
|
module ClassMethods
|
42
|
-
def inherited(child_class)
|
42
|
+
def inherited(child_class) # :nodoc:
|
43
43
|
child_class.initialize_generated_modules
|
44
44
|
super
|
45
45
|
end
|
@@ -267,9 +267,8 @@ module ActiveRecord
|
|
267
267
|
|
268
268
|
# Returns an <tt>#inspect</tt>-like string for the value of the
|
269
269
|
# attribute +attr_name+. String attributes are truncated up to 50
|
270
|
-
# characters
|
271
|
-
#
|
272
|
-
# <tt>#inspect</tt> without modification.
|
270
|
+
# characters. Other attributes return the value of <tt>#inspect</tt>
|
271
|
+
# without modification.
|
273
272
|
#
|
274
273
|
# person = Person.create!(name: 'David Heinemeier Hansson ' * 3)
|
275
274
|
#
|
@@ -277,7 +276,7 @@ module ActiveRecord
|
|
277
276
|
# # => "\"David Heinemeier Hansson David Heinemeier Hansson ...\""
|
278
277
|
#
|
279
278
|
# person.attribute_for_inspect(:created_at)
|
280
|
-
# # => "\"2012-10-22 00:15:07\""
|
279
|
+
# # => "\"2012-10-22 00:15:07.000000000 +0000\""
|
281
280
|
#
|
282
281
|
# person.attribute_for_inspect(:tag_ids)
|
283
282
|
# # => "[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]"
|
@@ -385,9 +384,7 @@ module ActiveRecord
|
|
385
384
|
end
|
386
385
|
|
387
386
|
def attributes_with_values(attribute_names)
|
388
|
-
attribute_names.index_with
|
389
|
-
_read_attribute(name)
|
390
|
-
end
|
387
|
+
attribute_names.index_with { |name| @attributes[name] }
|
391
388
|
end
|
392
389
|
|
393
390
|
# Filters the primary keys and readonly attributes from the attribute names.
|
@@ -12,9 +12,6 @@ module ActiveRecord
|
|
12
12
|
end
|
13
13
|
|
14
14
|
module ClassMethods
|
15
|
-
##
|
16
|
-
# :call-seq: attribute(name, cast_type = nil, **options)
|
17
|
-
#
|
18
15
|
# Defines an attribute with a type on this model. It will override the
|
19
16
|
# type of existing attributes if needed. This allows control over how
|
20
17
|
# values are converted to and from SQL when assigned to a model. It also
|
@@ -208,14 +205,31 @@ module ActiveRecord
|
|
208
205
|
# tracking is performed. The methods +changed?+ and +changed_in_place?+
|
209
206
|
# will be called from ActiveModel::Dirty. See the documentation for those
|
210
207
|
# methods in ActiveModel::Type::Value for more details.
|
211
|
-
def attribute(name, cast_type = nil, **options
|
208
|
+
def attribute(name, cast_type = nil, default: NO_DEFAULT_PROVIDED, **options)
|
212
209
|
name = name.to_s
|
210
|
+
name = attribute_aliases[name] || name
|
211
|
+
|
213
212
|
reload_schema_from_cache
|
214
213
|
|
214
|
+
case cast_type
|
215
|
+
when Symbol
|
216
|
+
cast_type = Type.lookup(cast_type, **options, adapter: Type.adapter_name_from(self))
|
217
|
+
when nil
|
218
|
+
if (prev_cast_type, prev_default = attributes_to_define_after_schema_loads[name])
|
219
|
+
default = prev_default if default == NO_DEFAULT_PROVIDED
|
220
|
+
else
|
221
|
+
prev_cast_type = -> subtype { subtype }
|
222
|
+
end
|
223
|
+
|
224
|
+
cast_type = if block_given?
|
225
|
+
-> subtype { yield Proc === prev_cast_type ? prev_cast_type[subtype] : prev_cast_type }
|
226
|
+
else
|
227
|
+
prev_cast_type
|
228
|
+
end
|
229
|
+
end
|
230
|
+
|
215
231
|
self.attributes_to_define_after_schema_loads =
|
216
|
-
attributes_to_define_after_schema_loads.merge(
|
217
|
-
name => [cast_type || block, options]
|
218
|
-
)
|
232
|
+
attributes_to_define_after_schema_loads.merge(name => [cast_type, default])
|
219
233
|
end
|
220
234
|
|
221
235
|
# This is the low level API which sits beneath +attribute+. It only
|
@@ -248,8 +262,9 @@ module ActiveRecord
|
|
248
262
|
|
249
263
|
def load_schema! # :nodoc:
|
250
264
|
super
|
251
|
-
attributes_to_define_after_schema_loads.each do |name, (
|
252
|
-
|
265
|
+
attributes_to_define_after_schema_loads.each do |name, (cast_type, default)|
|
266
|
+
cast_type = cast_type[type_for_attribute(name)] if Proc === cast_type
|
267
|
+
define_attribute(name, cast_type, default: default)
|
253
268
|
end
|
254
269
|
end
|
255
270
|
|
@@ -272,32 +287,6 @@ module ActiveRecord
|
|
272
287
|
end
|
273
288
|
_default_attributes[name] = default_attribute
|
274
289
|
end
|
275
|
-
|
276
|
-
def decorate_attribute_type(attr_name, **default)
|
277
|
-
type, options = attributes_to_define_after_schema_loads[attr_name]
|
278
|
-
|
279
|
-
default.with_defaults!(default: options[:default]) if options&.key?(:default)
|
280
|
-
|
281
|
-
attribute(attr_name, **default) do |cast_type|
|
282
|
-
if type && !type.is_a?(Proc)
|
283
|
-
cast_type = _lookup_cast_type(attr_name, type, options)
|
284
|
-
end
|
285
|
-
|
286
|
-
yield cast_type
|
287
|
-
end
|
288
|
-
end
|
289
|
-
|
290
|
-
def _lookup_cast_type(name, type, options)
|
291
|
-
case type
|
292
|
-
when Symbol
|
293
|
-
adapter_name = ActiveRecord::Type.adapter_name_from(self)
|
294
|
-
ActiveRecord::Type.lookup(type, **options.except(:default), adapter: adapter_name)
|
295
|
-
when Proc
|
296
|
-
type[type_for_attribute(name)]
|
297
|
-
else
|
298
|
-
type || type_for_attribute(name)
|
299
|
-
end
|
300
|
-
end
|
301
290
|
end
|
302
291
|
end
|
303
292
|
end
|
@@ -138,7 +138,7 @@ module ActiveRecord
|
|
138
138
|
module AutosaveAssociation
|
139
139
|
extend ActiveSupport::Concern
|
140
140
|
|
141
|
-
module AssociationBuilderExtension
|
141
|
+
module AssociationBuilderExtension # :nodoc:
|
142
142
|
def self.build(model, reflection)
|
143
143
|
model.send(:add_autosave_association_callbacks, reflection)
|
144
144
|
end
|
@@ -150,25 +150,10 @@ module ActiveRecord
|
|
150
150
|
|
151
151
|
included do
|
152
152
|
Associations::Builder::Association.extensions << AssociationBuilderExtension
|
153
|
-
mattr_accessor :index_nested_attribute_errors, instance_writer: false, default: false
|
154
153
|
end
|
155
154
|
|
156
155
|
module ClassMethods # :nodoc:
|
157
156
|
private
|
158
|
-
if Module.method(:method_defined?).arity == 1 # MRI 2.5 and older
|
159
|
-
using Module.new {
|
160
|
-
refine Module do
|
161
|
-
def method_defined?(method, inherit = true)
|
162
|
-
if inherit
|
163
|
-
super(method)
|
164
|
-
else
|
165
|
-
instance_methods(false).include?(method.to_sym)
|
166
|
-
end
|
167
|
-
end
|
168
|
-
end
|
169
|
-
}
|
170
|
-
end
|
171
|
-
|
172
157
|
def define_non_cyclic_method(name, &block)
|
173
158
|
return if method_defined?(name, false)
|
174
159
|
|
@@ -210,7 +195,7 @@ module ActiveRecord
|
|
210
195
|
after_create save_method
|
211
196
|
after_update save_method
|
212
197
|
elsif reflection.has_one?
|
213
|
-
|
198
|
+
define_non_cyclic_method(save_method) { save_has_one_association(reflection) }
|
214
199
|
# Configures two callbacks instead of a single after_save so that
|
215
200
|
# the model may rely on their execution order relative to its
|
216
201
|
# own callbacks.
|
@@ -349,7 +334,7 @@ module ActiveRecord
|
|
349
334
|
|
350
335
|
unless valid = record.valid?(context)
|
351
336
|
if reflection.options[:autosave]
|
352
|
-
indexed_attribute = !index.nil? && (reflection.options[:index_errors] || ActiveRecord
|
337
|
+
indexed_attribute = !index.nil? && (reflection.options[:index_errors] || ActiveRecord.index_nested_attribute_errors)
|
353
338
|
|
354
339
|
record.errors.group_by_attribute.each { |attribute, errors|
|
355
340
|
attribute = normalize_reflection_attribute(indexed_attribute, reflection, index, attribute)
|
data/lib/active_record/base.rb
CHANGED
@@ -12,7 +12,7 @@ require "active_record/attributes"
|
|
12
12
|
require "active_record/type_caster"
|
13
13
|
require "active_record/database_configurations"
|
14
14
|
|
15
|
-
module ActiveRecord
|
15
|
+
module ActiveRecord # :nodoc:
|
16
16
|
# = Active Record
|
17
17
|
#
|
18
18
|
# Active Record objects don't specify their attributes directly, but rather infer them from
|
@@ -137,6 +137,23 @@ 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:
|
141
|
+
#
|
142
|
+
# class User
|
143
|
+
# # Has admin boolean column
|
144
|
+
# def admin
|
145
|
+
# false
|
146
|
+
# end
|
147
|
+
# end
|
148
|
+
#
|
149
|
+
# user.update(admin: true)
|
150
|
+
#
|
151
|
+
# user.read_attribute(:admin) # => true, gets the column value
|
152
|
+
# user[:admin] # => true, also gets the column value
|
153
|
+
#
|
154
|
+
# user.admin # => false, due to the getter overwrite
|
155
|
+
# user.admin? # => false, due to the getter overwrite
|
156
|
+
#
|
140
157
|
# == Accessing attributes before they have been typecasted
|
141
158
|
#
|
142
159
|
# Sometimes you want to be able to read the raw attribute data without having the column-determined
|
@@ -310,6 +327,7 @@ module ActiveRecord #:nodoc:
|
|
310
327
|
include SecureToken
|
311
328
|
include SignedId
|
312
329
|
include Suppressor
|
330
|
+
include Encryption::EncryptableRecord
|
313
331
|
end
|
314
332
|
|
315
333
|
ActiveSupport.run_load_hooks(:active_record, Base)
|
@@ -432,7 +432,7 @@ module ActiveRecord
|
|
432
432
|
define_model_callbacks :save, :create, :update, :destroy
|
433
433
|
end
|
434
434
|
|
435
|
-
def destroy
|
435
|
+
def destroy # :nodoc:
|
436
436
|
@_destroy_callback_already_called ||= false
|
437
437
|
return if @_destroy_callback_already_called
|
438
438
|
@_destroy_callback_already_called = true
|
@@ -444,7 +444,7 @@ module ActiveRecord
|
|
444
444
|
@_destroy_callback_already_called = false
|
445
445
|
end
|
446
446
|
|
447
|
-
def touch(*, **)
|
447
|
+
def touch(*, **) # :nodoc:
|
448
448
|
_run_touch_callbacks { super }
|
449
449
|
end
|
450
450
|
|
@@ -47,23 +47,11 @@ module ActiveRecord
|
|
47
47
|
|
48
48
|
if YAML.respond_to?(:unsafe_load)
|
49
49
|
def yaml_load(payload)
|
50
|
-
|
51
|
-
YAML.unsafe_load(payload)
|
52
|
-
elsif YAML.method(:safe_load).parameters.include?([:key, :permitted_classes])
|
53
|
-
YAML.safe_load(payload, permitted_classes: ActiveRecord::Base.yaml_column_permitted_classes, aliases: true)
|
54
|
-
else
|
55
|
-
YAML.safe_load(payload, ActiveRecord::Base.yaml_column_permitted_classes, [], true)
|
56
|
-
end
|
50
|
+
YAML.unsafe_load(payload)
|
57
51
|
end
|
58
52
|
else
|
59
53
|
def yaml_load(payload)
|
60
|
-
|
61
|
-
YAML.load(payload)
|
62
|
-
elsif YAML.method(:safe_load).parameters.include?([:key, :permitted_classes])
|
63
|
-
YAML.safe_load(payload, permitted_classes: ActiveRecord::Base.yaml_column_permitted_classes, aliases: true)
|
64
|
-
else
|
65
|
-
YAML.safe_load(payload, ActiveRecord::Base.yaml_column_permitted_classes, [], true)
|
66
|
-
end
|
54
|
+
YAML.load(payload)
|
67
55
|
end
|
68
56
|
end
|
69
57
|
end
|