activerecord 5.2.4.4 → 6.0.3.4
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of activerecord might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/CHANGELOG.md +777 -552
- data/MIT-LICENSE +3 -1
- data/README.rdoc +5 -3
- data/examples/performance.rb +1 -1
- data/lib/active_record.rb +10 -2
- data/lib/active_record/advisory_lock_base.rb +18 -0
- data/lib/active_record/aggregations.rb +4 -3
- data/lib/active_record/association_relation.rb +10 -8
- data/lib/active_record/associations.rb +21 -16
- data/lib/active_record/associations/alias_tracker.rb +0 -1
- data/lib/active_record/associations/association.rb +56 -19
- data/lib/active_record/associations/association_scope.rb +4 -6
- data/lib/active_record/associations/belongs_to_association.rb +36 -42
- data/lib/active_record/associations/belongs_to_polymorphic_association.rb +0 -4
- data/lib/active_record/associations/builder/association.rb +14 -18
- data/lib/active_record/associations/builder/belongs_to.rb +19 -52
- data/lib/active_record/associations/builder/collection_association.rb +3 -13
- data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +17 -40
- data/lib/active_record/associations/builder/has_many.rb +2 -0
- data/lib/active_record/associations/builder/has_one.rb +35 -1
- data/lib/active_record/associations/builder/singular_association.rb +2 -0
- data/lib/active_record/associations/collection_association.rb +12 -23
- data/lib/active_record/associations/collection_proxy.rb +13 -17
- data/lib/active_record/associations/foreign_association.rb +7 -0
- data/lib/active_record/associations/has_many_association.rb +2 -11
- data/lib/active_record/associations/has_many_through_association.rb +14 -14
- data/lib/active_record/associations/has_one_association.rb +28 -30
- data/lib/active_record/associations/has_one_through_association.rb +5 -5
- data/lib/active_record/associations/join_dependency.rb +37 -28
- data/lib/active_record/associations/join_dependency/join_association.rb +9 -10
- data/lib/active_record/associations/join_dependency/join_part.rb +2 -2
- data/lib/active_record/associations/preloader.rb +39 -32
- data/lib/active_record/associations/preloader/association.rb +38 -36
- data/lib/active_record/associations/preloader/through_association.rb +48 -39
- data/lib/active_record/associations/singular_association.rb +2 -16
- data/lib/active_record/attribute_assignment.rb +7 -11
- data/lib/active_record/attribute_decorators.rb +0 -2
- data/lib/active_record/attribute_methods.rb +28 -100
- data/lib/active_record/attribute_methods/before_type_cast.rb +4 -2
- data/lib/active_record/attribute_methods/dirty.rb +111 -40
- data/lib/active_record/attribute_methods/primary_key.rb +15 -24
- data/lib/active_record/attribute_methods/query.rb +2 -3
- data/lib/active_record/attribute_methods/read.rb +15 -54
- data/lib/active_record/attribute_methods/serialization.rb +1 -2
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +1 -3
- data/lib/active_record/attribute_methods/write.rb +17 -25
- data/lib/active_record/attributes.rb +13 -1
- data/lib/active_record/autosave_association.rb +3 -5
- data/lib/active_record/base.rb +2 -3
- data/lib/active_record/callbacks.rb +6 -21
- data/lib/active_record/coders/yaml_column.rb +0 -1
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +103 -18
- data/lib/active_record/connection_adapters/abstract/database_limits.rb +17 -4
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +102 -124
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +18 -9
- data/lib/active_record/connection_adapters/abstract/quoting.rb +68 -17
- data/lib/active_record/connection_adapters/abstract/schema_creation.rb +20 -14
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +100 -72
- data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +1 -3
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +175 -79
- data/lib/active_record/connection_adapters/abstract/transaction.rb +96 -57
- data/lib/active_record/connection_adapters/abstract_adapter.rb +191 -43
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +142 -215
- data/lib/active_record/connection_adapters/column.rb +17 -13
- data/lib/active_record/connection_adapters/connection_specification.rb +54 -45
- data/lib/active_record/connection_adapters/determine_if_preparable_visitor.rb +6 -10
- data/lib/active_record/connection_adapters/mysql/column.rb +1 -1
- data/lib/active_record/connection_adapters/mysql/database_statements.rb +70 -14
- data/lib/active_record/connection_adapters/mysql/explain_pretty_printer.rb +0 -1
- data/lib/active_record/connection_adapters/mysql/quoting.rb +44 -7
- data/lib/active_record/connection_adapters/mysql/schema_creation.rb +4 -6
- data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +40 -32
- data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +14 -6
- data/lib/active_record/connection_adapters/mysql/schema_statements.rb +132 -16
- data/lib/active_record/connection_adapters/mysql/type_metadata.rb +6 -10
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +26 -10
- data/lib/active_record/connection_adapters/postgresql/column.rb +17 -31
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +26 -1
- data/lib/active_record/connection_adapters/postgresql/oid/array.rb +1 -2
- data/lib/active_record/connection_adapters/postgresql/oid/bit.rb +1 -4
- data/lib/active_record/connection_adapters/postgresql/oid/enum.rb +0 -1
- data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +1 -2
- data/lib/active_record/connection_adapters/postgresql/oid/legacy_point.rb +1 -2
- data/lib/active_record/connection_adapters/postgresql/oid/money.rb +2 -2
- data/lib/active_record/connection_adapters/postgresql/oid/oid.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/oid/point.rb +1 -2
- data/lib/active_record/connection_adapters/postgresql/oid/range.rb +1 -2
- data/lib/active_record/connection_adapters/postgresql/oid/specialized_string.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +9 -7
- data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +5 -3
- data/lib/active_record/connection_adapters/postgresql/quoting.rb +44 -7
- data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +14 -3
- data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +107 -91
- data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +0 -1
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +63 -75
- data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +24 -27
- data/lib/active_record/connection_adapters/postgresql/utils.rb +0 -1
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +168 -75
- data/lib/active_record/connection_adapters/schema_cache.rb +37 -14
- data/lib/active_record/connection_adapters/sql_type_metadata.rb +11 -8
- data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +119 -0
- data/lib/active_record/connection_adapters/sqlite3/quoting.rb +42 -7
- data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +43 -12
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +135 -146
- data/lib/active_record/connection_adapters/statement_pool.rb +0 -1
- data/lib/active_record/connection_handling.rb +139 -26
- data/lib/active_record/core.rb +103 -61
- data/lib/active_record/counter_cache.rb +8 -30
- data/lib/active_record/database_configurations.rb +233 -0
- data/lib/active_record/database_configurations/database_config.rb +37 -0
- data/lib/active_record/database_configurations/hash_config.rb +50 -0
- data/lib/active_record/database_configurations/url_config.rb +78 -0
- data/lib/active_record/dynamic_matchers.rb +3 -4
- data/lib/active_record/enum.rb +37 -7
- data/lib/active_record/errors.rb +15 -7
- data/lib/active_record/explain.rb +1 -2
- data/lib/active_record/fixture_set/model_metadata.rb +33 -0
- data/lib/active_record/fixture_set/render_context.rb +17 -0
- data/lib/active_record/fixture_set/table_row.rb +152 -0
- data/lib/active_record/fixture_set/table_rows.rb +46 -0
- data/lib/active_record/fixtures.rb +144 -474
- data/lib/active_record/gem_version.rb +3 -3
- data/lib/active_record/inheritance.rb +13 -6
- data/lib/active_record/insert_all.rb +179 -0
- data/lib/active_record/integration.rb +68 -16
- data/lib/active_record/internal_metadata.rb +11 -3
- data/lib/active_record/locking/optimistic.rb +5 -7
- data/lib/active_record/locking/pessimistic.rb +3 -3
- data/lib/active_record/log_subscriber.rb +8 -27
- data/lib/active_record/middleware/database_selector.rb +74 -0
- data/lib/active_record/middleware/database_selector/resolver.rb +87 -0
- data/lib/active_record/middleware/database_selector/resolver/session.rb +45 -0
- data/lib/active_record/migration.rb +104 -85
- data/lib/active_record/migration/command_recorder.rb +54 -22
- data/lib/active_record/migration/compatibility.rb +79 -52
- data/lib/active_record/migration/join_table.rb +0 -1
- data/lib/active_record/model_schema.rb +33 -11
- data/lib/active_record/nested_attributes.rb +2 -4
- data/lib/active_record/no_touching.rb +9 -2
- data/lib/active_record/null_relation.rb +0 -1
- data/lib/active_record/persistence.rb +232 -29
- data/lib/active_record/query_cache.rb +11 -4
- data/lib/active_record/querying.rb +33 -21
- data/lib/active_record/railtie.rb +80 -43
- data/lib/active_record/railties/collection_cache_association_loading.rb +34 -0
- data/lib/active_record/railties/controller_runtime.rb +30 -35
- data/lib/active_record/railties/databases.rake +199 -46
- data/lib/active_record/reflection.rb +40 -38
- data/lib/active_record/relation.rb +322 -80
- data/lib/active_record/relation/batches.rb +13 -11
- data/lib/active_record/relation/calculations.rb +54 -48
- data/lib/active_record/relation/delegation.rb +33 -49
- data/lib/active_record/relation/finder_methods.rb +23 -28
- data/lib/active_record/relation/from_clause.rb +4 -0
- data/lib/active_record/relation/merger.rb +11 -21
- data/lib/active_record/relation/predicate_builder.rb +5 -11
- data/lib/active_record/relation/predicate_builder/array_handler.rb +5 -4
- data/lib/active_record/relation/predicate_builder/association_query_value.rb +1 -4
- data/lib/active_record/relation/predicate_builder/base_handler.rb +1 -2
- data/lib/active_record/relation/predicate_builder/basic_object_handler.rb +1 -2
- data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +1 -4
- data/lib/active_record/relation/predicate_builder/range_handler.rb +3 -23
- data/lib/active_record/relation/query_attribute.rb +13 -8
- data/lib/active_record/relation/query_methods.rb +221 -70
- data/lib/active_record/relation/spawn_methods.rb +1 -2
- data/lib/active_record/relation/where_clause.rb +14 -11
- data/lib/active_record/relation/where_clause_factory.rb +1 -2
- data/lib/active_record/result.rb +30 -12
- data/lib/active_record/sanitization.rb +32 -40
- data/lib/active_record/schema.rb +2 -11
- data/lib/active_record/schema_dumper.rb +22 -7
- data/lib/active_record/schema_migration.rb +6 -2
- data/lib/active_record/scoping.rb +8 -9
- data/lib/active_record/scoping/default.rb +4 -6
- data/lib/active_record/scoping/named.rb +21 -17
- data/lib/active_record/statement_cache.rb +30 -3
- data/lib/active_record/store.rb +87 -8
- data/lib/active_record/suppressor.rb +2 -2
- data/lib/active_record/table_metadata.rb +23 -15
- data/lib/active_record/tasks/database_tasks.rb +194 -25
- data/lib/active_record/tasks/mysql_database_tasks.rb +5 -6
- data/lib/active_record/tasks/postgresql_database_tasks.rb +5 -8
- data/lib/active_record/tasks/sqlite_database_tasks.rb +2 -9
- data/lib/active_record/test_databases.rb +23 -0
- data/lib/active_record/test_fixtures.rb +225 -0
- data/lib/active_record/timestamp.rb +39 -26
- data/lib/active_record/touch_later.rb +5 -4
- data/lib/active_record/transactions.rb +64 -73
- data/lib/active_record/translation.rb +1 -1
- data/lib/active_record/type.rb +3 -5
- data/lib/active_record/type/adapter_specific_registry.rb +3 -13
- data/lib/active_record/type/hash_lookup_type_map.rb +0 -1
- data/lib/active_record/type/serialized.rb +0 -1
- 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_caster/connection.rb +15 -14
- data/lib/active_record/type_caster/map.rb +1 -4
- data/lib/active_record/validations.rb +3 -3
- data/lib/active_record/validations/associated.rb +1 -2
- data/lib/active_record/validations/uniqueness.rb +15 -27
- data/lib/arel.rb +62 -0
- data/lib/arel/alias_predication.rb +9 -0
- data/lib/arel/attributes.rb +22 -0
- data/lib/arel/attributes/attribute.rb +37 -0
- data/lib/arel/collectors/bind.rb +24 -0
- data/lib/arel/collectors/composite.rb +31 -0
- data/lib/arel/collectors/plain_string.rb +20 -0
- data/lib/arel/collectors/sql_string.rb +20 -0
- data/lib/arel/collectors/substitute_binds.rb +28 -0
- data/lib/arel/crud.rb +42 -0
- data/lib/arel/delete_manager.rb +18 -0
- data/lib/arel/errors.rb +9 -0
- data/lib/arel/expressions.rb +29 -0
- data/lib/arel/factory_methods.rb +49 -0
- data/lib/arel/insert_manager.rb +49 -0
- data/lib/arel/math.rb +45 -0
- data/lib/arel/nodes.rb +68 -0
- data/lib/arel/nodes/and.rb +32 -0
- data/lib/arel/nodes/ascending.rb +23 -0
- data/lib/arel/nodes/binary.rb +52 -0
- data/lib/arel/nodes/bind_param.rb +36 -0
- data/lib/arel/nodes/case.rb +55 -0
- data/lib/arel/nodes/casted.rb +50 -0
- data/lib/arel/nodes/comment.rb +29 -0
- data/lib/arel/nodes/count.rb +12 -0
- data/lib/arel/nodes/delete_statement.rb +45 -0
- data/lib/arel/nodes/descending.rb +23 -0
- data/lib/arel/nodes/equality.rb +18 -0
- data/lib/arel/nodes/extract.rb +24 -0
- data/lib/arel/nodes/false.rb +16 -0
- data/lib/arel/nodes/full_outer_join.rb +8 -0
- data/lib/arel/nodes/function.rb +44 -0
- data/lib/arel/nodes/grouping.rb +8 -0
- data/lib/arel/nodes/in.rb +8 -0
- data/lib/arel/nodes/infix_operation.rb +80 -0
- data/lib/arel/nodes/inner_join.rb +8 -0
- data/lib/arel/nodes/insert_statement.rb +37 -0
- data/lib/arel/nodes/join_source.rb +20 -0
- data/lib/arel/nodes/matches.rb +18 -0
- data/lib/arel/nodes/named_function.rb +23 -0
- data/lib/arel/nodes/node.rb +50 -0
- data/lib/arel/nodes/node_expression.rb +13 -0
- data/lib/arel/nodes/outer_join.rb +8 -0
- data/lib/arel/nodes/over.rb +15 -0
- data/lib/arel/nodes/regexp.rb +16 -0
- data/lib/arel/nodes/right_outer_join.rb +8 -0
- data/lib/arel/nodes/select_core.rb +67 -0
- data/lib/arel/nodes/select_statement.rb +41 -0
- data/lib/arel/nodes/sql_literal.rb +16 -0
- data/lib/arel/nodes/string_join.rb +11 -0
- data/lib/arel/nodes/table_alias.rb +27 -0
- data/lib/arel/nodes/terminal.rb +16 -0
- data/lib/arel/nodes/true.rb +16 -0
- data/lib/arel/nodes/unary.rb +45 -0
- data/lib/arel/nodes/unary_operation.rb +20 -0
- data/lib/arel/nodes/unqualified_column.rb +22 -0
- data/lib/arel/nodes/update_statement.rb +41 -0
- data/lib/arel/nodes/values_list.rb +9 -0
- data/lib/arel/nodes/window.rb +126 -0
- data/lib/arel/nodes/with.rb +11 -0
- data/lib/arel/order_predications.rb +13 -0
- data/lib/arel/predications.rb +256 -0
- data/lib/arel/select_manager.rb +271 -0
- data/lib/arel/table.rb +110 -0
- data/lib/arel/tree_manager.rb +72 -0
- data/lib/arel/update_manager.rb +34 -0
- data/lib/arel/visitors.rb +20 -0
- data/lib/arel/visitors/depth_first.rb +203 -0
- data/lib/arel/visitors/dot.rb +296 -0
- data/lib/arel/visitors/ibm_db.rb +34 -0
- data/lib/arel/visitors/informix.rb +62 -0
- data/lib/arel/visitors/mssql.rb +156 -0
- data/lib/arel/visitors/mysql.rb +83 -0
- data/lib/arel/visitors/oracle.rb +158 -0
- data/lib/arel/visitors/oracle12.rb +65 -0
- data/lib/arel/visitors/postgresql.rb +109 -0
- data/lib/arel/visitors/sqlite.rb +38 -0
- data/lib/arel/visitors/to_sql.rb +888 -0
- data/lib/arel/visitors/visitor.rb +45 -0
- data/lib/arel/visitors/where_sql.rb +22 -0
- data/lib/arel/window_predications.rb +9 -0
- data/lib/rails/generators/active_record/application_record/application_record_generator.rb +0 -1
- data/lib/rails/generators/active_record/migration.rb +14 -2
- data/lib/rails/generators/active_record/migration/migration_generator.rb +2 -5
- data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb.tt +1 -1
- data/lib/rails/generators/active_record/migration/templates/migration.rb.tt +4 -2
- data/lib/rails/generators/active_record/model/model_generator.rb +1 -1
- data/lib/rails/generators/active_record/model/templates/model.rb.tt +10 -1
- metadata +115 -29
- data/lib/active_record/collection_cache_key.rb +0 -53
@@ -2,11 +2,8 @@
|
|
2
2
|
|
3
3
|
module ActiveRecord
|
4
4
|
module Associations
|
5
|
-
#
|
6
|
-
#
|
7
|
-
# object, known as the <tt>@target</tt>. The kind of association any proxy is
|
8
|
-
# about is available in <tt>@reflection</tt>. That's an instance of the class
|
9
|
-
# ActiveRecord::Reflection::AssociationReflection.
|
5
|
+
# Collection proxies in Active Record are middlemen between an
|
6
|
+
# <tt>association</tt>, and its <tt>target</tt> result set.
|
10
7
|
#
|
11
8
|
# For example, given
|
12
9
|
#
|
@@ -16,21 +13,21 @@ module ActiveRecord
|
|
16
13
|
#
|
17
14
|
# blog = Blog.first
|
18
15
|
#
|
19
|
-
#
|
20
|
-
# <tt
|
21
|
-
#
|
16
|
+
# The collection proxy returned by <tt>blog.posts</tt> is built from a
|
17
|
+
# <tt>:has_many</tt> <tt>association</tt>, and delegates to a collection
|
18
|
+
# of posts as the <tt>target</tt>.
|
22
19
|
#
|
23
|
-
# This class delegates unknown methods to <tt
|
24
|
-
#
|
20
|
+
# This class delegates unknown methods to the <tt>association</tt>'s
|
21
|
+
# relation class via a delegate cache.
|
25
22
|
#
|
26
|
-
# The <tt
|
23
|
+
# The <tt>target</tt> result set is not loaded until needed. For example,
|
27
24
|
#
|
28
25
|
# blog.posts.count
|
29
26
|
#
|
30
27
|
# is computed directly through SQL and does not trigger by itself the
|
31
28
|
# instantiation of the actual post records.
|
32
29
|
class CollectionProxy < Relation
|
33
|
-
def initialize(klass, association) #:nodoc:
|
30
|
+
def initialize(klass, association, **) #:nodoc:
|
34
31
|
@association = association
|
35
32
|
super klass
|
36
33
|
|
@@ -1005,7 +1002,7 @@ module ActiveRecord
|
|
1005
1002
|
end
|
1006
1003
|
|
1007
1004
|
# Adds one or more +records+ to the collection by setting their foreign keys
|
1008
|
-
# to the association's primary key. Since
|
1005
|
+
# to the association's primary key. Since <tt><<</tt> flattens its argument list and
|
1009
1006
|
# inserts each record, +push+ and +concat+ behave identically. Returns +self+
|
1010
1007
|
# so several appends may be chained together.
|
1011
1008
|
#
|
@@ -1032,7 +1029,7 @@ module ActiveRecord
|
|
1032
1029
|
alias_method :append, :<<
|
1033
1030
|
alias_method :concat, :<<
|
1034
1031
|
|
1035
|
-
def prepend(*args)
|
1032
|
+
def prepend(*args) # :nodoc:
|
1036
1033
|
raise NoMethodError, "prepend on association is not defined. Please use <<, push or append"
|
1037
1034
|
end
|
1038
1035
|
|
@@ -1062,7 +1059,7 @@ module ActiveRecord
|
|
1062
1059
|
# person.pets.reload # fetches pets from the database
|
1063
1060
|
# # => [#<Pet id: 1, name: "Snoop", group: "dogs", person_id: 1>]
|
1064
1061
|
def reload
|
1065
|
-
proxy_association.reload
|
1062
|
+
proxy_association.reload(true)
|
1066
1063
|
reset_scope
|
1067
1064
|
end
|
1068
1065
|
|
@@ -1099,12 +1096,11 @@ module ActiveRecord
|
|
1099
1096
|
SpawnMethods,
|
1100
1097
|
].flat_map { |klass|
|
1101
1098
|
klass.public_instance_methods(false)
|
1102
|
-
} - self.public_instance_methods(false) - [:select] + [:scoping]
|
1099
|
+
} - self.public_instance_methods(false) - [:select] + [:scoping, :values]
|
1103
1100
|
|
1104
1101
|
delegate(*delegate_methods, to: :scope)
|
1105
1102
|
|
1106
1103
|
private
|
1107
|
-
|
1108
1104
|
def find_nth_with_limit(index, limit)
|
1109
1105
|
load_target if find_from_target?
|
1110
1106
|
super
|
@@ -36,16 +36,7 @@ module ActiveRecord
|
|
36
36
|
super
|
37
37
|
end
|
38
38
|
|
39
|
-
def empty?
|
40
|
-
if reflection.has_cached_counter?
|
41
|
-
size.zero?
|
42
|
-
else
|
43
|
-
super
|
44
|
-
end
|
45
|
-
end
|
46
|
-
|
47
39
|
private
|
48
|
-
|
49
40
|
# Returns the number of records in this collection.
|
50
41
|
#
|
51
42
|
# If the association has a counter cache it gets that value. Otherwise
|
@@ -69,7 +60,7 @@ module ActiveRecord
|
|
69
60
|
# If there's nothing in the database and @target has no new records
|
70
61
|
# we are certain the current target is an empty array. This is a
|
71
62
|
# documented side-effect of the method that may avoid an extra SELECT.
|
72
|
-
|
63
|
+
loaded! if count == 0
|
73
64
|
|
74
65
|
[association_scope.limit_value, count].compact.min
|
75
66
|
end
|
@@ -92,7 +83,7 @@ module ActiveRecord
|
|
92
83
|
if method == :delete_all
|
93
84
|
scope.delete_all
|
94
85
|
else
|
95
|
-
scope.update_all(
|
86
|
+
scope.update_all(nullified_owner_attributes)
|
96
87
|
end
|
97
88
|
end
|
98
89
|
|
@@ -21,20 +21,6 @@ module ActiveRecord
|
|
21
21
|
super
|
22
22
|
end
|
23
23
|
|
24
|
-
def concat_records(records)
|
25
|
-
ensure_not_nested
|
26
|
-
|
27
|
-
records = super(records, true)
|
28
|
-
|
29
|
-
if owner.new_record? && records
|
30
|
-
records.flatten.each do |record|
|
31
|
-
build_through_record(record)
|
32
|
-
end
|
33
|
-
end
|
34
|
-
|
35
|
-
records
|
36
|
-
end
|
37
|
-
|
38
24
|
def insert_record(record, validate = true, raise = false)
|
39
25
|
ensure_not_nested
|
40
26
|
|
@@ -48,6 +34,20 @@ module ActiveRecord
|
|
48
34
|
end
|
49
35
|
|
50
36
|
private
|
37
|
+
def concat_records(records)
|
38
|
+
ensure_not_nested
|
39
|
+
|
40
|
+
records = super(records, true)
|
41
|
+
|
42
|
+
if owner.new_record? && records
|
43
|
+
records.flatten.each do |record|
|
44
|
+
build_through_record(record)
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
records
|
49
|
+
end
|
50
|
+
|
51
51
|
# The through record (built with build_record) is temporarily cached
|
52
52
|
# so that it may be reused if insert_record is subsequently called.
|
53
53
|
#
|
@@ -23,35 +23,6 @@ module ActiveRecord
|
|
23
23
|
end
|
24
24
|
end
|
25
25
|
|
26
|
-
def replace(record, save = true)
|
27
|
-
raise_on_type_mismatch!(record) if record
|
28
|
-
load_target
|
29
|
-
|
30
|
-
return target unless target || record
|
31
|
-
|
32
|
-
assigning_another_record = target != record
|
33
|
-
if assigning_another_record || record.has_changes_to_save?
|
34
|
-
save &&= owner.persisted?
|
35
|
-
|
36
|
-
transaction_if(save) do
|
37
|
-
remove_target!(options[:dependent]) if target && !target.destroyed? && assigning_another_record
|
38
|
-
|
39
|
-
if record
|
40
|
-
set_owner_attributes(record)
|
41
|
-
set_inverse_instance(record)
|
42
|
-
|
43
|
-
if save && !record.save
|
44
|
-
nullify_owner_attributes(record)
|
45
|
-
set_owner_attributes(target) if target
|
46
|
-
raise RecordNotSaved, "Failed to save the new associated #{reflection.name}."
|
47
|
-
end
|
48
|
-
end
|
49
|
-
end
|
50
|
-
end
|
51
|
-
|
52
|
-
self.target = record
|
53
|
-
end
|
54
|
-
|
55
26
|
def delete(method = options[:dependent])
|
56
27
|
if load_target
|
57
28
|
case method
|
@@ -62,12 +33,39 @@ module ActiveRecord
|
|
62
33
|
target.destroy
|
63
34
|
throw(:abort) unless target.destroyed?
|
64
35
|
when :nullify
|
65
|
-
target.update_columns(
|
36
|
+
target.update_columns(nullified_owner_attributes) if target.persisted?
|
66
37
|
end
|
67
38
|
end
|
68
39
|
end
|
69
40
|
|
70
41
|
private
|
42
|
+
def replace(record, save = true)
|
43
|
+
raise_on_type_mismatch!(record) if record
|
44
|
+
|
45
|
+
return target unless load_target || record
|
46
|
+
|
47
|
+
assigning_another_record = target != record
|
48
|
+
if assigning_another_record || record.has_changes_to_save?
|
49
|
+
save &&= owner.persisted?
|
50
|
+
|
51
|
+
transaction_if(save) do
|
52
|
+
remove_target!(options[:dependent]) if target && !target.destroyed? && assigning_another_record
|
53
|
+
|
54
|
+
if record
|
55
|
+
set_owner_attributes(record)
|
56
|
+
set_inverse_instance(record)
|
57
|
+
|
58
|
+
if save && !record.save
|
59
|
+
nullify_owner_attributes(record)
|
60
|
+
set_owner_attributes(target) if target
|
61
|
+
raise RecordNotSaved, "Failed to save the new associated #{reflection.name}."
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
self.target = record
|
68
|
+
end
|
71
69
|
|
72
70
|
# The reason that the save param for replace is false, if for create (not just build),
|
73
71
|
# is because the setting of the foreign keys is actually handled by the scoping when
|
@@ -6,12 +6,12 @@ module ActiveRecord
|
|
6
6
|
class HasOneThroughAssociation < HasOneAssociation #:nodoc:
|
7
7
|
include ThroughAssociation
|
8
8
|
|
9
|
-
def replace(record, save = true)
|
10
|
-
create_through_record(record, save)
|
11
|
-
self.target = record
|
12
|
-
end
|
13
|
-
|
14
9
|
private
|
10
|
+
def replace(record, save = true)
|
11
|
+
create_through_record(record, save)
|
12
|
+
self.target = record
|
13
|
+
end
|
14
|
+
|
15
15
|
def create_through_record(record, save)
|
16
16
|
ensure_not_nested
|
17
17
|
|
@@ -14,10 +14,8 @@ module ActiveRecord
|
|
14
14
|
i[column.name] = column.alias
|
15
15
|
}
|
16
16
|
}
|
17
|
-
@
|
18
|
-
h[table.node] = table.columns
|
19
|
-
[column.name, column.alias]
|
20
|
-
}
|
17
|
+
@columns_cache = tables.each_with_object({}) { |table, h|
|
18
|
+
h[table.node] = table.columns
|
21
19
|
}
|
22
20
|
end
|
23
21
|
|
@@ -25,9 +23,8 @@ module ActiveRecord
|
|
25
23
|
@tables.flat_map(&:column_aliases)
|
26
24
|
end
|
27
25
|
|
28
|
-
# An array of [column_name, alias] pairs for the table
|
29
26
|
def column_aliases(node)
|
30
|
-
@
|
27
|
+
@columns_cache[node]
|
31
28
|
end
|
32
29
|
|
33
30
|
def column_alias(node, column)
|
@@ -67,16 +64,21 @@ module ActiveRecord
|
|
67
64
|
end
|
68
65
|
end
|
69
66
|
|
70
|
-
def initialize(base, table, associations)
|
67
|
+
def initialize(base, table, associations, join_type)
|
71
68
|
tree = self.class.make_tree associations
|
72
69
|
@join_root = JoinBase.new(base, table, build(tree, base))
|
70
|
+
@join_type = join_type
|
71
|
+
end
|
72
|
+
|
73
|
+
def base_klass
|
74
|
+
join_root.base_klass
|
73
75
|
end
|
74
76
|
|
75
77
|
def reflections
|
76
78
|
join_root.drop(1).map!(&:reflection)
|
77
79
|
end
|
78
80
|
|
79
|
-
def join_constraints(joins_to_add,
|
81
|
+
def join_constraints(joins_to_add, alias_tracker)
|
80
82
|
@alias_tracker = alias_tracker
|
81
83
|
|
82
84
|
construct_tables!(join_root)
|
@@ -85,9 +87,9 @@ module ActiveRecord
|
|
85
87
|
joins.concat joins_to_add.flat_map { |oj|
|
86
88
|
construct_tables!(oj.join_root)
|
87
89
|
if join_root.match? oj.join_root
|
88
|
-
walk join_root, oj.
|
90
|
+
walk(join_root, oj.join_root, oj.join_type)
|
89
91
|
else
|
90
|
-
make_join_constraints(oj.join_root, join_type)
|
92
|
+
make_join_constraints(oj.join_root, oj.join_type)
|
91
93
|
end
|
92
94
|
}
|
93
95
|
end
|
@@ -103,7 +105,9 @@ module ActiveRecord
|
|
103
105
|
|
104
106
|
model_cache = Hash.new { |h, klass| h[klass] = {} }
|
105
107
|
parents = model_cache[join_root]
|
108
|
+
|
106
109
|
column_aliases = aliases.column_aliases join_root
|
110
|
+
column_aliases += explicit_selections(column_aliases, result_set)
|
107
111
|
|
108
112
|
message_bus = ActiveSupport::Notifications.instrumenter
|
109
113
|
|
@@ -116,7 +120,7 @@ module ActiveRecord
|
|
116
120
|
result_set.each { |row_hash|
|
117
121
|
parent_key = primary_key ? row_hash[primary_key] : row_hash
|
118
122
|
parent = parents[parent_key] ||= join_root.instantiate(row_hash, column_aliases, &block)
|
119
|
-
construct(parent, join_root, row_hash,
|
123
|
+
construct(parent, join_root, row_hash, seen, model_cache)
|
120
124
|
}
|
121
125
|
end
|
122
126
|
|
@@ -128,9 +132,18 @@ module ActiveRecord
|
|
128
132
|
end
|
129
133
|
|
130
134
|
protected
|
131
|
-
attr_reader :
|
135
|
+
attr_reader :join_root, :join_type
|
132
136
|
|
133
137
|
private
|
138
|
+
attr_reader :alias_tracker
|
139
|
+
|
140
|
+
def explicit_selections(root_column_aliases, result_set)
|
141
|
+
root_names = root_column_aliases.map(&:name).to_set
|
142
|
+
result_set.columns
|
143
|
+
.reject { |n| root_names.include?(n) || n =~ /\At\d+_r\d+\z/ }
|
144
|
+
.map { |n| Aliases::Column.new(n, n) }
|
145
|
+
end
|
146
|
+
|
134
147
|
def aliases
|
135
148
|
@aliases ||= Aliases.new join_root.each_with_index.map { |join_part, i|
|
136
149
|
columns = join_part.column_names.each_with_index.map { |column_name, j|
|
@@ -152,7 +165,7 @@ module ActiveRecord
|
|
152
165
|
end
|
153
166
|
end
|
154
167
|
|
155
|
-
def make_constraints(parent, child, join_type
|
168
|
+
def make_constraints(parent, child, join_type)
|
156
169
|
foreign_table = parent.table
|
157
170
|
foreign_klass = parent.base_klass
|
158
171
|
joins = child.join_constraints(foreign_table, foreign_klass, join_type, alias_tracker)
|
@@ -170,17 +183,17 @@ module ActiveRecord
|
|
170
183
|
end
|
171
184
|
|
172
185
|
def table_alias_for(reflection, parent, join)
|
173
|
-
name =
|
186
|
+
name = reflection.alias_candidate(parent.table_name)
|
174
187
|
join ? "#{name}_join" : name
|
175
188
|
end
|
176
189
|
|
177
|
-
def walk(left, right)
|
190
|
+
def walk(left, right, join_type)
|
178
191
|
intersection, missing = right.children.map { |node1|
|
179
192
|
[left.children.find { |node2| node1.match? node2 }, node1]
|
180
193
|
}.partition(&:first)
|
181
194
|
|
182
|
-
joins = intersection.flat_map { |l, r| r.table = l.table; walk(l, r) }
|
183
|
-
joins.concat missing.flat_map { |_, n| make_constraints(left, n) }
|
195
|
+
joins = intersection.flat_map { |l, r| r.table = l.table; walk(l, r, join_type) }
|
196
|
+
joins.concat missing.flat_map { |_, n| make_constraints(left, n, join_type) }
|
184
197
|
end
|
185
198
|
|
186
199
|
def find_reflection(klass, name)
|
@@ -202,7 +215,7 @@ module ActiveRecord
|
|
202
215
|
end
|
203
216
|
end
|
204
217
|
|
205
|
-
def construct(ar_parent, parent, row,
|
218
|
+
def construct(ar_parent, parent, row, seen, model_cache)
|
206
219
|
return if ar_parent.nil?
|
207
220
|
|
208
221
|
parent.children.each do |node|
|
@@ -211,7 +224,7 @@ module ActiveRecord
|
|
211
224
|
other.loaded!
|
212
225
|
elsif ar_parent.association_cached?(node.reflection.name)
|
213
226
|
model = ar_parent.association(node.reflection.name).target
|
214
|
-
construct(model, node, row,
|
227
|
+
construct(model, node, row, seen, model_cache)
|
215
228
|
next
|
216
229
|
end
|
217
230
|
|
@@ -226,22 +239,17 @@ module ActiveRecord
|
|
226
239
|
model = seen[ar_parent.object_id][node][id]
|
227
240
|
|
228
241
|
if model
|
229
|
-
construct(model, node, row,
|
242
|
+
construct(model, node, row, seen, model_cache)
|
230
243
|
else
|
231
|
-
model = construct_model(ar_parent, node, row, model_cache, id
|
232
|
-
|
233
|
-
if node.reflection.scope &&
|
234
|
-
node.reflection.scope_for(node.base_klass.unscoped).readonly_value
|
235
|
-
model.readonly!
|
236
|
-
end
|
244
|
+
model = construct_model(ar_parent, node, row, model_cache, id)
|
237
245
|
|
238
246
|
seen[ar_parent.object_id][node][id] = model
|
239
|
-
construct(model, node, row,
|
247
|
+
construct(model, node, row, seen, model_cache)
|
240
248
|
end
|
241
249
|
end
|
242
250
|
end
|
243
251
|
|
244
|
-
def construct_model(record, node, row, model_cache, id
|
252
|
+
def construct_model(record, node, row, model_cache, id)
|
245
253
|
other = record.association(node.reflection.name)
|
246
254
|
|
247
255
|
model = model_cache[node][id] ||=
|
@@ -255,6 +263,7 @@ module ActiveRecord
|
|
255
263
|
other.target = model
|
256
264
|
end
|
257
265
|
|
266
|
+
model.readonly! if node.readonly?
|
258
267
|
model
|
259
268
|
end
|
260
269
|
end
|
@@ -1,6 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require "active_record/associations/join_dependency/join_part"
|
4
|
+
require "active_support/core_ext/array/extract"
|
4
5
|
|
5
6
|
module ActiveRecord
|
6
7
|
module Associations
|
@@ -35,10 +36,9 @@ module ActiveRecord
|
|
35
36
|
arel = join_scope.arel(alias_tracker.aliases)
|
36
37
|
nodes = arel.constraints.first
|
37
38
|
|
38
|
-
others
|
39
|
-
!
|
39
|
+
others = nodes.children.extract! do |node|
|
40
|
+
!Arel.fetch_attribute(node) { |attr| attr.relation.name == table.name }
|
40
41
|
end
|
41
|
-
nodes = table.create_and(children)
|
42
42
|
|
43
43
|
joins << table.create_join(table, table.create_on(nodes), join_type)
|
44
44
|
|
@@ -59,14 +59,13 @@ module ActiveRecord
|
|
59
59
|
@table = tables.first
|
60
60
|
end
|
61
61
|
|
62
|
-
|
63
|
-
|
64
|
-
case value
|
65
|
-
when Arel::Nodes::Between, Arel::Nodes::In, Arel::Nodes::NotIn, Arel::Nodes::Equality, Arel::Nodes::NotEqual, Arel::Nodes::LessThan, Arel::Nodes::LessThanOrEqual, Arel::Nodes::GreaterThan, Arel::Nodes::GreaterThanOrEqual
|
66
|
-
yield value.left.is_a?(Arel::Attributes::Attribute) ? value.left : value.right
|
67
|
-
end
|
68
|
-
end
|
62
|
+
def readonly?
|
63
|
+
return @readonly if defined?(@readonly)
|
69
64
|
|
65
|
+
@readonly = reflection.scope && reflection.scope_for(base_klass.unscoped).readonly_value
|
66
|
+
end
|
67
|
+
|
68
|
+
private
|
70
69
|
def append_constraints(join, constraints)
|
71
70
|
if join.is_a?(Arel::Nodes::StringJoin)
|
72
71
|
join_string = table.create_and(constraints.unshift(join.left))
|