activerecord 4.2.11.3 → 5.0.7.2
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 +1638 -1132
- data/MIT-LICENSE +2 -2
- data/README.rdoc +7 -8
- data/examples/performance.rb +2 -3
- data/examples/simple.rb +0 -1
- data/lib/active_record.rb +7 -2
- data/lib/active_record/aggregations.rb +34 -21
- data/lib/active_record/association_relation.rb +7 -4
- data/lib/active_record/associations.rb +347 -218
- data/lib/active_record/associations/alias_tracker.rb +19 -16
- data/lib/active_record/associations/association.rb +22 -10
- data/lib/active_record/associations/association_scope.rb +75 -104
- data/lib/active_record/associations/belongs_to_association.rb +21 -32
- data/lib/active_record/associations/builder/association.rb +28 -34
- data/lib/active_record/associations/builder/belongs_to.rb +43 -18
- data/lib/active_record/associations/builder/collection_association.rb +7 -19
- data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +16 -11
- data/lib/active_record/associations/builder/has_many.rb +4 -4
- data/lib/active_record/associations/builder/has_one.rb +11 -6
- data/lib/active_record/associations/builder/singular_association.rb +13 -11
- data/lib/active_record/associations/collection_association.rb +85 -69
- data/lib/active_record/associations/collection_proxy.rb +104 -46
- data/lib/active_record/associations/foreign_association.rb +1 -1
- data/lib/active_record/associations/has_many_association.rb +21 -78
- data/lib/active_record/associations/has_many_through_association.rb +6 -47
- data/lib/active_record/associations/has_one_association.rb +12 -5
- data/lib/active_record/associations/join_dependency.rb +38 -22
- data/lib/active_record/associations/join_dependency/join_association.rb +15 -14
- data/lib/active_record/associations/join_dependency/join_part.rb +2 -2
- data/lib/active_record/associations/preloader.rb +14 -4
- data/lib/active_record/associations/preloader/association.rb +52 -71
- data/lib/active_record/associations/preloader/collection_association.rb +0 -7
- data/lib/active_record/associations/preloader/has_many_through.rb +1 -1
- data/lib/active_record/associations/preloader/has_one.rb +0 -8
- data/lib/active_record/associations/preloader/singular_association.rb +0 -1
- data/lib/active_record/associations/preloader/through_association.rb +36 -17
- data/lib/active_record/associations/singular_association.rb +13 -1
- data/lib/active_record/associations/through_association.rb +12 -4
- data/lib/active_record/attribute.rb +69 -19
- data/lib/active_record/attribute/user_provided_default.rb +28 -0
- data/lib/active_record/attribute_assignment.rb +19 -140
- data/lib/active_record/attribute_decorators.rb +6 -5
- data/lib/active_record/attribute_methods.rb +69 -44
- data/lib/active_record/attribute_methods/before_type_cast.rb +1 -1
- data/lib/active_record/attribute_methods/dirty.rb +46 -86
- data/lib/active_record/attribute_methods/primary_key.rb +16 -3
- data/lib/active_record/attribute_methods/query.rb +2 -2
- data/lib/active_record/attribute_methods/read.rb +31 -59
- data/lib/active_record/attribute_methods/serialization.rb +13 -16
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +61 -14
- data/lib/active_record/attribute_methods/write.rb +13 -37
- data/lib/active_record/attribute_mutation_tracker.rb +70 -0
- data/lib/active_record/attribute_set.rb +32 -3
- data/lib/active_record/attribute_set/builder.rb +42 -16
- data/lib/active_record/attributes.rb +199 -81
- data/lib/active_record/autosave_association.rb +54 -17
- data/lib/active_record/base.rb +32 -23
- data/lib/active_record/callbacks.rb +39 -43
- data/lib/active_record/coders/json.rb +1 -1
- data/lib/active_record/coders/yaml_column.rb +20 -8
- data/lib/active_record/collection_cache_key.rb +50 -0
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +467 -189
- data/lib/active_record/connection_adapters/abstract/database_limits.rb +3 -3
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +66 -62
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +39 -4
- data/lib/active_record/connection_adapters/abstract/quoting.rb +86 -13
- data/lib/active_record/connection_adapters/abstract/savepoints.rb +3 -3
- data/lib/active_record/connection_adapters/abstract/schema_creation.rb +61 -39
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +236 -188
- data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +72 -17
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +407 -156
- data/lib/active_record/connection_adapters/abstract/transaction.rb +51 -34
- data/lib/active_record/connection_adapters/abstract_adapter.rb +177 -71
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +433 -399
- data/lib/active_record/connection_adapters/column.rb +28 -43
- data/lib/active_record/connection_adapters/connection_specification.rb +15 -27
- data/lib/active_record/connection_adapters/determine_if_preparable_visitor.rb +22 -0
- data/lib/active_record/connection_adapters/mysql/column.rb +50 -0
- data/lib/active_record/connection_adapters/mysql/database_statements.rb +108 -0
- data/lib/active_record/connection_adapters/mysql/explain_pretty_printer.rb +70 -0
- data/lib/active_record/connection_adapters/mysql/quoting.rb +51 -0
- data/lib/active_record/connection_adapters/mysql/schema_creation.rb +67 -0
- data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +93 -0
- data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +54 -0
- data/lib/active_record/connection_adapters/mysql/type_metadata.rb +32 -0
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +25 -166
- data/lib/active_record/connection_adapters/postgresql/column.rb +33 -11
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +18 -72
- data/lib/active_record/connection_adapters/postgresql/explain_pretty_printer.rb +42 -0
- data/lib/active_record/connection_adapters/postgresql/oid.rb +1 -6
- data/lib/active_record/connection_adapters/postgresql/oid/array.rb +37 -57
- data/lib/active_record/connection_adapters/postgresql/oid/bit.rb +3 -3
- data/lib/active_record/connection_adapters/postgresql/oid/bytea.rb +2 -2
- data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +3 -1
- data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +7 -22
- data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +13 -3
- data/lib/active_record/connection_adapters/postgresql/oid/json.rb +1 -26
- data/lib/active_record/connection_adapters/postgresql/oid/jsonb.rb +2 -2
- data/lib/active_record/connection_adapters/postgresql/oid/money.rb +0 -4
- data/lib/active_record/connection_adapters/postgresql/oid/point.rb +4 -4
- data/lib/active_record/connection_adapters/postgresql/oid/rails_5_1_point.rb +50 -0
- data/lib/active_record/connection_adapters/postgresql/oid/range.rb +31 -17
- data/lib/active_record/connection_adapters/postgresql/oid/specialized_string.rb +0 -4
- data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +2 -2
- data/lib/active_record/connection_adapters/postgresql/oid/vector.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/oid/xml.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/quoting.rb +56 -19
- data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +29 -10
- data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +107 -79
- data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +47 -0
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +250 -154
- data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +35 -0
- data/lib/active_record/connection_adapters/postgresql/utils.rb +2 -2
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +264 -170
- data/lib/active_record/connection_adapters/schema_cache.rb +36 -23
- data/lib/active_record/connection_adapters/sql_type_metadata.rb +32 -0
- data/lib/active_record/connection_adapters/sqlite3/explain_pretty_printer.rb +19 -0
- data/lib/active_record/connection_adapters/sqlite3/quoting.rb +48 -0
- data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +22 -0
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +151 -194
- data/lib/active_record/connection_adapters/statement_pool.rb +31 -12
- data/lib/active_record/connection_handling.rb +37 -14
- data/lib/active_record/core.rb +92 -108
- data/lib/active_record/counter_cache.rb +13 -24
- data/lib/active_record/dynamic_matchers.rb +1 -20
- data/lib/active_record/enum.rb +116 -76
- data/lib/active_record/errors.rb +87 -48
- data/lib/active_record/explain.rb +20 -9
- data/lib/active_record/explain_registry.rb +1 -1
- data/lib/active_record/explain_subscriber.rb +1 -1
- data/lib/active_record/fixture_set/file.rb +26 -5
- data/lib/active_record/fixtures.rb +77 -41
- data/lib/active_record/gem_version.rb +4 -4
- data/lib/active_record/inheritance.rb +32 -40
- data/lib/active_record/integration.rb +17 -14
- data/lib/active_record/internal_metadata.rb +56 -0
- data/lib/active_record/legacy_yaml_adapter.rb +18 -2
- data/lib/active_record/locale/en.yml +3 -2
- data/lib/active_record/locking/optimistic.rb +15 -15
- data/lib/active_record/locking/pessimistic.rb +1 -1
- data/lib/active_record/log_subscriber.rb +48 -24
- data/lib/active_record/migration.rb +362 -111
- data/lib/active_record/migration/command_recorder.rb +59 -18
- data/lib/active_record/migration/compatibility.rb +126 -0
- data/lib/active_record/model_schema.rb +270 -73
- data/lib/active_record/nested_attributes.rb +58 -29
- data/lib/active_record/no_touching.rb +4 -0
- data/lib/active_record/null_relation.rb +16 -8
- data/lib/active_record/persistence.rb +152 -90
- data/lib/active_record/query_cache.rb +18 -23
- data/lib/active_record/querying.rb +12 -11
- data/lib/active_record/railtie.rb +23 -16
- data/lib/active_record/railties/controller_runtime.rb +1 -1
- data/lib/active_record/railties/databases.rake +52 -41
- data/lib/active_record/readonly_attributes.rb +1 -1
- data/lib/active_record/reflection.rb +302 -115
- data/lib/active_record/relation.rb +187 -120
- data/lib/active_record/relation/batches.rb +141 -36
- data/lib/active_record/relation/batches/batch_enumerator.rb +67 -0
- data/lib/active_record/relation/calculations.rb +92 -117
- data/lib/active_record/relation/delegation.rb +8 -20
- data/lib/active_record/relation/finder_methods.rb +173 -89
- data/lib/active_record/relation/from_clause.rb +32 -0
- data/lib/active_record/relation/merger.rb +16 -42
- data/lib/active_record/relation/predicate_builder.rb +120 -107
- data/lib/active_record/relation/predicate_builder/array_handler.rb +11 -16
- data/lib/active_record/relation/predicate_builder/association_query_handler.rb +88 -0
- data/lib/active_record/relation/predicate_builder/base_handler.rb +17 -0
- data/lib/active_record/relation/predicate_builder/basic_object_handler.rb +17 -0
- data/lib/active_record/relation/predicate_builder/class_handler.rb +27 -0
- data/lib/active_record/relation/predicate_builder/polymorphic_array_handler.rb +57 -0
- data/lib/active_record/relation/predicate_builder/range_handler.rb +33 -0
- data/lib/active_record/relation/predicate_builder/relation_handler.rb +1 -1
- data/lib/active_record/relation/query_attribute.rb +19 -0
- data/lib/active_record/relation/query_methods.rb +308 -244
- data/lib/active_record/relation/record_fetch_warning.rb +49 -0
- data/lib/active_record/relation/spawn_methods.rb +4 -7
- data/lib/active_record/relation/where_clause.rb +174 -0
- data/lib/active_record/relation/where_clause_factory.rb +38 -0
- data/lib/active_record/result.rb +11 -4
- data/lib/active_record/runtime_registry.rb +1 -1
- data/lib/active_record/sanitization.rb +105 -66
- data/lib/active_record/schema.rb +26 -22
- data/lib/active_record/schema_dumper.rb +54 -37
- data/lib/active_record/schema_migration.rb +11 -14
- data/lib/active_record/scoping.rb +34 -16
- data/lib/active_record/scoping/default.rb +28 -10
- data/lib/active_record/scoping/named.rb +59 -26
- data/lib/active_record/secure_token.rb +38 -0
- data/lib/active_record/serialization.rb +3 -5
- data/lib/active_record/statement_cache.rb +17 -15
- data/lib/active_record/store.rb +8 -3
- data/lib/active_record/suppressor.rb +58 -0
- data/lib/active_record/table_metadata.rb +69 -0
- data/lib/active_record/tasks/database_tasks.rb +66 -49
- data/lib/active_record/tasks/mysql_database_tasks.rb +6 -14
- data/lib/active_record/tasks/postgresql_database_tasks.rb +12 -3
- data/lib/active_record/tasks/sqlite_database_tasks.rb +5 -1
- data/lib/active_record/timestamp.rb +20 -9
- data/lib/active_record/touch_later.rb +63 -0
- data/lib/active_record/transactions.rb +139 -57
- data/lib/active_record/type.rb +66 -17
- data/lib/active_record/type/adapter_specific_registry.rb +130 -0
- data/lib/active_record/type/date.rb +2 -45
- data/lib/active_record/type/date_time.rb +2 -49
- data/lib/active_record/type/internal/abstract_json.rb +33 -0
- data/lib/active_record/type/internal/timezone.rb +15 -0
- data/lib/active_record/type/serialized.rb +15 -14
- data/lib/active_record/type/time.rb +10 -16
- data/lib/active_record/type/type_map.rb +4 -4
- data/lib/active_record/type_caster.rb +7 -0
- data/lib/active_record/type_caster/connection.rb +29 -0
- data/lib/active_record/type_caster/map.rb +19 -0
- data/lib/active_record/validations.rb +33 -32
- data/lib/active_record/validations/absence.rb +23 -0
- data/lib/active_record/validations/associated.rb +10 -3
- data/lib/active_record/validations/length.rb +24 -0
- data/lib/active_record/validations/presence.rb +11 -12
- data/lib/active_record/validations/uniqueness.rb +33 -33
- data/lib/rails/generators/active_record/migration.rb +15 -0
- data/lib/rails/generators/active_record/migration/migration_generator.rb +8 -5
- data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb +8 -3
- data/lib/rails/generators/active_record/migration/templates/migration.rb +8 -1
- data/lib/rails/generators/active_record/model/model_generator.rb +33 -16
- data/lib/rails/generators/active_record/model/templates/application_record.rb +5 -0
- data/lib/rails/generators/active_record/model/templates/model.rb +3 -0
- metadata +58 -34
- data/lib/active_record/connection_adapters/mysql_adapter.rb +0 -498
- data/lib/active_record/connection_adapters/postgresql/array_parser.rb +0 -93
- data/lib/active_record/connection_adapters/postgresql/oid/date.rb +0 -11
- data/lib/active_record/connection_adapters/postgresql/oid/float.rb +0 -21
- data/lib/active_record/connection_adapters/postgresql/oid/infinity.rb +0 -13
- data/lib/active_record/connection_adapters/postgresql/oid/integer.rb +0 -11
- data/lib/active_record/connection_adapters/postgresql/oid/time.rb +0 -11
- data/lib/active_record/serializers/xml_serializer.rb +0 -193
- data/lib/active_record/type/big_integer.rb +0 -13
- data/lib/active_record/type/binary.rb +0 -50
- data/lib/active_record/type/boolean.rb +0 -31
- data/lib/active_record/type/decimal.rb +0 -64
- data/lib/active_record/type/decimal_without_scale.rb +0 -11
- data/lib/active_record/type/decorator.rb +0 -14
- data/lib/active_record/type/float.rb +0 -19
- data/lib/active_record/type/integer.rb +0 -59
- data/lib/active_record/type/mutable.rb +0 -16
- data/lib/active_record/type/numeric.rb +0 -36
- data/lib/active_record/type/string.rb +0 -40
- data/lib/active_record/type/text.rb +0 -11
- data/lib/active_record/type/time_value.rb +0 -38
- data/lib/active_record/type/unsigned_integer.rb +0 -15
- data/lib/active_record/type/value.rb +0 -110
@@ -54,6 +54,8 @@ module ActiveRecord
|
|
54
54
|
autoload :BelongsTo, 'active_record/associations/preloader/belongs_to'
|
55
55
|
end
|
56
56
|
|
57
|
+
NULL_RELATION = Struct.new(:values, :where_clause, :joins_values).new({}, Relation::WhereClause.empty, [])
|
58
|
+
|
57
59
|
# Eager loads the named associations for the given Active Record record(s).
|
58
60
|
#
|
59
61
|
# In this description, 'association name' shall refer to the name passed
|
@@ -88,9 +90,6 @@ module ActiveRecord
|
|
88
90
|
# [ :books, :author ]
|
89
91
|
# { author: :avatar }
|
90
92
|
# [ :books, { author: :avatar } ]
|
91
|
-
|
92
|
-
NULL_RELATION = Struct.new(:values, :bind_values).new({}, [])
|
93
|
-
|
94
93
|
def preload(records, associations, preload_scope = nil)
|
95
94
|
records = Array.wrap(records).compact.uniq
|
96
95
|
associations = Array.wrap(associations)
|
@@ -107,6 +106,7 @@ module ActiveRecord
|
|
107
106
|
|
108
107
|
private
|
109
108
|
|
109
|
+
# Loads all the given data into +records+ for the +association+.
|
110
110
|
def preloaders_on(association, records, scope)
|
111
111
|
case association
|
112
112
|
when Hash
|
@@ -116,7 +116,7 @@ module ActiveRecord
|
|
116
116
|
when String
|
117
117
|
preloaders_for_one(association.to_sym, records, scope)
|
118
118
|
else
|
119
|
-
raise ArgumentError, "#{association.inspect} was not
|
119
|
+
raise ArgumentError, "#{association.inspect} was not recognized for preload"
|
120
120
|
end
|
121
121
|
end
|
122
122
|
|
@@ -132,6 +132,11 @@ module ActiveRecord
|
|
132
132
|
}
|
133
133
|
end
|
134
134
|
|
135
|
+
# Loads all the given data into +records+ for a singular +association+.
|
136
|
+
#
|
137
|
+
# Functions by instantiating a preloader class such as Preloader::HasManyThrough and
|
138
|
+
# call the +run+ method for each passed in class in the +records+ argument.
|
139
|
+
#
|
135
140
|
# Not all records have the same class, so group then preload group on the reflection
|
136
141
|
# itself so that if various subclass share the same association then we do not split
|
137
142
|
# them unnecessarily
|
@@ -179,8 +184,13 @@ module ActiveRecord
|
|
179
184
|
def self.new(klass, owners, reflection, preload_scope); self; end
|
180
185
|
def self.run(preloader); end
|
181
186
|
def self.preloaded_records; []; end
|
187
|
+
def self.owners; []; end
|
182
188
|
end
|
183
189
|
|
190
|
+
# Returns a class containing the logic needed to load preload the data
|
191
|
+
# and attach it to a relation. For example +Preloader::Association+ or
|
192
|
+
# +Preloader::HasManyThrough+. The class returned implements a `run` method
|
193
|
+
# that accepts a preloader.
|
184
194
|
def preloader_for(reflection, owners, rhs_klass)
|
185
195
|
return NullPreloader unless rhs_klass
|
186
196
|
|
@@ -12,7 +12,6 @@ module ActiveRecord
|
|
12
12
|
@preload_scope = preload_scope
|
13
13
|
@model = owners.first && owners.first.class
|
14
14
|
@scope = nil
|
15
|
-
@owners_by_key = nil
|
16
15
|
@preloaded_records = []
|
17
16
|
end
|
18
17
|
|
@@ -33,7 +32,7 @@ module ActiveRecord
|
|
33
32
|
end
|
34
33
|
|
35
34
|
def query_scope(ids)
|
36
|
-
scope.where(
|
35
|
+
scope.where(association_key_name => ids)
|
37
36
|
end
|
38
37
|
|
39
38
|
def table
|
@@ -48,7 +47,7 @@ module ActiveRecord
|
|
48
47
|
# This is overridden by HABTM as the condition should be on the foreign_key column in
|
49
48
|
# the join table
|
50
49
|
def association_key
|
51
|
-
table
|
50
|
+
klass.arel_attribute(association_key_name, table)
|
52
51
|
end
|
53
52
|
|
54
53
|
# The name of the key on the model which declares the association
|
@@ -56,18 +55,6 @@ module ActiveRecord
|
|
56
55
|
raise NotImplementedError
|
57
56
|
end
|
58
57
|
|
59
|
-
def owners_by_key
|
60
|
-
@owners_by_key ||= if key_conversion_required?
|
61
|
-
owners.group_by do |owner|
|
62
|
-
owner[owner_key_name].to_s
|
63
|
-
end
|
64
|
-
else
|
65
|
-
owners.group_by do |owner|
|
66
|
-
owner[owner_key_name]
|
67
|
-
end
|
68
|
-
end
|
69
|
-
end
|
70
|
-
|
71
58
|
def options
|
72
59
|
reflection.options
|
73
60
|
end
|
@@ -75,32 +62,47 @@ module ActiveRecord
|
|
75
62
|
private
|
76
63
|
|
77
64
|
def associated_records_by_owner(preloader)
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
records_by_owner = owners.each_with_object({}) do |owner,h|
|
83
|
-
h[owner] = []
|
65
|
+
records = load_records do |record|
|
66
|
+
owner = owners_by_key[convert_key(record[association_key_name])]
|
67
|
+
association = owner.association(reflection.name)
|
68
|
+
association.set_inverse_instance(record)
|
84
69
|
end
|
85
70
|
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
71
|
+
owners.each_with_object({}) do |owner, result|
|
72
|
+
result[owner] = records[convert_key(owner[owner_key_name])] || []
|
73
|
+
end
|
74
|
+
end
|
90
75
|
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
end
|
76
|
+
def owner_keys
|
77
|
+
unless defined?(@owner_keys)
|
78
|
+
@owner_keys = owners.map do |owner|
|
79
|
+
owner[owner_key_name]
|
96
80
|
end
|
81
|
+
@owner_keys.uniq!
|
82
|
+
@owner_keys.compact!
|
97
83
|
end
|
84
|
+
@owner_keys
|
85
|
+
end
|
98
86
|
|
99
|
-
|
87
|
+
def owners_by_key
|
88
|
+
unless defined?(@owners_by_key)
|
89
|
+
@owners_by_key = owners.each_with_object({}) do |owner, h|
|
90
|
+
h[convert_key(owner[owner_key_name])] = owner
|
91
|
+
end
|
92
|
+
end
|
93
|
+
@owners_by_key
|
100
94
|
end
|
101
95
|
|
102
96
|
def key_conversion_required?
|
103
|
-
association_key_type != owner_key_type
|
97
|
+
@key_conversion_required ||= association_key_type != owner_key_type
|
98
|
+
end
|
99
|
+
|
100
|
+
def convert_key(key)
|
101
|
+
if key_conversion_required?
|
102
|
+
key.to_s
|
103
|
+
else
|
104
|
+
key
|
105
|
+
end
|
104
106
|
end
|
105
107
|
|
106
108
|
def association_key_type
|
@@ -111,54 +113,33 @@ module ActiveRecord
|
|
111
113
|
@model.type_for_attribute(owner_key_name.to_s).type
|
112
114
|
end
|
113
115
|
|
114
|
-
def
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
@preloaded_records.
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
[
|
124
|
-
|
116
|
+
def load_records(&block)
|
117
|
+
return {} if owner_keys.empty?
|
118
|
+
# Some databases impose a limit on the number of ids in a list (in Oracle it's 1000)
|
119
|
+
# Make several smaller queries if necessary or make one query if the adapter supports it
|
120
|
+
slices = owner_keys.each_slice(klass.connection.in_clause_length || owner_keys.size)
|
121
|
+
@preloaded_records = slices.flat_map do |slice|
|
122
|
+
records_for(slice).load(&block)
|
123
|
+
end
|
124
|
+
@preloaded_records.group_by do |record|
|
125
|
+
convert_key(record[association_key_name])
|
126
|
+
end
|
125
127
|
end
|
126
128
|
|
127
129
|
def reflection_scope
|
128
|
-
@reflection_scope ||= reflection.
|
130
|
+
@reflection_scope ||= reflection.scope_for(klass)
|
129
131
|
end
|
130
132
|
|
131
133
|
def build_scope
|
132
|
-
scope = klass.
|
133
|
-
|
134
|
-
values = reflection_scope.values
|
135
|
-
reflection_binds = reflection_scope.bind_values
|
136
|
-
preload_values = preload_scope.values
|
137
|
-
preload_binds = preload_scope.bind_values
|
138
|
-
|
139
|
-
scope.where_values = Array(values[:where]) + Array(preload_values[:where])
|
140
|
-
scope.references_values = Array(values[:references]) + Array(preload_values[:references])
|
141
|
-
scope.bind_values = (reflection_binds + preload_binds)
|
142
|
-
|
143
|
-
scope._select! preload_values[:select] || values[:select] || table[Arel.star]
|
144
|
-
scope.includes! preload_values[:includes] || values[:includes]
|
145
|
-
scope.joins! preload_values[:joins] || values[:joins]
|
146
|
-
scope.order! preload_values[:order] || values[:order]
|
147
|
-
|
148
|
-
if preload_values[:reordering] || values[:reordering]
|
149
|
-
scope.reordering_value = true
|
150
|
-
end
|
151
|
-
|
152
|
-
if preload_values[:readonly] || values[:readonly]
|
153
|
-
scope.readonly!
|
154
|
-
end
|
134
|
+
scope = klass.scope_for_association
|
155
135
|
|
156
|
-
if
|
157
|
-
scope.where!(
|
136
|
+
if reflection.type
|
137
|
+
scope.where!(reflection.type => model.base_class.sti_name)
|
158
138
|
end
|
159
139
|
|
160
|
-
scope.
|
161
|
-
|
140
|
+
scope.merge!(reflection_scope)
|
141
|
+
scope.merge!(preload_scope) if preload_scope != NULL_RELATION
|
142
|
+
scope
|
162
143
|
end
|
163
144
|
end
|
164
145
|
end
|
@@ -2,22 +2,15 @@ module ActiveRecord
|
|
2
2
|
module Associations
|
3
3
|
class Preloader
|
4
4
|
class CollectionAssociation < Association #:nodoc:
|
5
|
-
|
6
5
|
private
|
7
6
|
|
8
|
-
def build_scope
|
9
|
-
super.order(preload_scope.values[:order] || reflection_scope.values[:order])
|
10
|
-
end
|
11
|
-
|
12
7
|
def preload(preloader)
|
13
8
|
associated_records_by_owner(preloader).each do |owner, records|
|
14
9
|
association = owner.association(reflection.name)
|
15
10
|
association.loaded!
|
16
11
|
association.target.concat(records)
|
17
|
-
records.each { |record| association.set_inverse_instance(record) }
|
18
12
|
end
|
19
13
|
end
|
20
|
-
|
21
14
|
end
|
22
15
|
end
|
23
16
|
end
|
@@ -2,7 +2,6 @@ module ActiveRecord
|
|
2
2
|
module Associations
|
3
3
|
class Preloader
|
4
4
|
class HasOne < SingularAssociation #:nodoc:
|
5
|
-
|
6
5
|
def association_key_name
|
7
6
|
reflection.foreign_key
|
8
7
|
end
|
@@ -10,13 +9,6 @@ module ActiveRecord
|
|
10
9
|
def owner_key_name
|
11
10
|
reflection.active_record_primary_key
|
12
11
|
end
|
13
|
-
|
14
|
-
private
|
15
|
-
|
16
|
-
def build_scope
|
17
|
-
super.order(preload_scope.values[:order] || reflection_scope.values[:order])
|
18
|
-
end
|
19
|
-
|
20
12
|
end
|
21
13
|
end
|
22
14
|
end
|
@@ -18,7 +18,8 @@ module ActiveRecord
|
|
18
18
|
through_records = owners.map do |owner|
|
19
19
|
association = owner.association through_reflection.name
|
20
20
|
|
21
|
-
|
21
|
+
center = target_records_from_association(association)
|
22
|
+
[owner, Array(center)]
|
22
23
|
end
|
23
24
|
|
24
25
|
reset_association owners, through_reflection.name
|
@@ -37,28 +38,35 @@ module ActiveRecord
|
|
37
38
|
}
|
38
39
|
end
|
39
40
|
|
40
|
-
|
41
|
-
@preloaded_records.each_with_index do |record,i|
|
42
|
-
record_offset[record] = i
|
43
|
-
end
|
44
|
-
|
45
|
-
through_records.each_with_object({}) { |(lhs,center),records_by_owner|
|
41
|
+
through_records.each_with_object({}) do |(lhs,center), records_by_owner|
|
46
42
|
pl_to_middle = center.group_by { |record| middle_to_pl[record] }
|
47
43
|
|
48
44
|
records_by_owner[lhs] = pl_to_middle.flat_map do |pl, middles|
|
49
45
|
rhs_records = middles.flat_map { |r|
|
50
46
|
association = r.association source_reflection.name
|
51
47
|
|
52
|
-
association
|
48
|
+
target_records_from_association(association)
|
53
49
|
}.compact
|
54
50
|
|
55
|
-
|
51
|
+
# Respect the order on `reflection_scope` if it exists, else use the natural order.
|
52
|
+
if reflection_scope.values[:order].present?
|
53
|
+
@id_map ||= id_to_index_map @preloaded_records
|
54
|
+
rhs_records.sort_by { |rhs| @id_map[rhs] }
|
55
|
+
else
|
56
|
+
rhs_records
|
57
|
+
end
|
56
58
|
end
|
57
|
-
|
59
|
+
end
|
58
60
|
end
|
59
61
|
|
60
62
|
private
|
61
63
|
|
64
|
+
def id_to_index_map(ids)
|
65
|
+
id_map = {}
|
66
|
+
ids.each_with_index { |id, index| id_map[id] = index }
|
67
|
+
id_map
|
68
|
+
end
|
69
|
+
|
62
70
|
def reset_association(owners, association_name)
|
63
71
|
should_reset = (through_scope != through_reflection.klass.unscoped) ||
|
64
72
|
(reflection.options[:source_type] && through_reflection.collection?)
|
@@ -71,25 +79,36 @@ module ActiveRecord
|
|
71
79
|
end
|
72
80
|
end
|
73
81
|
|
74
|
-
|
75
82
|
def through_scope
|
76
83
|
scope = through_reflection.klass.unscoped
|
84
|
+
values = reflection_scope.values
|
77
85
|
|
78
86
|
if options[:source_type]
|
79
87
|
scope.where! reflection.foreign_type => options[:source_type]
|
80
88
|
else
|
81
|
-
unless reflection_scope.
|
82
|
-
scope.includes_values = Array(
|
83
|
-
scope.
|
84
|
-
|
89
|
+
unless reflection_scope.where_clause.empty?
|
90
|
+
scope.includes_values = Array(values[:includes] || options[:source])
|
91
|
+
scope.where_clause = reflection_scope.where_clause
|
92
|
+
if joins = values[:joins]
|
93
|
+
scope.joins!(source_reflection.name => joins)
|
94
|
+
end
|
95
|
+
if left_outer_joins = values[:left_outer_joins]
|
96
|
+
scope.left_outer_joins!(source_reflection.name => left_outer_joins)
|
97
|
+
end
|
85
98
|
end
|
86
99
|
|
87
|
-
scope.references!
|
88
|
-
scope =
|
100
|
+
scope.references! values[:references]
|
101
|
+
if scope.eager_loading? && order_values = values[:order]
|
102
|
+
scope = scope.order(order_values)
|
103
|
+
end
|
89
104
|
end
|
90
105
|
|
91
106
|
scope
|
92
107
|
end
|
108
|
+
|
109
|
+
def target_records_from_association(association)
|
110
|
+
association.loaded? ? association.target : association.reader
|
111
|
+
end
|
93
112
|
end
|
94
113
|
end
|
95
114
|
end
|
@@ -4,6 +4,11 @@ module ActiveRecord
|
|
4
4
|
# Implements the reader method, e.g. foo.bar for Foo.has_one :bar
|
5
5
|
def reader(force_reload = false)
|
6
6
|
if force_reload && klass
|
7
|
+
ActiveSupport::Deprecation.warn(<<-MSG.squish)
|
8
|
+
Passing an argument to force an association to reload is now
|
9
|
+
deprecated and will be removed in Rails 5.1. Please call `reload_#{reflection.name}` instead.
|
10
|
+
MSG
|
11
|
+
|
7
12
|
klass.uncached { reload }
|
8
13
|
elsif !loaded? || stale_target?
|
9
14
|
reload
|
@@ -32,6 +37,13 @@ module ActiveRecord
|
|
32
37
|
record
|
33
38
|
end
|
34
39
|
|
40
|
+
# Implements the reload reader method, e.g. foo.reload_bar for
|
41
|
+
# Foo.has_one :bar
|
42
|
+
def force_reload_reader
|
43
|
+
klass.uncached { reload }
|
44
|
+
target
|
45
|
+
end
|
46
|
+
|
35
47
|
private
|
36
48
|
|
37
49
|
def create_scope
|
@@ -39,7 +51,7 @@ module ActiveRecord
|
|
39
51
|
end
|
40
52
|
|
41
53
|
def get_records
|
42
|
-
return scope.limit(1).
|
54
|
+
return scope.limit(1).records if skip_statement_cache?
|
43
55
|
|
44
56
|
conn = klass.connection
|
45
57
|
sc = reflection.association_scope_cache(conn, owner) do
|