activerecord 6.1.4 → 7.0.0.rc1
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of activerecord might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/CHANGELOG.md +1049 -977
- 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 +33 -17
- 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 +10 -3
- 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 +34 -27
- 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 +187 -55
- data/lib/active_record/associations/preloader/batch.rb +48 -0
- data/lib/active_record/associations/preloader/branch.rb +147 -0
- data/lib/active_record/associations/preloader/through_association.rb +49 -13
- data/lib/active_record/associations/preloader.rb +39 -113
- data/lib/active_record/associations/singular_association.rb +8 -2
- data/lib/active_record/associations/through_association.rb +3 -3
- data/lib/active_record/associations.rb +90 -82
- data/lib/active_record/asynchronous_queries_tracker.rb +60 -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 +49 -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 +13 -14
- data/lib/active_record/attributes.rb +24 -35
- data/lib/active_record/autosave_association.rb +6 -21
- data/lib/active_record/base.rb +19 -1
- data/lib/active_record/callbacks.rb +2 -2
- data/lib/active_record/connection_adapters/abstract/connection_handler.rb +292 -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 +47 -561
- data/lib/active_record/connection_adapters/abstract/database_limits.rb +0 -17
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +46 -22
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +24 -12
- data/lib/active_record/connection_adapters/abstract/quoting.rb +42 -72
- data/lib/active_record/connection_adapters/abstract/schema_creation.rb +4 -17
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +34 -9
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +69 -18
- data/lib/active_record/connection_adapters/abstract/transaction.rb +15 -22
- data/lib/active_record/connection_adapters/abstract_adapter.rb +149 -74
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +97 -81
- data/lib/active_record/connection_adapters/column.rb +4 -0
- data/lib/active_record/connection_adapters/mysql/database_statements.rb +35 -23
- data/lib/active_record/connection_adapters/mysql/quoting.rb +35 -21
- data/lib/active_record/connection_adapters/mysql/schema_statements.rb +4 -1
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +12 -6
- data/lib/active_record/connection_adapters/pool_config.rb +7 -7
- data/lib/active_record/connection_adapters/postgresql/column.rb +17 -1
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +19 -12
- 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 +50 -50
- data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +32 -0
- data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +21 -1
- data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +22 -1
- data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +25 -0
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +27 -16
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +205 -105
- data/lib/active_record/connection_adapters/schema_cache.rb +29 -4
- data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +25 -19
- data/lib/active_record/connection_adapters/sqlite3/quoting.rb +15 -16
- 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 +47 -53
- data/lib/active_record/core.rb +122 -132
- data/lib/active_record/database_configurations/connection_url_resolver.rb +2 -1
- data/lib/active_record/database_configurations/database_config.rb +12 -9
- data/lib/active_record/database_configurations/hash_config.rb +63 -5
- data/lib/active_record/database_configurations/url_config.rb +2 -2
- data/lib/active_record/database_configurations.rb +16 -32
- data/lib/active_record/delegated_type.rb +52 -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 +28 -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 +90 -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 +49 -42
- data/lib/active_record/errors.rb +67 -4
- data/lib/active_record/explain_registry.rb +11 -6
- data/lib/active_record/fixture_set/file.rb +15 -1
- data/lib/active_record/fixture_set/table_row.rb +41 -6
- data/lib/active_record/fixture_set/table_rows.rb +4 -4
- data/lib/active_record/fixtures.rb +17 -20
- 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 +80 -14
- data/lib/active_record/integration.rb +4 -3
- data/lib/active_record/internal_metadata.rb +3 -5
- data/lib/active_record/legacy_yaml_adapter.rb +2 -39
- data/lib/active_record/locking/optimistic.rb +10 -9
- data/lib/active_record/locking/pessimistic.rb +9 -3
- data/lib/active_record/log_subscriber.rb +14 -3
- 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/middleware/shard_selector.rb +60 -0
- data/lib/active_record/migration/command_recorder.rb +4 -4
- data/lib/active_record/migration/compatibility.rb +83 -1
- 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 -58
- data/lib/active_record/nested_attributes.rb +13 -12
- data/lib/active_record/no_touching.rb +3 -3
- data/lib/active_record/null_relation.rb +2 -6
- data/lib/active_record/persistence.rb +219 -52
- data/lib/active_record/query_cache.rb +2 -2
- data/lib/active_record/query_logs.rb +138 -0
- data/lib/active_record/querying.rb +15 -5
- data/lib/active_record/railtie.rb +127 -17
- data/lib/active_record/railties/controller_runtime.rb +1 -1
- data/lib/active_record/railties/databases.rake +66 -129
- data/lib/active_record/readonly_attributes.rb +11 -0
- data/lib/active_record/reflection.rb +67 -50
- 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 +40 -36
- data/lib/active_record/relation/delegation.rb +6 -6
- data/lib/active_record/relation/finder_methods.rb +31 -35
- 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 +235 -61
- data/lib/active_record/relation/record_fetch_warning.rb +7 -9
- data/lib/active_record/relation/spawn_methods.rb +2 -2
- data/lib/active_record/relation/where_clause.rb +10 -19
- data/lib/active_record/relation.rb +171 -84
- data/lib/active_record/result.rb +17 -7
- data/lib/active_record/runtime_registry.rb +9 -13
- data/lib/active_record/sanitization.rb +11 -7
- data/lib/active_record/schema_dumper.rb +10 -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 +64 -34
- data/lib/active_record/serialization.rb +1 -1
- data/lib/active_record/signed_id.rb +1 -1
- data/lib/active_record/suppressor.rb +11 -15
- data/lib/active_record/tasks/database_tasks.rb +116 -58
- data/lib/active_record/tasks/mysql_database_tasks.rb +1 -1
- data/lib/active_record/tasks/postgresql_database_tasks.rb +19 -12
- data/lib/active_record/test_databases.rb +1 -1
- data/lib/active_record/test_fixtures.rb +4 -4
- 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/validations/uniqueness.rb +1 -1
- data/lib/active_record.rb +204 -28
- data/lib/arel/attributes/attribute.rb +0 -8
- data/lib/arel/crud.rb +28 -22
- data/lib/arel/delete_manager.rb +18 -4
- data/lib/arel/filter_predications.rb +9 -0
- data/lib/arel/insert_manager.rb +2 -3
- data/lib/arel/nodes/casted.rb +1 -1
- data/lib/arel/nodes/delete_statement.rb +12 -13
- data/lib/arel/nodes/filter.rb +10 -0
- data/lib/arel/nodes/function.rb +1 -0
- 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 +8 -3
- data/lib/arel/nodes.rb +1 -0
- data/lib/arel/predications.rb +11 -3
- 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 +18 -4
- data/lib/arel/visitors/dot.rb +80 -90
- data/lib/arel/visitors/mysql.rb +8 -2
- data/lib/arel/visitors/postgresql.rb +0 -10
- data/lib/arel/visitors/to_sql.rb +58 -2
- data/lib/arel.rb +2 -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 +56 -13
@@ -1,11 +1,9 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require "active_support/core_ext/enumerable"
|
4
|
-
require "active_support/core_ext/string/conversions"
|
5
|
-
|
6
3
|
module ActiveRecord
|
7
|
-
class AssociationNotFoundError < ConfigurationError
|
4
|
+
class AssociationNotFoundError < ConfigurationError # :nodoc:
|
8
5
|
attr_reader :record, :association_name
|
6
|
+
|
9
7
|
def initialize(record = nil, association_name = nil)
|
10
8
|
@record = record
|
11
9
|
@association_name = association_name
|
@@ -16,32 +14,25 @@ module ActiveRecord
|
|
16
14
|
end
|
17
15
|
end
|
18
16
|
|
19
|
-
|
20
|
-
|
21
|
-
@error = error
|
22
|
-
end
|
17
|
+
if defined?(DidYouMean::Correctable) && defined?(DidYouMean::SpellChecker)
|
18
|
+
include DidYouMean::Correctable
|
23
19
|
|
24
20
|
def corrections
|
25
|
-
if
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
}.reverse.first(4)
|
21
|
+
if record && association_name
|
22
|
+
@corrections ||= begin
|
23
|
+
maybe_these = record.class.reflections.keys
|
24
|
+
DidYouMean::SpellChecker.new(dictionary: maybe_these).correct(association_name)
|
25
|
+
end
|
31
26
|
else
|
32
27
|
[]
|
33
28
|
end
|
34
29
|
end
|
35
30
|
end
|
36
|
-
|
37
|
-
# We may not have DYM, and DYM might not let us register error handlers
|
38
|
-
if defined?(DidYouMean) && DidYouMean.respond_to?(:correct_error)
|
39
|
-
DidYouMean.correct_error(self, Correction)
|
40
|
-
end
|
41
31
|
end
|
42
32
|
|
43
|
-
class InverseOfAssociationNotFoundError < ActiveRecordError
|
33
|
+
class InverseOfAssociationNotFoundError < ActiveRecordError # :nodoc:
|
44
34
|
attr_reader :reflection, :associated_class
|
35
|
+
|
45
36
|
def initialize(reflection = nil, associated_class = nil)
|
46
37
|
if reflection
|
47
38
|
@reflection = reflection
|
@@ -52,31 +43,35 @@ module ActiveRecord
|
|
52
43
|
end
|
53
44
|
end
|
54
45
|
|
55
|
-
|
56
|
-
|
57
|
-
@error = error
|
58
|
-
end
|
46
|
+
if defined?(DidYouMean::Correctable) && defined?(DidYouMean::SpellChecker)
|
47
|
+
include DidYouMean::Correctable
|
59
48
|
|
60
49
|
def corrections
|
61
|
-
if
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
}.reverse.first(4)
|
50
|
+
if reflection && associated_class
|
51
|
+
@corrections ||= begin
|
52
|
+
maybe_these = associated_class.reflections.keys
|
53
|
+
DidYouMean::SpellChecker.new(dictionary: maybe_these).correct(reflection.options[:inverse_of].to_s)
|
54
|
+
end
|
67
55
|
else
|
68
56
|
[]
|
69
57
|
end
|
70
58
|
end
|
71
59
|
end
|
60
|
+
end
|
72
61
|
|
73
|
-
|
74
|
-
|
75
|
-
|
62
|
+
class InverseOfAssociationRecursiveError < ActiveRecordError # :nodoc:
|
63
|
+
attr_reader :reflection
|
64
|
+
def initialize(reflection = nil)
|
65
|
+
if reflection
|
66
|
+
@reflection = reflection
|
67
|
+
super("Inverse association #{reflection.name} (#{reflection.options[:inverse_of].inspect} in #{reflection.class_name}) is recursive.")
|
68
|
+
else
|
69
|
+
super("Inverse association is recursive.")
|
70
|
+
end
|
76
71
|
end
|
77
72
|
end
|
78
73
|
|
79
|
-
class HasManyThroughAssociationNotFoundError < ActiveRecordError
|
74
|
+
class HasManyThroughAssociationNotFoundError < ActiveRecordError # :nodoc:
|
80
75
|
attr_reader :owner_class, :reflection
|
81
76
|
|
82
77
|
def initialize(owner_class = nil, reflection = nil)
|
@@ -89,32 +84,24 @@ module ActiveRecord
|
|
89
84
|
end
|
90
85
|
end
|
91
86
|
|
92
|
-
|
93
|
-
|
94
|
-
@error = error
|
95
|
-
end
|
87
|
+
if defined?(DidYouMean::Correctable) && defined?(DidYouMean::SpellChecker)
|
88
|
+
include DidYouMean::Correctable
|
96
89
|
|
97
90
|
def corrections
|
98
|
-
if
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
}.reverse.first(4)
|
91
|
+
if owner_class && reflection
|
92
|
+
@corrections ||= begin
|
93
|
+
maybe_these = owner_class.reflections.keys
|
94
|
+
maybe_these -= [reflection.name.to_s] # remove failing reflection
|
95
|
+
DidYouMean::SpellChecker.new(dictionary: maybe_these).correct(reflection.options[:through].to_s)
|
96
|
+
end
|
105
97
|
else
|
106
98
|
[]
|
107
99
|
end
|
108
100
|
end
|
109
101
|
end
|
110
|
-
|
111
|
-
# We may not have DYM, and DYM might not let us register error handlers
|
112
|
-
if defined?(DidYouMean) && DidYouMean.respond_to?(:correct_error)
|
113
|
-
DidYouMean.correct_error(self, Correction)
|
114
|
-
end
|
115
102
|
end
|
116
103
|
|
117
|
-
class HasManyThroughAssociationPolymorphicSourceError < ActiveRecordError
|
104
|
+
class HasManyThroughAssociationPolymorphicSourceError < ActiveRecordError # :nodoc:
|
118
105
|
def initialize(owner_class_name = nil, reflection = nil, source_reflection = nil)
|
119
106
|
if owner_class_name && reflection && source_reflection
|
120
107
|
super("Cannot have a has_many :through association '#{owner_class_name}##{reflection.name}' on the polymorphic object '#{source_reflection.class_name}##{source_reflection.name}' without 'source_type'. Try adding 'source_type: \"#{reflection.name.to_s.classify}\"' to 'has_many :through' definition.")
|
@@ -124,7 +111,7 @@ module ActiveRecord
|
|
124
111
|
end
|
125
112
|
end
|
126
113
|
|
127
|
-
class HasManyThroughAssociationPolymorphicThroughError < ActiveRecordError
|
114
|
+
class HasManyThroughAssociationPolymorphicThroughError < ActiveRecordError # :nodoc:
|
128
115
|
def initialize(owner_class_name = nil, reflection = nil)
|
129
116
|
if owner_class_name && reflection
|
130
117
|
super("Cannot have a has_many :through association '#{owner_class_name}##{reflection.name}' which goes through the polymorphic association '#{owner_class_name}##{reflection.through_reflection.name}'.")
|
@@ -134,7 +121,7 @@ module ActiveRecord
|
|
134
121
|
end
|
135
122
|
end
|
136
123
|
|
137
|
-
class HasManyThroughAssociationPointlessSourceTypeError < ActiveRecordError
|
124
|
+
class HasManyThroughAssociationPointlessSourceTypeError < ActiveRecordError # :nodoc:
|
138
125
|
def initialize(owner_class_name = nil, reflection = nil, source_reflection = nil)
|
139
126
|
if owner_class_name && reflection && source_reflection
|
140
127
|
super("Cannot have a has_many :through association '#{owner_class_name}##{reflection.name}' with a :source_type option if the '#{reflection.through_reflection.class_name}##{source_reflection.name}' is not polymorphic. Try removing :source_type on your association.")
|
@@ -144,7 +131,7 @@ module ActiveRecord
|
|
144
131
|
end
|
145
132
|
end
|
146
133
|
|
147
|
-
class HasOneThroughCantAssociateThroughCollection < ActiveRecordError
|
134
|
+
class HasOneThroughCantAssociateThroughCollection < ActiveRecordError # :nodoc:
|
148
135
|
def initialize(owner_class_name = nil, reflection = nil, through_reflection = nil)
|
149
136
|
if owner_class_name && reflection && through_reflection
|
150
137
|
super("Cannot have a has_one :through association '#{owner_class_name}##{reflection.name}' where the :through association '#{owner_class_name}##{through_reflection.name}' is a collection. Specify a has_one or belongs_to association in the :through option instead.")
|
@@ -154,7 +141,7 @@ module ActiveRecord
|
|
154
141
|
end
|
155
142
|
end
|
156
143
|
|
157
|
-
class HasOneAssociationPolymorphicThroughError < ActiveRecordError
|
144
|
+
class HasOneAssociationPolymorphicThroughError < ActiveRecordError # :nodoc:
|
158
145
|
def initialize(owner_class_name = nil, reflection = nil)
|
159
146
|
if owner_class_name && reflection
|
160
147
|
super("Cannot have a has_one :through association '#{owner_class_name}##{reflection.name}' which goes through the polymorphic association '#{owner_class_name}##{reflection.through_reflection.name}'.")
|
@@ -164,7 +151,7 @@ module ActiveRecord
|
|
164
151
|
end
|
165
152
|
end
|
166
153
|
|
167
|
-
class HasManyThroughSourceAssociationNotFoundError < ActiveRecordError
|
154
|
+
class HasManyThroughSourceAssociationNotFoundError < ActiveRecordError # :nodoc:
|
168
155
|
def initialize(reflection = nil)
|
169
156
|
if reflection
|
170
157
|
through_reflection = reflection.through_reflection
|
@@ -177,7 +164,7 @@ module ActiveRecord
|
|
177
164
|
end
|
178
165
|
end
|
179
166
|
|
180
|
-
class HasManyThroughOrderError < ActiveRecordError
|
167
|
+
class HasManyThroughOrderError < ActiveRecordError # :nodoc:
|
181
168
|
def initialize(owner_class_name = nil, reflection = nil, through_reflection = nil)
|
182
169
|
if owner_class_name && reflection && through_reflection
|
183
170
|
super("Cannot have a has_many :through association '#{owner_class_name}##{reflection.name}' which goes through '#{owner_class_name}##{through_reflection.name}' before the through association is defined.")
|
@@ -187,7 +174,7 @@ module ActiveRecord
|
|
187
174
|
end
|
188
175
|
end
|
189
176
|
|
190
|
-
class ThroughCantAssociateThroughHasOneOrManyReflection < ActiveRecordError
|
177
|
+
class ThroughCantAssociateThroughHasOneOrManyReflection < ActiveRecordError # :nodoc:
|
191
178
|
def initialize(owner = nil, reflection = nil)
|
192
179
|
if owner && reflection
|
193
180
|
super("Cannot modify association '#{owner.class.name}##{reflection.name}' because the source reflection class '#{reflection.source_reflection.class_name}' is associated to '#{reflection.through_reflection.class_name}' via :#{reflection.source_reflection.macro}.")
|
@@ -212,13 +199,13 @@ module ActiveRecord
|
|
212
199
|
end
|
213
200
|
end
|
214
201
|
|
215
|
-
class HasManyThroughCantAssociateThroughHasOneOrManyReflection < ThroughCantAssociateThroughHasOneOrManyReflection
|
202
|
+
class HasManyThroughCantAssociateThroughHasOneOrManyReflection < ThroughCantAssociateThroughHasOneOrManyReflection # :nodoc:
|
216
203
|
end
|
217
204
|
|
218
|
-
class HasOneThroughCantAssociateThroughHasOneOrManyReflection < ThroughCantAssociateThroughHasOneOrManyReflection
|
205
|
+
class HasOneThroughCantAssociateThroughHasOneOrManyReflection < ThroughCantAssociateThroughHasOneOrManyReflection # :nodoc:
|
219
206
|
end
|
220
207
|
|
221
|
-
class ThroughNestedAssociationsAreReadonly < ActiveRecordError
|
208
|
+
class ThroughNestedAssociationsAreReadonly < ActiveRecordError # :nodoc:
|
222
209
|
def initialize(owner = nil, reflection = nil)
|
223
210
|
if owner && reflection
|
224
211
|
super("Cannot modify association '#{owner.class.name}##{reflection.name}' because it goes through more than one other association.")
|
@@ -228,10 +215,10 @@ module ActiveRecord
|
|
228
215
|
end
|
229
216
|
end
|
230
217
|
|
231
|
-
class HasManyThroughNestedAssociationsAreReadonly < ThroughNestedAssociationsAreReadonly
|
218
|
+
class HasManyThroughNestedAssociationsAreReadonly < ThroughNestedAssociationsAreReadonly # :nodoc:
|
232
219
|
end
|
233
220
|
|
234
|
-
class HasOneThroughNestedAssociationsAreReadonly < ThroughNestedAssociationsAreReadonly
|
221
|
+
class HasOneThroughNestedAssociationsAreReadonly < ThroughNestedAssociationsAreReadonly # :nodoc:
|
235
222
|
end
|
236
223
|
|
237
224
|
# This error is raised when trying to eager load a polymorphic association using a JOIN.
|
@@ -250,7 +237,7 @@ module ActiveRecord
|
|
250
237
|
# This error is raised when trying to destroy a parent instance in N:1 or 1:1 associations
|
251
238
|
# (has_many, has_one) when there is at least 1 child associated instance.
|
252
239
|
# ex: if @project.tasks.size > 0, DeleteRestrictionError will be raised when trying to destroy @project
|
253
|
-
class DeleteRestrictionError < ActiveRecordError
|
240
|
+
class DeleteRestrictionError < ActiveRecordError # :nodoc:
|
254
241
|
def initialize(name = nil)
|
255
242
|
if name
|
256
243
|
super("Cannot delete record because of dependent #{name}")
|
@@ -274,7 +261,7 @@ module ActiveRecord
|
|
274
261
|
autoload :CollectionProxy
|
275
262
|
autoload :ThroughAssociation
|
276
263
|
|
277
|
-
module Builder
|
264
|
+
module Builder # :nodoc:
|
278
265
|
autoload :Association, "active_record/associations/builder/association"
|
279
266
|
autoload :SingularAssociation, "active_record/associations/builder/singular_association"
|
280
267
|
autoload :CollectionAssociation, "active_record/associations/builder/collection_association"
|
@@ -296,6 +283,7 @@ module ActiveRecord
|
|
296
283
|
autoload :Preloader
|
297
284
|
autoload :JoinDependency
|
298
285
|
autoload :AssociationScope
|
286
|
+
autoload :DisableJoinsAssociationScope
|
299
287
|
autoload :AliasTracker
|
300
288
|
end
|
301
289
|
|
@@ -305,7 +293,7 @@ module ActiveRecord
|
|
305
293
|
end
|
306
294
|
|
307
295
|
# Returns the association instance for the given name, instantiating it if it doesn't already exist
|
308
|
-
def association(name)
|
296
|
+
def association(name) # :nodoc:
|
309
297
|
association = association_instance_get(name)
|
310
298
|
|
311
299
|
if association.nil?
|
@@ -328,17 +316,7 @@ module ActiveRecord
|
|
328
316
|
super
|
329
317
|
end
|
330
318
|
|
331
|
-
def reload(*) # :nodoc:
|
332
|
-
clear_association_cache
|
333
|
-
super
|
334
|
-
end
|
335
|
-
|
336
319
|
private
|
337
|
-
# Clears out the association cache.
|
338
|
-
def clear_association_cache
|
339
|
-
@association_cache.clear if persisted?
|
340
|
-
end
|
341
|
-
|
342
320
|
def init_internals
|
343
321
|
@association_cache = {}
|
344
322
|
super
|
@@ -398,6 +376,8 @@ module ActiveRecord
|
|
398
376
|
# create_other(attributes={}) | X | | X
|
399
377
|
# create_other!(attributes={}) | X | | X
|
400
378
|
# reload_other | X | X | X
|
379
|
+
# other_changed? | X | X |
|
380
|
+
# other_previously_changed? | X | X |
|
401
381
|
#
|
402
382
|
# === Collection associations (one-to-many / many-to-many)
|
403
383
|
# | | | has_many
|
@@ -780,9 +760,10 @@ module ActiveRecord
|
|
780
760
|
# inverse detection only works on #has_many, #has_one, and
|
781
761
|
# #belongs_to associations.
|
782
762
|
#
|
783
|
-
# <tt>:foreign_key</tt> and <tt>:through</tt> options on the associations
|
784
|
-
#
|
785
|
-
#
|
763
|
+
# <tt>:foreign_key</tt> and <tt>:through</tt> options on the associations
|
764
|
+
# will also prevent the association's inverse from being found automatically,
|
765
|
+
# as will a custom scopes in some cases. See further details in the
|
766
|
+
# {Active Record Associations guide}[https://guides.rubyonrails.org/association_basics.html#bi-directional-associations].
|
786
767
|
#
|
787
768
|
# The automatic guessing of the inverse association uses a heuristic based
|
788
769
|
# on the name of the class, so it may not work for all associations,
|
@@ -1410,6 +1391,11 @@ module ActiveRecord
|
|
1410
1391
|
# join model. This allows associated records to be built which will automatically create
|
1411
1392
|
# the appropriate join model records when they are saved. (See the 'Association Join Models'
|
1412
1393
|
# section above.)
|
1394
|
+
# [:disable_joins]
|
1395
|
+
# Specifies whether joins should be skipped for an association. If set to true, two or more queries
|
1396
|
+
# will be generated. Note that in some cases, if order or limit is applied, it will be done in-memory
|
1397
|
+
# due to database limitations. This option is only applicable on `has_many :through` associations as
|
1398
|
+
# `has_many` alone do not perform a join.
|
1413
1399
|
# [:source]
|
1414
1400
|
# Specifies the source association name used by #has_many <tt>:through</tt> queries.
|
1415
1401
|
# Only use it if the name cannot be inferred from the association.
|
@@ -1439,7 +1425,8 @@ module ActiveRecord
|
|
1439
1425
|
# Useful for defining methods on associations, especially when they should be shared between multiple
|
1440
1426
|
# association objects.
|
1441
1427
|
# [:strict_loading]
|
1442
|
-
#
|
1428
|
+
# When set to +true+, enforces strict loading every time the associated record is loaded through this
|
1429
|
+
# association.
|
1443
1430
|
# [:ensuring_owner_was]
|
1444
1431
|
# Specifies an instance method to be called on the owner. The method must return true in order for the
|
1445
1432
|
# associated records to be deleted in a background job.
|
@@ -1453,6 +1440,7 @@ module ActiveRecord
|
|
1453
1440
|
# has_many :tags, as: :taggable
|
1454
1441
|
# has_many :reports, -> { readonly }
|
1455
1442
|
# has_many :subscribers, through: :subscriptions, source: :user
|
1443
|
+
# has_many :subscribers, through: :subscriptions, disable_joins: true
|
1456
1444
|
# has_many :comments, strict_loading: true
|
1457
1445
|
def has_many(name, scope = nil, **options, &extension)
|
1458
1446
|
reflection = Builder::HasMany.build(self, name, scope, options, &extension)
|
@@ -1558,8 +1546,21 @@ module ActiveRecord
|
|
1558
1546
|
# source reflection. You can only use a <tt>:through</tt> query through a #has_one
|
1559
1547
|
# or #belongs_to association on the join model.
|
1560
1548
|
#
|
1549
|
+
# If the association on the join model is a #belongs_to, the collection can be modified
|
1550
|
+
# and the records on the <tt>:through</tt> model will be automatically created and removed
|
1551
|
+
# as appropriate. Otherwise, the collection is read-only, so you should manipulate the
|
1552
|
+
# <tt>:through</tt> association directly.
|
1553
|
+
#
|
1561
1554
|
# If you are going to modify the association (rather than just read from it), then it is
|
1562
|
-
# a good idea to set the <tt>:inverse_of</tt> option
|
1555
|
+
# a good idea to set the <tt>:inverse_of</tt> option on the source association on the
|
1556
|
+
# join model. This allows associated records to be built which will automatically create
|
1557
|
+
# the appropriate join model records when they are saved. (See the 'Association Join Models'
|
1558
|
+
# section above.)
|
1559
|
+
# [:disable_joins]
|
1560
|
+
# Specifies whether joins should be skipped for an association. If set to true, two or more queries
|
1561
|
+
# will be generated. Note that in some cases, if order or limit is applied, it will be done in-memory
|
1562
|
+
# due to database limitations. This option is only applicable on `has_one :through` associations as
|
1563
|
+
# `has_one` alone does not perform a join.
|
1563
1564
|
# [:source]
|
1564
1565
|
# Specifies the source association name used by #has_one <tt>:through</tt> queries.
|
1565
1566
|
# Only use it if the name cannot be inferred from the association.
|
@@ -1601,6 +1602,7 @@ module ActiveRecord
|
|
1601
1602
|
# has_one :attachment, as: :attachable
|
1602
1603
|
# has_one :boss, -> { readonly }
|
1603
1604
|
# has_one :club, through: :membership
|
1605
|
+
# has_one :club, through: :membership, disable_joins: true
|
1604
1606
|
# has_one :primary_address, -> { where(primary: true) }, through: :addressables, source: :addressable
|
1605
1607
|
# has_one :credit_card, required: true
|
1606
1608
|
# has_one :credit_card, strict_loading: true
|
@@ -1637,6 +1639,10 @@ module ActiveRecord
|
|
1637
1639
|
# if the record is invalid.
|
1638
1640
|
# [reload_association]
|
1639
1641
|
# Returns the associated object, forcing a database read.
|
1642
|
+
# [association_changed?]
|
1643
|
+
# Returns true if a new associate object has been assigned and the next save will update the foreign key.
|
1644
|
+
# [association_previously_changed?]
|
1645
|
+
# Returns true if the previous save updated the association to reference a new associate object.
|
1640
1646
|
#
|
1641
1647
|
# === Example
|
1642
1648
|
#
|
@@ -1647,6 +1653,8 @@ module ActiveRecord
|
|
1647
1653
|
# * <tt>Post#create_author</tt> (similar to <tt>post.author = Author.new; post.author.save; post.author</tt>)
|
1648
1654
|
# * <tt>Post#create_author!</tt> (similar to <tt>post.author = Author.new; post.author.save!; post.author</tt>)
|
1649
1655
|
# * <tt>Post#reload_author</tt>
|
1656
|
+
# * <tt>Post#author_changed?</tt>
|
1657
|
+
# * <tt>Post#author_previously_changed?</tt>
|
1650
1658
|
# The declaration can also include an +options+ hash to specialize the behavior of the association.
|
1651
1659
|
#
|
1652
1660
|
# === Scopes
|
@@ -1780,7 +1788,7 @@ module ActiveRecord
|
|
1780
1788
|
# The join table should not have a primary key or a model associated with it. You must manually generate the
|
1781
1789
|
# join table with a migration such as this:
|
1782
1790
|
#
|
1783
|
-
# class CreateDevelopersProjectsJoinTable < ActiveRecord::Migration[
|
1791
|
+
# class CreateDevelopersProjectsJoinTable < ActiveRecord::Migration[7.0]
|
1784
1792
|
# def change
|
1785
1793
|
# create_join_table :developers, :projects
|
1786
1794
|
# end
|
@@ -0,0 +1,60 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ActiveRecord
|
4
|
+
class AsynchronousQueriesTracker # :nodoc:
|
5
|
+
module NullSession # :nodoc:
|
6
|
+
class << self
|
7
|
+
def active?
|
8
|
+
true
|
9
|
+
end
|
10
|
+
|
11
|
+
def finalize
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
class Session # :nodoc:
|
17
|
+
def initialize
|
18
|
+
@active = true
|
19
|
+
end
|
20
|
+
|
21
|
+
def active?
|
22
|
+
@active
|
23
|
+
end
|
24
|
+
|
25
|
+
def finalize
|
26
|
+
@active = false
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
class << self
|
31
|
+
def install_executor_hooks(executor = ActiveSupport::Executor)
|
32
|
+
executor.register_hook(self)
|
33
|
+
end
|
34
|
+
|
35
|
+
def run
|
36
|
+
ActiveRecord::Base.asynchronous_queries_tracker.start_session
|
37
|
+
end
|
38
|
+
|
39
|
+
def complete(asynchronous_queries_tracker)
|
40
|
+
asynchronous_queries_tracker.finalize_session
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
attr_reader :current_session
|
45
|
+
|
46
|
+
def initialize
|
47
|
+
@current_session = NullSession
|
48
|
+
end
|
49
|
+
|
50
|
+
def start_session
|
51
|
+
@current_session = Session.new
|
52
|
+
self
|
53
|
+
end
|
54
|
+
|
55
|
+
def finalize_session
|
56
|
+
@current_session.finalize
|
57
|
+
@current_session = NullSession
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
@@ -46,7 +46,7 @@ module ActiveRecord
|
|
46
46
|
def execute_callstack_for_multiparameter_attributes(callstack)
|
47
47
|
errors = []
|
48
48
|
callstack.each do |name, values_with_empty_parameters|
|
49
|
-
if values_with_empty_parameters.each_value.all?(
|
49
|
+
if values_with_empty_parameters.each_value.all?(NilClass)
|
50
50
|
values = nil
|
51
51
|
else
|
52
52
|
values = values_with_empty_parameters
|
@@ -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,32 @@ 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
|
+
if partial_inserts?
|
233
|
+
changed_attribute_names_to_save
|
234
|
+
else
|
235
|
+
attribute_names.reject do |attr_name|
|
236
|
+
if column_for_attribute(attr_name).default_function
|
237
|
+
!attribute_changed?(attr_name)
|
238
|
+
end
|
239
|
+
end
|
240
|
+
end
|
208
241
|
end
|
209
242
|
end
|
210
243
|
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
|
|