activerecord 6.0.1 → 6.1.0
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 +843 -626
- data/MIT-LICENSE +1 -1
- data/README.rdoc +3 -3
- data/lib/active_record/aggregations.rb +1 -2
- data/lib/active_record/association_relation.rb +18 -17
- data/lib/active_record/associations/alias_tracker.rb +19 -16
- data/lib/active_record/associations/association.rb +49 -37
- data/lib/active_record/associations/association_scope.rb +17 -15
- data/lib/active_record/associations/belongs_to_association.rb +15 -5
- data/lib/active_record/associations/belongs_to_polymorphic_association.rb +1 -1
- data/lib/active_record/associations/builder/association.rb +9 -3
- data/lib/active_record/associations/builder/belongs_to.rb +10 -7
- data/lib/active_record/associations/builder/collection_association.rb +5 -4
- data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +0 -3
- data/lib/active_record/associations/builder/has_many.rb +6 -2
- data/lib/active_record/associations/builder/has_one.rb +11 -14
- data/lib/active_record/associations/builder/singular_association.rb +1 -1
- data/lib/active_record/associations/collection_association.rb +25 -8
- data/lib/active_record/associations/collection_proxy.rb +14 -7
- data/lib/active_record/associations/foreign_association.rb +13 -0
- data/lib/active_record/associations/has_many_association.rb +24 -3
- data/lib/active_record/associations/has_many_through_association.rb +10 -4
- data/lib/active_record/associations/has_one_association.rb +15 -1
- data/lib/active_record/associations/join_dependency/join_association.rb +36 -14
- data/lib/active_record/associations/join_dependency/join_part.rb +3 -3
- data/lib/active_record/associations/join_dependency.rb +73 -42
- data/lib/active_record/associations/preloader/association.rb +51 -25
- data/lib/active_record/associations/preloader/through_association.rb +2 -2
- data/lib/active_record/associations/preloader.rb +12 -7
- data/lib/active_record/associations/singular_association.rb +1 -1
- data/lib/active_record/associations/through_association.rb +1 -1
- data/lib/active_record/associations.rb +115 -12
- data/lib/active_record/attribute_assignment.rb +10 -9
- data/lib/active_record/attribute_methods/before_type_cast.rb +13 -10
- data/lib/active_record/attribute_methods/dirty.rb +3 -13
- data/lib/active_record/attribute_methods/primary_key.rb +6 -4
- data/lib/active_record/attribute_methods/query.rb +3 -6
- data/lib/active_record/attribute_methods/read.rb +8 -12
- data/lib/active_record/attribute_methods/serialization.rb +11 -6
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +12 -15
- data/lib/active_record/attribute_methods/write.rb +12 -21
- data/lib/active_record/attribute_methods.rb +64 -54
- data/lib/active_record/attributes.rb +32 -8
- data/lib/active_record/autosave_association.rb +56 -41
- data/lib/active_record/base.rb +2 -14
- data/lib/active_record/callbacks.rb +153 -24
- data/lib/active_record/coders/yaml_column.rb +1 -2
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +190 -136
- data/lib/active_record/connection_adapters/abstract/database_limits.rb +2 -44
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +82 -37
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +2 -8
- data/lib/active_record/connection_adapters/abstract/quoting.rb +34 -34
- data/lib/active_record/connection_adapters/abstract/savepoints.rb +3 -3
- data/lib/active_record/connection_adapters/abstract/schema_creation.rb +152 -116
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +137 -52
- data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +3 -3
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +263 -107
- data/lib/active_record/connection_adapters/abstract/transaction.rb +82 -35
- data/lib/active_record/connection_adapters/abstract_adapter.rb +60 -73
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +136 -111
- data/lib/active_record/connection_adapters/column.rb +15 -1
- data/lib/active_record/connection_adapters/deduplicable.rb +29 -0
- data/lib/active_record/connection_adapters/legacy_pool_manager.rb +31 -0
- data/lib/active_record/connection_adapters/mysql/column.rb +1 -1
- data/lib/active_record/connection_adapters/mysql/database_statements.rb +28 -36
- data/lib/active_record/connection_adapters/mysql/explain_pretty_printer.rb +1 -2
- data/lib/active_record/connection_adapters/mysql/quoting.rb +1 -1
- data/lib/active_record/connection_adapters/mysql/schema_creation.rb +32 -7
- data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +8 -0
- data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +1 -1
- data/lib/active_record/connection_adapters/mysql/schema_statements.rb +17 -13
- data/lib/active_record/connection_adapters/mysql/type_metadata.rb +10 -1
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +31 -13
- data/lib/active_record/connection_adapters/pool_config.rb +63 -0
- data/lib/active_record/connection_adapters/pool_manager.rb +43 -0
- data/lib/active_record/connection_adapters/postgresql/column.rb +24 -1
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +19 -56
- data/lib/active_record/connection_adapters/postgresql/oid/array.rb +0 -1
- data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +3 -5
- data/lib/active_record/connection_adapters/postgresql/oid/date.rb +2 -2
- data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +10 -2
- data/lib/active_record/connection_adapters/postgresql/oid/enum.rb +0 -1
- data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +0 -1
- data/lib/active_record/connection_adapters/postgresql/oid/interval.rb +49 -0
- data/lib/active_record/connection_adapters/postgresql/oid/legacy_point.rb +2 -3
- data/lib/active_record/connection_adapters/postgresql/oid/macaddr.rb +25 -0
- data/lib/active_record/connection_adapters/postgresql/oid/oid.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/oid/point.rb +2 -3
- data/lib/active_record/connection_adapters/postgresql/oid/range.rb +24 -6
- data/lib/active_record/connection_adapters/postgresql/oid/specialized_string.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +11 -2
- data/lib/active_record/connection_adapters/postgresql/oid.rb +2 -0
- data/lib/active_record/connection_adapters/postgresql/quoting.rb +4 -4
- data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +2 -2
- data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +7 -3
- data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +0 -1
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +72 -54
- data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +8 -0
- data/lib/active_record/connection_adapters/postgresql/utils.rb +0 -1
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +77 -57
- data/lib/active_record/connection_adapters/schema_cache.rb +98 -15
- data/lib/active_record/connection_adapters/sql_type_metadata.rb +10 -0
- data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +36 -12
- data/lib/active_record/connection_adapters/sqlite3/quoting.rb +1 -2
- data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +5 -1
- data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +38 -5
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +57 -57
- data/lib/active_record/connection_adapters/statement_pool.rb +0 -1
- data/lib/active_record/connection_adapters.rb +50 -0
- data/lib/active_record/connection_handling.rb +210 -87
- data/lib/active_record/core.rb +229 -65
- data/lib/active_record/counter_cache.rb +4 -1
- data/lib/active_record/database_configurations/connection_url_resolver.rb +98 -0
- data/lib/active_record/database_configurations/database_config.rb +52 -9
- data/lib/active_record/database_configurations/hash_config.rb +54 -8
- data/lib/active_record/database_configurations/url_config.rb +15 -41
- data/lib/active_record/database_configurations.rb +124 -85
- data/lib/active_record/delegated_type.rb +209 -0
- data/lib/active_record/destroy_association_async_job.rb +36 -0
- data/lib/active_record/dynamic_matchers.rb +2 -3
- data/lib/active_record/enum.rb +40 -16
- data/lib/active_record/errors.rb +47 -12
- data/lib/active_record/explain.rb +9 -5
- data/lib/active_record/explain_subscriber.rb +1 -1
- data/lib/active_record/fixture_set/file.rb +10 -17
- data/lib/active_record/fixture_set/model_metadata.rb +1 -2
- data/lib/active_record/fixture_set/render_context.rb +1 -1
- data/lib/active_record/fixture_set/table_row.rb +2 -3
- data/lib/active_record/fixture_set/table_rows.rb +0 -1
- data/lib/active_record/fixtures.rb +54 -11
- data/lib/active_record/gem_version.rb +2 -2
- data/lib/active_record/inheritance.rb +40 -21
- data/lib/active_record/insert_all.rb +38 -9
- data/lib/active_record/integration.rb +3 -5
- data/lib/active_record/internal_metadata.rb +16 -7
- data/lib/active_record/legacy_yaml_adapter.rb +7 -3
- data/lib/active_record/locking/optimistic.rb +22 -17
- data/lib/active_record/locking/pessimistic.rb +6 -2
- data/lib/active_record/log_subscriber.rb +27 -9
- data/lib/active_record/middleware/database_selector/resolver/session.rb +3 -0
- data/lib/active_record/middleware/database_selector/resolver.rb +6 -2
- data/lib/active_record/middleware/database_selector.rb +4 -2
- data/lib/active_record/migration/command_recorder.rb +53 -45
- data/lib/active_record/migration/compatibility.rb +70 -20
- data/lib/active_record/migration/join_table.rb +0 -1
- data/lib/active_record/migration.rb +114 -84
- data/lib/active_record/model_schema.rb +117 -15
- data/lib/active_record/nested_attributes.rb +2 -5
- data/lib/active_record/no_touching.rb +1 -1
- data/lib/active_record/null_relation.rb +0 -1
- data/lib/active_record/persistence.rb +50 -46
- data/lib/active_record/query_cache.rb +15 -5
- data/lib/active_record/querying.rb +12 -7
- data/lib/active_record/railtie.rb +65 -45
- data/lib/active_record/railties/databases.rake +267 -93
- data/lib/active_record/readonly_attributes.rb +4 -0
- data/lib/active_record/reflection.rb +77 -63
- data/lib/active_record/relation/batches/batch_enumerator.rb +25 -9
- data/lib/active_record/relation/batches.rb +38 -32
- data/lib/active_record/relation/calculations.rb +102 -45
- data/lib/active_record/relation/delegation.rb +9 -7
- data/lib/active_record/relation/finder_methods.rb +45 -16
- data/lib/active_record/relation/from_clause.rb +5 -1
- data/lib/active_record/relation/merger.rb +27 -26
- data/lib/active_record/relation/predicate_builder/array_handler.rb +8 -9
- data/lib/active_record/relation/predicate_builder/association_query_value.rb +4 -5
- data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +3 -3
- data/lib/active_record/relation/predicate_builder/relation_handler.rb +1 -1
- data/lib/active_record/relation/predicate_builder.rb +55 -35
- data/lib/active_record/relation/query_methods.rb +335 -187
- data/lib/active_record/relation/record_fetch_warning.rb +3 -3
- data/lib/active_record/relation/spawn_methods.rb +8 -8
- data/lib/active_record/relation/where_clause.rb +104 -58
- data/lib/active_record/relation.rb +108 -68
- data/lib/active_record/result.rb +41 -34
- data/lib/active_record/runtime_registry.rb +2 -2
- data/lib/active_record/sanitization.rb +6 -17
- data/lib/active_record/schema_dumper.rb +34 -4
- data/lib/active_record/schema_migration.rb +2 -8
- data/lib/active_record/scoping/default.rb +0 -1
- data/lib/active_record/scoping/named.rb +7 -18
- data/lib/active_record/scoping.rb +0 -1
- data/lib/active_record/secure_token.rb +16 -8
- data/lib/active_record/serialization.rb +5 -3
- data/lib/active_record/signed_id.rb +116 -0
- data/lib/active_record/statement_cache.rb +20 -4
- data/lib/active_record/store.rb +3 -3
- data/lib/active_record/suppressor.rb +2 -2
- data/lib/active_record/table_metadata.rb +39 -36
- data/lib/active_record/tasks/database_tasks.rb +139 -113
- data/lib/active_record/tasks/mysql_database_tasks.rb +34 -36
- data/lib/active_record/tasks/postgresql_database_tasks.rb +24 -27
- data/lib/active_record/tasks/sqlite_database_tasks.rb +13 -10
- data/lib/active_record/test_databases.rb +5 -4
- data/lib/active_record/test_fixtures.rb +38 -16
- data/lib/active_record/timestamp.rb +4 -7
- data/lib/active_record/touch_later.rb +20 -21
- data/lib/active_record/transactions.rb +21 -70
- data/lib/active_record/type/adapter_specific_registry.rb +2 -5
- data/lib/active_record/type/hash_lookup_type_map.rb +0 -1
- data/lib/active_record/type/serialized.rb +6 -3
- data/lib/active_record/type/time.rb +10 -0
- data/lib/active_record/type/type_map.rb +0 -1
- data/lib/active_record/type/unsigned_integer.rb +0 -1
- data/lib/active_record/type.rb +8 -2
- data/lib/active_record/type_caster/connection.rb +0 -1
- data/lib/active_record/type_caster/map.rb +8 -5
- data/lib/active_record/validations/associated.rb +1 -2
- data/lib/active_record/validations/numericality.rb +35 -0
- data/lib/active_record/validations/uniqueness.rb +24 -4
- data/lib/active_record/validations.rb +3 -3
- data/lib/active_record.rb +7 -13
- data/lib/arel/attributes/attribute.rb +4 -0
- data/lib/arel/collectors/bind.rb +5 -0
- data/lib/arel/collectors/composite.rb +8 -0
- data/lib/arel/collectors/sql_string.rb +7 -0
- data/lib/arel/collectors/substitute_binds.rb +7 -0
- data/lib/arel/nodes/binary.rb +82 -8
- data/lib/arel/nodes/bind_param.rb +8 -0
- data/lib/arel/nodes/casted.rb +21 -9
- data/lib/arel/nodes/equality.rb +6 -9
- data/lib/arel/nodes/grouping.rb +3 -0
- data/lib/arel/nodes/homogeneous_in.rb +72 -0
- data/lib/arel/nodes/in.rb +8 -1
- data/lib/arel/nodes/infix_operation.rb +13 -1
- data/lib/arel/nodes/join_source.rb +1 -1
- data/lib/arel/nodes/node.rb +7 -6
- data/lib/arel/nodes/ordering.rb +27 -0
- data/lib/arel/nodes/sql_literal.rb +3 -0
- data/lib/arel/nodes/table_alias.rb +7 -3
- data/lib/arel/nodes/unary.rb +0 -1
- data/lib/arel/nodes.rb +3 -1
- data/lib/arel/predications.rb +17 -24
- data/lib/arel/select_manager.rb +1 -2
- data/lib/arel/table.rb +13 -5
- data/lib/arel/visitors/dot.rb +14 -3
- data/lib/arel/visitors/mysql.rb +11 -1
- data/lib/arel/visitors/postgresql.rb +15 -5
- data/lib/arel/visitors/sqlite.rb +0 -1
- data/lib/arel/visitors/to_sql.rb +89 -79
- data/lib/arel/visitors/visitor.rb +0 -1
- data/lib/arel/visitors.rb +0 -7
- data/lib/arel.rb +5 -9
- data/lib/rails/generators/active_record/application_record/application_record_generator.rb +0 -1
- data/lib/rails/generators/active_record/migration/migration_generator.rb +1 -0
- data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb.tt +2 -0
- data/lib/rails/generators/active_record/migration/templates/migration.rb.tt +4 -4
- data/lib/rails/generators/active_record/migration.rb +6 -2
- data/lib/rails/generators/active_record/model/model_generator.rb +38 -2
- data/lib/rails/generators/active_record/model/templates/abstract_base_class.rb.tt +7 -0
- metadata +26 -26
- data/lib/active_record/attribute_decorators.rb +0 -90
- data/lib/active_record/connection_adapters/connection_specification.rb +0 -297
- data/lib/active_record/connection_adapters/determine_if_preparable_visitor.rb +0 -29
- data/lib/active_record/define_callbacks.rb +0 -22
- data/lib/active_record/railties/collection_cache_association_loading.rb +0 -34
- data/lib/active_record/relation/predicate_builder/base_handler.rb +0 -18
- data/lib/active_record/relation/where_clause_factory.rb +0 -33
- data/lib/arel/attributes.rb +0 -22
- data/lib/arel/visitors/depth_first.rb +0 -204
- data/lib/arel/visitors/ibm_db.rb +0 -34
- data/lib/arel/visitors/informix.rb +0 -62
- data/lib/arel/visitors/mssql.rb +0 -157
- data/lib/arel/visitors/oracle.rb +0 -159
- data/lib/arel/visitors/oracle12.rb +0 -66
- data/lib/arel/visitors/where_sql.rb +0 -23
@@ -4,46 +4,62 @@ module ActiveRecord
|
|
4
4
|
module Associations
|
5
5
|
class Preloader
|
6
6
|
class Association #:nodoc:
|
7
|
-
def initialize(klass, owners, reflection, preload_scope)
|
7
|
+
def initialize(klass, owners, reflection, preload_scope, associate_by_default = true)
|
8
8
|
@klass = klass
|
9
|
-
@owners = owners
|
9
|
+
@owners = owners.uniq(&:__id__)
|
10
10
|
@reflection = reflection
|
11
11
|
@preload_scope = preload_scope
|
12
|
+
@associate = associate_by_default || !preload_scope || preload_scope.empty_scope?
|
12
13
|
@model = owners.first && owners.first.class
|
13
14
|
end
|
14
15
|
|
15
16
|
def run
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
# the association can not be marked as loaded
|
23
|
-
# Loading into a Hash instead
|
24
|
-
records_by_owner
|
25
|
-
end
|
17
|
+
records = records_by_owner
|
18
|
+
|
19
|
+
owners.each do |owner|
|
20
|
+
associate_records_to_owner(owner, records[owner] || [])
|
21
|
+
end if @associate
|
22
|
+
|
26
23
|
self
|
27
24
|
end
|
28
25
|
|
29
26
|
def records_by_owner
|
30
|
-
|
31
|
-
|
32
|
-
@records_by_owner
|
33
|
-
owners_by_key[convert_key(record[association_key_name])].each do |owner|
|
34
|
-
(result[owner] ||= []) << record
|
35
|
-
end
|
36
|
-
end
|
27
|
+
load_records unless defined?(@records_by_owner)
|
28
|
+
|
29
|
+
@records_by_owner
|
37
30
|
end
|
38
31
|
|
39
32
|
def preloaded_records
|
40
|
-
|
41
|
-
|
33
|
+
load_records unless defined?(@preloaded_records)
|
34
|
+
|
35
|
+
@preloaded_records
|
42
36
|
end
|
43
37
|
|
44
38
|
private
|
45
39
|
attr_reader :owners, :reflection, :preload_scope, :model, :klass
|
46
40
|
|
41
|
+
def load_records
|
42
|
+
# owners can be duplicated when a relation has a collection association join
|
43
|
+
# #compare_by_identity makes such owners different hash keys
|
44
|
+
@records_by_owner = {}.compare_by_identity
|
45
|
+
raw_records = owner_keys.empty? ? [] : records_for(owner_keys)
|
46
|
+
|
47
|
+
@preloaded_records = raw_records.select do |record|
|
48
|
+
assignments = false
|
49
|
+
|
50
|
+
owners_by_key[convert_key(record[association_key_name])].each do |owner|
|
51
|
+
entries = (@records_by_owner[owner] ||= [])
|
52
|
+
|
53
|
+
if reflection.collection? || entries.empty?
|
54
|
+
entries << record
|
55
|
+
assignments = true
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
assignments
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
47
63
|
# The name of the key on the associated records
|
48
64
|
def association_key_name
|
49
65
|
reflection.join_primary_key(klass)
|
@@ -113,7 +129,9 @@ module ActiveRecord
|
|
113
129
|
end
|
114
130
|
|
115
131
|
def reflection_scope
|
116
|
-
@reflection_scope ||=
|
132
|
+
@reflection_scope ||= begin
|
133
|
+
reflection.join_scopes(klass.arel_table, klass.predicate_builder, klass).inject(&:merge!) || klass.unscoped
|
134
|
+
end
|
117
135
|
end
|
118
136
|
|
119
137
|
def build_scope
|
@@ -123,9 +141,17 @@ module ActiveRecord
|
|
123
141
|
scope.where!(reflection.type => model.polymorphic_name)
|
124
142
|
end
|
125
143
|
|
126
|
-
scope.merge!(reflection_scope)
|
127
|
-
|
128
|
-
|
144
|
+
scope.merge!(reflection_scope) unless reflection_scope.empty_scope?
|
145
|
+
|
146
|
+
if preload_scope && !preload_scope.empty_scope?
|
147
|
+
scope.merge!(preload_scope)
|
148
|
+
end
|
149
|
+
|
150
|
+
if preload_scope && preload_scope.strict_loading_value
|
151
|
+
scope.strict_loading
|
152
|
+
else
|
153
|
+
scope
|
154
|
+
end
|
129
155
|
end
|
130
156
|
end
|
131
157
|
end
|
@@ -4,7 +4,7 @@ module ActiveRecord
|
|
4
4
|
module Associations
|
5
5
|
class Preloader
|
6
6
|
class ThroughAssociation < Association # :nodoc:
|
7
|
-
PRELOADER = ActiveRecord::Associations::Preloader.new
|
7
|
+
PRELOADER = ActiveRecord::Associations::Preloader.new(associate_by_default: false)
|
8
8
|
|
9
9
|
def initialize(*)
|
10
10
|
super
|
@@ -90,7 +90,7 @@ module ActiveRecord
|
|
90
90
|
end
|
91
91
|
|
92
92
|
if values[:references] && !values[:references].empty?
|
93
|
-
scope.
|
93
|
+
scope.references_values |= values[:references]
|
94
94
|
else
|
95
95
|
scope.references!(source_reflection.table_name)
|
96
96
|
end
|
@@ -1,5 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require "active_support/core_ext/enumerable"
|
4
|
+
|
3
5
|
module ActiveRecord
|
4
6
|
module Associations
|
5
7
|
# Implements the details of eager loading of Active Record associations.
|
@@ -58,7 +60,7 @@ module ActiveRecord
|
|
58
60
|
# == Parameters
|
59
61
|
# +records+ is an array of ActiveRecord::Base. This array needs not be flat,
|
60
62
|
# i.e. +records+ itself may also contain arrays of records. In any case,
|
61
|
-
# +preload_associations+ will preload
|
63
|
+
# +preload_associations+ will preload all associations records by
|
62
64
|
# flattening +records+.
|
63
65
|
#
|
64
66
|
# +associations+ specifies one or more associations that you want to
|
@@ -94,8 +96,11 @@ module ActiveRecord
|
|
94
96
|
end
|
95
97
|
end
|
96
98
|
|
97
|
-
|
99
|
+
def initialize(associate_by_default: true)
|
100
|
+
@associate_by_default = associate_by_default
|
101
|
+
end
|
98
102
|
|
103
|
+
private
|
99
104
|
# Loads all the given data into +records+ for the +association+.
|
100
105
|
def preloaders_on(association, records, scope, polymorphic_parent = false)
|
101
106
|
case association
|
@@ -143,7 +148,7 @@ module ActiveRecord
|
|
143
148
|
|
144
149
|
def preloaders_for_reflection(reflection, records, scope)
|
145
150
|
records.group_by { |record| record.association(reflection.name).klass }.map do |rhs_klass, rs|
|
146
|
-
preloader_for(reflection, rs).new(rhs_klass, rs, reflection, scope).run
|
151
|
+
preloader_for(reflection, rs).new(rhs_klass, rs, reflection, scope, @associate_by_default).run
|
147
152
|
end
|
148
153
|
end
|
149
154
|
|
@@ -158,7 +163,7 @@ module ActiveRecord
|
|
158
163
|
end
|
159
164
|
|
160
165
|
class AlreadyLoaded # :nodoc:
|
161
|
-
def initialize(klass, owners, reflection, preload_scope)
|
166
|
+
def initialize(klass, owners, reflection, preload_scope, associate_by_default = true)
|
162
167
|
@owners = owners
|
163
168
|
@reflection = reflection
|
164
169
|
end
|
@@ -172,8 +177,8 @@ module ActiveRecord
|
|
172
177
|
end
|
173
178
|
|
174
179
|
def records_by_owner
|
175
|
-
@records_by_owner ||= owners.
|
176
|
-
|
180
|
+
@records_by_owner ||= owners.index_with do |owner|
|
181
|
+
Array(owner.association(reflection.name).target)
|
177
182
|
end
|
178
183
|
end
|
179
184
|
|
@@ -185,7 +190,7 @@ module ActiveRecord
|
|
185
190
|
# and attach it to a relation. The class returned implements a `run` method
|
186
191
|
# that accepts a preloader.
|
187
192
|
def preloader_for(reflection, owners)
|
188
|
-
if owners.
|
193
|
+
if owners.all? { |o| o.association(reflection.name).loaded? }
|
189
194
|
return AlreadyLoaded
|
190
195
|
end
|
191
196
|
reflection.check_preloadable!
|
@@ -32,7 +32,7 @@ module ActiveRecord
|
|
32
32
|
reflection.chain.drop(1).each do |reflection|
|
33
33
|
relation = reflection.klass.scope_for_association
|
34
34
|
scope.merge!(
|
35
|
-
relation.except(:select, :create_with, :includes, :preload, :joins, :
|
35
|
+
relation.except(:select, :create_with, :includes, :preload, :eager_load, :joins, :left_outer_joins)
|
36
36
|
)
|
37
37
|
end
|
38
38
|
scope
|
@@ -2,38 +2,116 @@
|
|
2
2
|
|
3
3
|
require "active_support/core_ext/enumerable"
|
4
4
|
require "active_support/core_ext/string/conversions"
|
5
|
-
require "active_support/core_ext/module/remove_method"
|
6
|
-
require "active_record/errors"
|
7
5
|
|
8
6
|
module ActiveRecord
|
9
7
|
class AssociationNotFoundError < ConfigurationError #:nodoc:
|
8
|
+
attr_reader :record, :association_name
|
10
9
|
def initialize(record = nil, association_name = nil)
|
10
|
+
@record = record
|
11
|
+
@association_name = association_name
|
11
12
|
if record && association_name
|
12
13
|
super("Association named '#{association_name}' was not found on #{record.class.name}; perhaps you misspelled it?")
|
13
14
|
else
|
14
15
|
super("Association was not found.")
|
15
16
|
end
|
16
17
|
end
|
18
|
+
|
19
|
+
class Correction
|
20
|
+
def initialize(error)
|
21
|
+
@error = error
|
22
|
+
end
|
23
|
+
|
24
|
+
def corrections
|
25
|
+
if @error.association_name
|
26
|
+
maybe_these = @error.record.class.reflections.keys
|
27
|
+
|
28
|
+
maybe_these.sort_by { |n|
|
29
|
+
DidYouMean::Jaro.distance(@error.association_name.to_s, n)
|
30
|
+
}.reverse.first(4)
|
31
|
+
else
|
32
|
+
[]
|
33
|
+
end
|
34
|
+
end
|
35
|
+
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
|
17
41
|
end
|
18
42
|
|
19
43
|
class InverseOfAssociationNotFoundError < ActiveRecordError #:nodoc:
|
44
|
+
attr_reader :reflection, :associated_class
|
20
45
|
def initialize(reflection = nil, associated_class = nil)
|
21
46
|
if reflection
|
47
|
+
@reflection = reflection
|
48
|
+
@associated_class = associated_class.nil? ? reflection.klass : associated_class
|
22
49
|
super("Could not find the inverse association for #{reflection.name} (#{reflection.options[:inverse_of].inspect} in #{associated_class.nil? ? reflection.class_name : associated_class.name})")
|
23
50
|
else
|
24
51
|
super("Could not find the inverse association.")
|
25
52
|
end
|
26
53
|
end
|
54
|
+
|
55
|
+
class Correction
|
56
|
+
def initialize(error)
|
57
|
+
@error = error
|
58
|
+
end
|
59
|
+
|
60
|
+
def corrections
|
61
|
+
if @error.reflection && @error.associated_class
|
62
|
+
maybe_these = @error.associated_class.reflections.keys
|
63
|
+
|
64
|
+
maybe_these.sort_by { |n|
|
65
|
+
DidYouMean::Jaro.distance(@error.reflection.options[:inverse_of].to_s, n)
|
66
|
+
}.reverse.first(4)
|
67
|
+
else
|
68
|
+
[]
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
# We may not have DYM, and DYM might not let us register error handlers
|
74
|
+
if defined?(DidYouMean) && DidYouMean.respond_to?(:correct_error)
|
75
|
+
DidYouMean.correct_error(self, Correction)
|
76
|
+
end
|
27
77
|
end
|
28
78
|
|
29
79
|
class HasManyThroughAssociationNotFoundError < ActiveRecordError #:nodoc:
|
30
|
-
|
31
|
-
|
32
|
-
|
80
|
+
attr_reader :owner_class, :reflection
|
81
|
+
|
82
|
+
def initialize(owner_class = nil, reflection = nil)
|
83
|
+
if owner_class && reflection
|
84
|
+
@owner_class = owner_class
|
85
|
+
@reflection = reflection
|
86
|
+
super("Could not find the association #{reflection.options[:through].inspect} in model #{owner_class.name}")
|
33
87
|
else
|
34
88
|
super("Could not find the association.")
|
35
89
|
end
|
36
90
|
end
|
91
|
+
|
92
|
+
class Correction
|
93
|
+
def initialize(error)
|
94
|
+
@error = error
|
95
|
+
end
|
96
|
+
|
97
|
+
def corrections
|
98
|
+
if @error.reflection && @error.owner_class
|
99
|
+
maybe_these = @error.owner_class.reflections.keys
|
100
|
+
maybe_these -= [@error.reflection.name.to_s] # remove failing reflection
|
101
|
+
|
102
|
+
maybe_these.sort_by { |n|
|
103
|
+
DidYouMean::Jaro.distance(@error.reflection.options[:through].to_s, n)
|
104
|
+
}.reverse.first(4)
|
105
|
+
else
|
106
|
+
[]
|
107
|
+
end
|
108
|
+
end
|
109
|
+
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
|
37
115
|
end
|
38
116
|
|
39
117
|
class HasManyThroughAssociationPolymorphicSourceError < ActiveRecordError #:nodoc:
|
@@ -702,9 +780,8 @@ module ActiveRecord
|
|
702
780
|
# inverse detection only works on #has_many, #has_one, and
|
703
781
|
# #belongs_to associations.
|
704
782
|
#
|
705
|
-
#
|
706
|
-
#
|
707
|
-
# constant, or a custom scope, will also prevent the association's inverse
|
783
|
+
# <tt>:foreign_key</tt> and <tt>:through</tt> options on the associations,
|
784
|
+
# or a custom scope, will also prevent the association's inverse
|
708
785
|
# from being found automatically.
|
709
786
|
#
|
710
787
|
# The automatic guessing of the inverse association uses a heuristic based
|
@@ -1292,7 +1369,9 @@ module ActiveRecord
|
|
1292
1369
|
# similar callbacks may affect the <tt>:dependent</tt> behavior, and the
|
1293
1370
|
# <tt>:dependent</tt> behavior may affect other callbacks.
|
1294
1371
|
#
|
1372
|
+
# * <tt>nil</tt> do nothing (default).
|
1295
1373
|
# * <tt>:destroy</tt> causes all the associated objects to also be destroyed.
|
1374
|
+
# * <tt>:destroy_async</tt> destroys all the associated objects in a background job.
|
1296
1375
|
# * <tt>:delete_all</tt> causes all the associated objects to be deleted directly from the database (so callbacks will not be executed).
|
1297
1376
|
# * <tt>:nullify</tt> causes the foreign keys to be set to +NULL+. Polymorphic type will also be nullified
|
1298
1377
|
# on polymorphic associations. Callbacks are not executed.
|
@@ -1357,6 +1436,11 @@ module ActiveRecord
|
|
1357
1436
|
# Specifies a module or array of modules that will be extended into the association object returned.
|
1358
1437
|
# Useful for defining methods on associations, especially when they should be shared between multiple
|
1359
1438
|
# association objects.
|
1439
|
+
# [:strict_loading]
|
1440
|
+
# Enforces strict loading every time the associated record is loaded through this association.
|
1441
|
+
# [:ensuring_owner_was]
|
1442
|
+
# Specifies an instance method to be called on the owner. The method must return true in order for the
|
1443
|
+
# associated records to be deleted in a background job.
|
1360
1444
|
#
|
1361
1445
|
# Option examples:
|
1362
1446
|
# has_many :comments, -> { order("posted_on") }
|
@@ -1367,6 +1451,7 @@ module ActiveRecord
|
|
1367
1451
|
# has_many :tags, as: :taggable
|
1368
1452
|
# has_many :reports, -> { readonly }
|
1369
1453
|
# has_many :subscribers, through: :subscriptions, source: :user
|
1454
|
+
# has_many :comments, strict_loading: true
|
1370
1455
|
def has_many(name, scope = nil, **options, &extension)
|
1371
1456
|
reflection = Builder::HasMany.build(self, name, scope, options, &extension)
|
1372
1457
|
Reflection.add_reflection self, name, reflection
|
@@ -1436,7 +1521,9 @@ module ActiveRecord
|
|
1436
1521
|
# Controls what happens to the associated object when
|
1437
1522
|
# its owner is destroyed:
|
1438
1523
|
#
|
1524
|
+
# * <tt>nil</tt> do nothing (default).
|
1439
1525
|
# * <tt>:destroy</tt> causes the associated object to also be destroyed
|
1526
|
+
# * <tt>:destroy_async</tt> causes all the associated object to be destroyed in a background job.
|
1440
1527
|
# * <tt>:delete</tt> causes the associated object to be deleted directly from the database (so callbacks will not execute)
|
1441
1528
|
# * <tt>:nullify</tt> causes the foreign key to be set to +NULL+. Polymorphic type column is also nullified
|
1442
1529
|
# on polymorphic associations. Callbacks are not executed.
|
@@ -1495,6 +1582,11 @@ module ActiveRecord
|
|
1495
1582
|
# When set to +true+, the association will also have its presence validated.
|
1496
1583
|
# This will validate the association itself, not the id. You can use
|
1497
1584
|
# +:inverse_of+ to avoid an extra query during validation.
|
1585
|
+
# [:strict_loading]
|
1586
|
+
# Enforces strict loading every time the associated record is loaded through this association.
|
1587
|
+
# [:ensuring_owner_was]
|
1588
|
+
# Specifies an instance method to be called on the owner. The method must return true in order for the
|
1589
|
+
# associated records to be deleted in a background job.
|
1498
1590
|
#
|
1499
1591
|
# Option examples:
|
1500
1592
|
# has_one :credit_card, dependent: :destroy # destroys the associated credit card
|
@@ -1507,6 +1599,7 @@ module ActiveRecord
|
|
1507
1599
|
# has_one :club, through: :membership
|
1508
1600
|
# has_one :primary_address, -> { where(primary: true) }, through: :addressables, source: :addressable
|
1509
1601
|
# has_one :credit_card, required: true
|
1602
|
+
# has_one :credit_card, strict_loading: true
|
1510
1603
|
def has_one(name, scope = nil, **options)
|
1511
1604
|
reflection = Builder::HasOne.build(self, name, scope, options)
|
1512
1605
|
Reflection.add_reflection self, name, reflection
|
@@ -1588,7 +1681,8 @@ module ActiveRecord
|
|
1588
1681
|
# By default this is +id+.
|
1589
1682
|
# [:dependent]
|
1590
1683
|
# If set to <tt>:destroy</tt>, the associated object is destroyed when this object is. If set to
|
1591
|
-
# <tt>:delete</tt>, the associated object is deleted *without* calling its destroy method.
|
1684
|
+
# <tt>:delete</tt>, the associated object is deleted *without* calling its destroy method. If set to
|
1685
|
+
# <tt>:destroy_async</tt>, the associated object is scheduled to be destroyed in a background job.
|
1592
1686
|
# This option should not be specified when #belongs_to is used in conjunction with
|
1593
1687
|
# a #has_many relationship on another class because of the potential to leave
|
1594
1688
|
# orphaned records behind.
|
@@ -1640,6 +1734,11 @@ module ActiveRecord
|
|
1640
1734
|
# [:default]
|
1641
1735
|
# Provide a callable (i.e. proc or lambda) to specify that the association should
|
1642
1736
|
# be initialized with a particular record before validation.
|
1737
|
+
# [:strict_loading]
|
1738
|
+
# Enforces strict loading every time the associated record is loaded through this association.
|
1739
|
+
# [:ensuring_owner_was]
|
1740
|
+
# Specifies an instance method to be called on the owner. The method must return true in order for the
|
1741
|
+
# associated records to be deleted in a background job.
|
1643
1742
|
#
|
1644
1743
|
# Option examples:
|
1645
1744
|
# belongs_to :firm, foreign_key: "client_of"
|
@@ -1654,6 +1753,7 @@ module ActiveRecord
|
|
1654
1753
|
# belongs_to :company, touch: :employees_last_updated_at
|
1655
1754
|
# belongs_to :user, optional: true
|
1656
1755
|
# belongs_to :account, default: -> { company.account }
|
1756
|
+
# belongs_to :account, strict_loading: true
|
1657
1757
|
def belongs_to(name, scope = nil, **options)
|
1658
1758
|
reflection = Builder::BelongsTo.build(self, name, scope, options)
|
1659
1759
|
Reflection.add_reflection self, name, reflection
|
@@ -1676,7 +1776,7 @@ module ActiveRecord
|
|
1676
1776
|
# The join table should not have a primary key or a model associated with it. You must manually generate the
|
1677
1777
|
# join table with a migration such as this:
|
1678
1778
|
#
|
1679
|
-
# class CreateDevelopersProjectsJoinTable < ActiveRecord::Migration[
|
1779
|
+
# class CreateDevelopersProjectsJoinTable < ActiveRecord::Migration[6.0]
|
1680
1780
|
# def change
|
1681
1781
|
# create_join_table :developers, :projects
|
1682
1782
|
# end
|
@@ -1816,6 +1916,8 @@ module ActiveRecord
|
|
1816
1916
|
#
|
1817
1917
|
# Note that NestedAttributes::ClassMethods#accepts_nested_attributes_for sets
|
1818
1918
|
# <tt>:autosave</tt> to <tt>true</tt>.
|
1919
|
+
# [:strict_loading]
|
1920
|
+
# Enforces strict loading every time an associated record is loaded through this association.
|
1819
1921
|
#
|
1820
1922
|
# Option examples:
|
1821
1923
|
# has_and_belongs_to_many :projects
|
@@ -1823,6 +1925,7 @@ module ActiveRecord
|
|
1823
1925
|
# has_and_belongs_to_many :nations, class_name: "Country"
|
1824
1926
|
# has_and_belongs_to_many :categories, join_table: "prods_cats"
|
1825
1927
|
# has_and_belongs_to_many :categories, -> { readonly }
|
1928
|
+
# has_and_belongs_to_many :categories, strict_loading: true
|
1826
1929
|
def has_and_belongs_to_many(name, scope = nil, **options, &extension)
|
1827
1930
|
habtm_reflection = ActiveRecord::Reflection::HasAndBelongsToManyReflection.new(name, scope, options, self)
|
1828
1931
|
|
@@ -1853,11 +1956,11 @@ module ActiveRecord
|
|
1853
1956
|
hm_options[:through] = middle_reflection.name
|
1854
1957
|
hm_options[:source] = join_model.right_reflection.name
|
1855
1958
|
|
1856
|
-
[:before_add, :after_add, :before_remove, :after_remove, :autosave, :validate, :join_table, :class_name, :extend].each do |k|
|
1959
|
+
[:before_add, :after_add, :before_remove, :after_remove, :autosave, :validate, :join_table, :class_name, :extend, :strict_loading].each do |k|
|
1857
1960
|
hm_options[k] = options[k] if options.key? k
|
1858
1961
|
end
|
1859
1962
|
|
1860
|
-
has_many name, scope, hm_options, &extension
|
1963
|
+
has_many name, scope, **hm_options, &extension
|
1861
1964
|
_reflections[name.to_s].parent_reflection = habtm_reflection
|
1862
1965
|
end
|
1863
1966
|
end
|
@@ -7,22 +7,23 @@ module ActiveRecord
|
|
7
7
|
include ActiveModel::AttributeAssignment
|
8
8
|
|
9
9
|
private
|
10
|
-
|
11
10
|
def _assign_attributes(attributes)
|
12
|
-
multi_parameter_attributes
|
13
|
-
nested_parameter_attributes = {}
|
11
|
+
multi_parameter_attributes = nested_parameter_attributes = nil
|
14
12
|
|
15
13
|
attributes.each do |k, v|
|
16
|
-
|
17
|
-
|
14
|
+
key = k.to_s
|
15
|
+
|
16
|
+
if key.include?("(")
|
17
|
+
(multi_parameter_attributes ||= {})[key] = v
|
18
18
|
elsif v.is_a?(Hash)
|
19
|
-
nested_parameter_attributes[
|
19
|
+
(nested_parameter_attributes ||= {})[key] = v
|
20
|
+
else
|
21
|
+
_assign_attribute(key, v)
|
20
22
|
end
|
21
23
|
end
|
22
|
-
super(attributes)
|
23
24
|
|
24
|
-
assign_nested_parameter_attributes(nested_parameter_attributes)
|
25
|
-
assign_multiparameter_attributes(multi_parameter_attributes)
|
25
|
+
assign_nested_parameter_attributes(nested_parameter_attributes) if nested_parameter_attributes
|
26
|
+
assign_multiparameter_attributes(multi_parameter_attributes) if multi_parameter_attributes
|
26
27
|
end
|
27
28
|
|
28
29
|
# Assign any deferred nested attributes after the base attributes have been set.
|
@@ -29,7 +29,7 @@ module ActiveRecord
|
|
29
29
|
extend ActiveSupport::Concern
|
30
30
|
|
31
31
|
included do
|
32
|
-
attribute_method_suffix "_before_type_cast"
|
32
|
+
attribute_method_suffix "_before_type_cast", "_for_database"
|
33
33
|
attribute_method_suffix "_came_from_user?"
|
34
34
|
end
|
35
35
|
|
@@ -46,8 +46,10 @@ module ActiveRecord
|
|
46
46
|
# task.read_attribute_before_type_cast('completed_on') # => "2012-10-21"
|
47
47
|
# task.read_attribute_before_type_cast(:completed_on) # => "2012-10-21"
|
48
48
|
def read_attribute_before_type_cast(attr_name)
|
49
|
-
|
50
|
-
|
49
|
+
name = attr_name.to_s
|
50
|
+
name = self.class.attribute_aliases[name] || name
|
51
|
+
|
52
|
+
attribute_before_type_cast(name)
|
51
53
|
end
|
52
54
|
|
53
55
|
# Returns a hash of attributes before typecasting and deserialization.
|
@@ -61,20 +63,21 @@ module ActiveRecord
|
|
61
63
|
# task.attributes_before_type_cast
|
62
64
|
# # => {"id"=>nil, "title"=>nil, "is_done"=>true, "completed_on"=>"2012-10-21", "created_at"=>nil, "updated_at"=>nil}
|
63
65
|
def attributes_before_type_cast
|
64
|
-
sync_with_transaction_state if @transaction_state&.finalized?
|
65
66
|
@attributes.values_before_type_cast
|
66
67
|
end
|
67
68
|
|
68
69
|
private
|
69
|
-
|
70
70
|
# Dispatch target for <tt>*_before_type_cast</tt> attribute methods.
|
71
|
-
def attribute_before_type_cast(
|
72
|
-
|
71
|
+
def attribute_before_type_cast(attr_name)
|
72
|
+
@attributes[attr_name].value_before_type_cast
|
73
|
+
end
|
74
|
+
|
75
|
+
def attribute_for_database(attr_name)
|
76
|
+
@attributes[attr_name].value_for_database
|
73
77
|
end
|
74
78
|
|
75
|
-
def attribute_came_from_user?(
|
76
|
-
|
77
|
-
@attributes[attribute_name].came_from_user?
|
79
|
+
def attribute_came_from_user?(attr_name)
|
80
|
+
@attributes[attr_name].came_from_user?
|
78
81
|
end
|
79
82
|
end
|
80
83
|
end
|
@@ -49,7 +49,7 @@ module ActiveRecord
|
|
49
49
|
# +to+ When passed, this method will return false unless the value was
|
50
50
|
# changed to the given value
|
51
51
|
def saved_change_to_attribute?(attr_name, **options)
|
52
|
-
mutations_before_last_save.changed?(attr_name.to_s, options)
|
52
|
+
mutations_before_last_save.changed?(attr_name.to_s, **options)
|
53
53
|
end
|
54
54
|
|
55
55
|
# Returns the change to an attribute during the last save. If the
|
@@ -89,7 +89,7 @@ module ActiveRecord
|
|
89
89
|
# This method is useful in validations and before callbacks to determine
|
90
90
|
# if the next call to +save+ will change a particular attribute. It can be
|
91
91
|
# invoked as +will_save_change_to_name?+ instead of
|
92
|
-
# <tt>will_save_change_to_attribute("name")</tt>.
|
92
|
+
# <tt>will_save_change_to_attribute?("name")</tt>.
|
93
93
|
#
|
94
94
|
# ==== Options
|
95
95
|
#
|
@@ -99,7 +99,7 @@ module ActiveRecord
|
|
99
99
|
# +to+ When passed, this method will return false unless the value will be
|
100
100
|
# changed to the given value
|
101
101
|
def will_save_change_to_attribute?(attr_name, **options)
|
102
|
-
mutations_from_database.changed?(attr_name.to_s, options)
|
102
|
+
mutations_from_database.changed?(attr_name.to_s, **options)
|
103
103
|
end
|
104
104
|
|
105
105
|
# Returns the change to an attribute that will be persisted during the
|
@@ -156,16 +156,6 @@ module ActiveRecord
|
|
156
156
|
end
|
157
157
|
|
158
158
|
private
|
159
|
-
def mutations_from_database
|
160
|
-
sync_with_transaction_state if @transaction_state&.finalized?
|
161
|
-
super
|
162
|
-
end
|
163
|
-
|
164
|
-
def mutations_before_last_save
|
165
|
-
sync_with_transaction_state if @transaction_state&.finalized?
|
166
|
-
super
|
167
|
-
end
|
168
|
-
|
169
159
|
def write_attribute_without_type_cast(attr_name, value)
|
170
160
|
result = super
|
171
161
|
clear_attribute_change(attr_name)
|
@@ -31,7 +31,7 @@ module ActiveRecord
|
|
31
31
|
|
32
32
|
# Returns the primary key column's value before type cast.
|
33
33
|
def id_before_type_cast
|
34
|
-
|
34
|
+
attribute_before_type_cast(@primary_key)
|
35
35
|
end
|
36
36
|
|
37
37
|
# Returns the primary key column's previous value.
|
@@ -44,14 +44,17 @@ module ActiveRecord
|
|
44
44
|
attribute_in_database(@primary_key)
|
45
45
|
end
|
46
46
|
|
47
|
-
|
47
|
+
def id_for_database # :nodoc:
|
48
|
+
@attributes[@primary_key].value_for_database
|
49
|
+
end
|
48
50
|
|
51
|
+
private
|
49
52
|
def attribute_method?(attr_name)
|
50
53
|
attr_name == "id" || super
|
51
54
|
end
|
52
55
|
|
53
56
|
module ClassMethods
|
54
|
-
ID_ATTRIBUTE_METHODS = %w(id id= id? id_before_type_cast id_was id_in_database).to_set
|
57
|
+
ID_ATTRIBUTE_METHODS = %w(id id= id? id_before_type_cast id_was id_in_database id_for_database).to_set
|
55
58
|
|
56
59
|
def instance_method_already_implemented?(method_name)
|
57
60
|
super || primary_key && ID_ATTRIBUTE_METHODS.include?(method_name)
|
@@ -120,7 +123,6 @@ module ActiveRecord
|
|
120
123
|
end
|
121
124
|
|
122
125
|
private
|
123
|
-
|
124
126
|
def suppress_composite_primary_key(pk)
|
125
127
|
return pk unless pk.is_a?(Array)
|
126
128
|
|
@@ -17,7 +17,7 @@ module ActiveRecord
|
|
17
17
|
when false, nil then false
|
18
18
|
else
|
19
19
|
if !type_for_attribute(attr_name) { false }
|
20
|
-
if Numeric === value || value
|
20
|
+
if Numeric === value || !value.match?(/[^0-9]/)
|
21
21
|
!value.to_i.zero?
|
22
22
|
else
|
23
23
|
return false if ActiveModel::Type::Boolean::FALSE_VALUES.include?(value)
|
@@ -31,11 +31,8 @@ module ActiveRecord
|
|
31
31
|
end
|
32
32
|
end
|
33
33
|
|
34
|
-
|
35
|
-
|
36
|
-
def attribute?(attribute_name)
|
37
|
-
query_attribute(attribute_name)
|
38
|
-
end
|
34
|
+
alias :attribute? :query_attribute
|
35
|
+
private :attribute?
|
39
36
|
end
|
40
37
|
end
|
41
38
|
end
|