activerecord 5.1.0 → 5.2.3
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 +5 -5
- data/CHANGELOG.md +596 -450
- data/MIT-LICENSE +1 -1
- data/README.rdoc +5 -5
- data/examples/performance.rb +2 -0
- data/examples/simple.rb +2 -0
- data/lib/active_record.rb +11 -4
- data/lib/active_record/aggregations.rb +6 -5
- data/lib/active_record/association_relation.rb +7 -5
- data/lib/active_record/associations.rb +77 -85
- data/lib/active_record/associations/alias_tracker.rb +23 -32
- data/lib/active_record/associations/association.rb +49 -35
- data/lib/active_record/associations/association_scope.rb +55 -55
- data/lib/active_record/associations/belongs_to_association.rb +30 -11
- data/lib/active_record/associations/belongs_to_polymorphic_association.rb +8 -8
- data/lib/active_record/associations/builder/association.rb +4 -7
- data/lib/active_record/associations/builder/belongs_to.rb +21 -8
- data/lib/active_record/associations/builder/collection_association.rb +1 -1
- data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +3 -1
- data/lib/active_record/associations/builder/has_many.rb +2 -0
- data/lib/active_record/associations/builder/has_one.rb +2 -0
- data/lib/active_record/associations/builder/singular_association.rb +2 -0
- data/lib/active_record/associations/collection_association.rb +66 -53
- data/lib/active_record/associations/collection_proxy.rb +30 -73
- data/lib/active_record/associations/foreign_association.rb +2 -0
- data/lib/active_record/associations/has_many_association.rb +13 -2
- data/lib/active_record/associations/has_many_through_association.rb +37 -19
- data/lib/active_record/associations/has_one_association.rb +14 -1
- data/lib/active_record/associations/has_one_through_association.rb +13 -8
- data/lib/active_record/associations/join_dependency.rb +52 -96
- data/lib/active_record/associations/join_dependency/join_association.rb +22 -75
- data/lib/active_record/associations/join_dependency/join_base.rb +9 -8
- data/lib/active_record/associations/join_dependency/join_part.rb +9 -9
- data/lib/active_record/associations/preloader.rb +17 -37
- data/lib/active_record/associations/preloader/association.rb +53 -92
- data/lib/active_record/associations/preloader/through_association.rb +72 -73
- data/lib/active_record/associations/singular_association.rb +14 -16
- data/lib/active_record/associations/through_association.rb +27 -12
- data/lib/active_record/attribute_assignment.rb +2 -5
- data/lib/active_record/attribute_decorators.rb +3 -2
- data/lib/active_record/attribute_methods.rb +65 -24
- data/lib/active_record/attribute_methods/before_type_cast.rb +2 -0
- data/lib/active_record/attribute_methods/dirty.rb +33 -216
- data/lib/active_record/attribute_methods/primary_key.rb +10 -13
- data/lib/active_record/attribute_methods/query.rb +2 -0
- data/lib/active_record/attribute_methods/read.rb +9 -3
- data/lib/active_record/attribute_methods/serialization.rb +23 -0
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +6 -8
- data/lib/active_record/attribute_methods/write.rb +22 -19
- data/lib/active_record/attributes.rb +7 -6
- data/lib/active_record/autosave_association.rb +15 -13
- data/lib/active_record/base.rb +2 -0
- data/lib/active_record/callbacks.rb +12 -6
- data/lib/active_record/coders/json.rb +2 -0
- data/lib/active_record/coders/yaml_column.rb +2 -0
- data/lib/active_record/collection_cache_key.rb +15 -11
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +120 -39
- data/lib/active_record/connection_adapters/abstract/database_limits.rb +7 -0
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +192 -37
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +13 -2
- data/lib/active_record/connection_adapters/abstract/quoting.rb +15 -25
- data/lib/active_record/connection_adapters/abstract/savepoints.rb +2 -0
- data/lib/active_record/connection_adapters/abstract/schema_creation.rb +15 -6
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +65 -7
- data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +31 -53
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +158 -87
- data/lib/active_record/connection_adapters/abstract/transaction.rb +66 -21
- data/lib/active_record/connection_adapters/abstract_adapter.rb +86 -98
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +126 -189
- data/lib/active_record/connection_adapters/column.rb +4 -2
- data/lib/active_record/connection_adapters/connection_specification.rb +17 -3
- data/lib/active_record/connection_adapters/determine_if_preparable_visitor.rb +13 -2
- data/lib/active_record/connection_adapters/mysql/column.rb +2 -0
- data/lib/active_record/connection_adapters/mysql/database_statements.rb +45 -15
- data/lib/active_record/connection_adapters/mysql/explain_pretty_printer.rb +2 -0
- data/lib/active_record/connection_adapters/mysql/quoting.rb +9 -10
- data/lib/active_record/connection_adapters/mysql/schema_creation.rb +5 -3
- data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +7 -10
- data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +30 -23
- data/lib/active_record/connection_adapters/mysql/schema_statements.rb +106 -1
- data/lib/active_record/connection_adapters/mysql/type_metadata.rb +2 -0
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +8 -2
- data/lib/active_record/connection_adapters/postgresql/column.rb +30 -1
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +6 -32
- data/lib/active_record/connection_adapters/postgresql/explain_pretty_printer.rb +2 -0
- data/lib/active_record/connection_adapters/postgresql/oid.rb +3 -1
- data/lib/active_record/connection_adapters/postgresql/oid/array.rb +13 -1
- data/lib/active_record/connection_adapters/postgresql/oid/bit.rb +2 -0
- data/lib/active_record/connection_adapters/postgresql/oid/bit_varying.rb +2 -0
- data/lib/active_record/connection_adapters/postgresql/oid/bytea.rb +2 -0
- data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +2 -0
- data/lib/active_record/connection_adapters/postgresql/oid/date.rb +23 -0
- data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +2 -0
- data/lib/active_record/connection_adapters/postgresql/oid/decimal.rb +3 -1
- data/lib/active_record/connection_adapters/postgresql/oid/enum.rb +2 -0
- data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +2 -0
- data/lib/active_record/connection_adapters/postgresql/oid/inet.rb +2 -0
- data/lib/active_record/connection_adapters/postgresql/oid/jsonb.rb +3 -11
- data/lib/active_record/connection_adapters/postgresql/oid/legacy_point.rb +2 -0
- data/lib/active_record/connection_adapters/postgresql/oid/money.rb +3 -1
- data/lib/active_record/connection_adapters/postgresql/oid/oid.rb +2 -0
- data/lib/active_record/connection_adapters/postgresql/oid/point.rb +2 -0
- data/lib/active_record/connection_adapters/postgresql/oid/range.rb +8 -2
- data/lib/active_record/connection_adapters/postgresql/oid/specialized_string.rb +2 -0
- data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +4 -2
- data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +3 -1
- data/lib/active_record/connection_adapters/postgresql/oid/vector.rb +2 -0
- data/lib/active_record/connection_adapters/postgresql/oid/xml.rb +2 -0
- data/lib/active_record/connection_adapters/postgresql/quoting.rb +22 -1
- data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +19 -25
- data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +50 -0
- data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +24 -11
- data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +20 -13
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +258 -129
- data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +2 -0
- data/lib/active_record/connection_adapters/postgresql/utils.rb +3 -1
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +75 -87
- data/lib/active_record/connection_adapters/schema_cache.rb +4 -2
- data/lib/active_record/connection_adapters/sql_type_metadata.rb +2 -0
- data/lib/active_record/connection_adapters/sqlite3/explain_pretty_printer.rb +2 -0
- data/lib/active_record/connection_adapters/sqlite3/quoting.rb +24 -1
- data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +2 -0
- data/lib/active_record/connection_adapters/sqlite3/schema_definitions.rb +6 -15
- data/lib/active_record/connection_adapters/sqlite3/schema_dumper.rb +3 -2
- data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +75 -1
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +90 -96
- data/lib/active_record/connection_adapters/statement_pool.rb +2 -0
- data/lib/active_record/connection_handling.rb +4 -2
- data/lib/active_record/core.rb +41 -61
- data/lib/active_record/counter_cache.rb +20 -15
- data/lib/active_record/define_callbacks.rb +5 -3
- data/lib/active_record/dynamic_matchers.rb +9 -9
- data/lib/active_record/enum.rb +18 -13
- data/lib/active_record/errors.rb +60 -15
- data/lib/active_record/explain.rb +3 -1
- data/lib/active_record/explain_registry.rb +2 -0
- data/lib/active_record/explain_subscriber.rb +2 -0
- data/lib/active_record/fixture_set/file.rb +2 -0
- data/lib/active_record/fixtures.rb +67 -60
- data/lib/active_record/gem_version.rb +4 -2
- data/lib/active_record/inheritance.rb +49 -19
- data/lib/active_record/integration.rb +58 -19
- data/lib/active_record/internal_metadata.rb +2 -0
- data/lib/active_record/legacy_yaml_adapter.rb +3 -1
- data/lib/active_record/locking/optimistic.rb +30 -42
- data/lib/active_record/locking/pessimistic.rb +10 -7
- data/lib/active_record/log_subscriber.rb +46 -4
- data/lib/active_record/migration.rb +189 -139
- data/lib/active_record/migration/command_recorder.rb +11 -9
- data/lib/active_record/migration/compatibility.rb +81 -29
- data/lib/active_record/migration/join_table.rb +2 -0
- data/lib/active_record/model_schema.rb +74 -58
- data/lib/active_record/nested_attributes.rb +18 -6
- data/lib/active_record/no_touching.rb +3 -1
- data/lib/active_record/null_relation.rb +2 -0
- data/lib/active_record/persistence.rb +199 -54
- data/lib/active_record/query_cache.rb +8 -10
- data/lib/active_record/querying.rb +5 -3
- data/lib/active_record/railtie.rb +62 -6
- data/lib/active_record/railties/console_sandbox.rb +2 -0
- data/lib/active_record/railties/controller_runtime.rb +2 -0
- data/lib/active_record/railties/databases.rake +48 -38
- data/lib/active_record/readonly_attributes.rb +3 -2
- data/lib/active_record/reflection.rb +137 -207
- data/lib/active_record/relation.rb +132 -207
- data/lib/active_record/relation/batches.rb +32 -17
- data/lib/active_record/relation/batches/batch_enumerator.rb +2 -0
- data/lib/active_record/relation/calculations.rb +66 -25
- data/lib/active_record/relation/delegation.rb +45 -29
- data/lib/active_record/relation/finder_methods.rb +76 -85
- data/lib/active_record/relation/from_clause.rb +2 -8
- data/lib/active_record/relation/merger.rb +53 -23
- data/lib/active_record/relation/predicate_builder.rb +60 -79
- data/lib/active_record/relation/predicate_builder/array_handler.rb +10 -7
- data/lib/active_record/relation/predicate_builder/association_query_value.rb +46 -0
- data/lib/active_record/relation/predicate_builder/base_handler.rb +2 -2
- data/lib/active_record/relation/predicate_builder/basic_object_handler.rb +12 -1
- data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +56 -0
- data/lib/active_record/relation/predicate_builder/range_handler.rb +26 -9
- data/lib/active_record/relation/predicate_builder/relation_handler.rb +6 -0
- data/lib/active_record/relation/query_attribute.rb +28 -2
- data/lib/active_record/relation/query_methods.rb +135 -103
- data/lib/active_record/relation/record_fetch_warning.rb +2 -0
- data/lib/active_record/relation/spawn_methods.rb +4 -2
- data/lib/active_record/relation/where_clause.rb +65 -67
- data/lib/active_record/relation/where_clause_factory.rb +5 -48
- data/lib/active_record/result.rb +2 -0
- data/lib/active_record/runtime_registry.rb +2 -0
- data/lib/active_record/sanitization.rb +129 -121
- data/lib/active_record/schema.rb +4 -2
- data/lib/active_record/schema_dumper.rb +36 -26
- data/lib/active_record/schema_migration.rb +2 -0
- data/lib/active_record/scoping.rb +12 -10
- data/lib/active_record/scoping/default.rb +10 -7
- data/lib/active_record/scoping/named.rb +40 -12
- data/lib/active_record/secure_token.rb +2 -0
- data/lib/active_record/serialization.rb +2 -0
- data/lib/active_record/statement_cache.rb +22 -12
- data/lib/active_record/store.rb +3 -1
- data/lib/active_record/suppressor.rb +2 -0
- data/lib/active_record/table_metadata.rb +12 -3
- data/lib/active_record/tasks/database_tasks.rb +38 -26
- data/lib/active_record/tasks/mysql_database_tasks.rb +11 -50
- data/lib/active_record/tasks/postgresql_database_tasks.rb +11 -3
- data/lib/active_record/tasks/sqlite_database_tasks.rb +25 -3
- data/lib/active_record/timestamp.rb +13 -6
- data/lib/active_record/touch_later.rb +2 -0
- data/lib/active_record/transactions.rb +32 -27
- data/lib/active_record/translation.rb +2 -0
- data/lib/active_record/type.rb +4 -1
- data/lib/active_record/type/adapter_specific_registry.rb +2 -0
- data/lib/active_record/type/date.rb +2 -0
- data/lib/active_record/type/date_time.rb +2 -0
- data/lib/active_record/type/decimal_without_scale.rb +2 -0
- data/lib/active_record/type/hash_lookup_type_map.rb +2 -0
- data/lib/active_record/type/internal/timezone.rb +2 -0
- data/lib/active_record/type/json.rb +30 -0
- data/lib/active_record/type/serialized.rb +6 -0
- data/lib/active_record/type/text.rb +2 -0
- data/lib/active_record/type/time.rb +2 -0
- data/lib/active_record/type/type_map.rb +2 -0
- data/lib/active_record/type/unsigned_integer.rb +2 -0
- data/lib/active_record/type_caster.rb +2 -0
- data/lib/active_record/type_caster/connection.rb +2 -0
- data/lib/active_record/type_caster/map.rb +3 -1
- data/lib/active_record/validations.rb +2 -0
- data/lib/active_record/validations/absence.rb +2 -0
- data/lib/active_record/validations/associated.rb +2 -0
- data/lib/active_record/validations/length.rb +2 -0
- data/lib/active_record/validations/presence.rb +2 -0
- data/lib/active_record/validations/uniqueness.rb +36 -6
- data/lib/active_record/version.rb +2 -0
- data/lib/rails/generators/active_record.rb +3 -1
- data/lib/rails/generators/active_record/application_record/application_record_generator.rb +27 -0
- data/lib/rails/generators/active_record/{model/templates/application_record.rb → application_record/templates/application_record.rb.tt} +0 -0
- data/lib/rails/generators/active_record/migration.rb +2 -0
- data/lib/rails/generators/active_record/migration/migration_generator.rb +3 -1
- data/lib/rails/generators/active_record/migration/templates/{create_table_migration.rb → create_table_migration.rb.tt} +0 -0
- data/lib/rails/generators/active_record/migration/templates/{migration.rb → migration.rb.tt} +0 -0
- data/lib/rails/generators/active_record/model/model_generator.rb +2 -23
- data/lib/rails/generators/active_record/model/templates/{model.rb → model.rb.tt} +0 -0
- data/lib/rails/generators/active_record/model/templates/{module.rb → module.rb.tt} +0 -0
- metadata +24 -36
- data/lib/active_record/associations/preloader/belongs_to.rb +0 -15
- data/lib/active_record/associations/preloader/collection_association.rb +0 -17
- data/lib/active_record/associations/preloader/has_many.rb +0 -15
- data/lib/active_record/associations/preloader/has_many_through.rb +0 -19
- data/lib/active_record/associations/preloader/has_one.rb +0 -15
- data/lib/active_record/associations/preloader/has_one_through.rb +0 -9
- data/lib/active_record/associations/preloader/singular_association.rb +0 -18
- data/lib/active_record/attribute.rb +0 -240
- data/lib/active_record/attribute/user_provided_default.rb +0 -30
- data/lib/active_record/attribute_mutation_tracker.rb +0 -113
- data/lib/active_record/attribute_set.rb +0 -113
- data/lib/active_record/attribute_set/builder.rb +0 -124
- data/lib/active_record/attribute_set/yaml_encoder.rb +0 -41
- data/lib/active_record/connection_adapters/postgresql/oid/json.rb +0 -10
- data/lib/active_record/railties/jdbcmysql_error.rb +0 -16
- data/lib/active_record/relation/predicate_builder/association_query_handler.rb +0 -88
- data/lib/active_record/relation/predicate_builder/polymorphic_array_handler.rb +0 -59
- data/lib/active_record/type/internal/abstract_json.rb +0 -33
@@ -1,51 +1,41 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require "active_support/core_ext/string/conversions"
|
2
4
|
|
3
5
|
module ActiveRecord
|
4
6
|
module Associations
|
5
7
|
# Keeps track of table aliases for ActiveRecord::Associations::JoinDependency
|
6
8
|
class AliasTracker # :nodoc:
|
7
|
-
|
8
|
-
|
9
|
-
def self.create(connection, initial_table, type_caster)
|
10
|
-
aliases = Hash.new(0)
|
11
|
-
aliases[initial_table] = 1
|
12
|
-
new connection, aliases, type_caster
|
13
|
-
end
|
14
|
-
|
15
|
-
def self.create_with_joins(connection, initial_table, joins, type_caster)
|
9
|
+
def self.create(connection, initial_table, joins)
|
16
10
|
if joins.empty?
|
17
|
-
|
11
|
+
aliases = Hash.new(0)
|
18
12
|
else
|
19
13
|
aliases = Hash.new { |h, k|
|
20
14
|
h[k] = initial_count_for(connection, k, joins)
|
21
15
|
}
|
22
|
-
aliases[initial_table] = 1
|
23
|
-
new connection, aliases, type_caster
|
24
16
|
end
|
17
|
+
aliases[initial_table] = 1
|
18
|
+
new(connection, aliases)
|
25
19
|
end
|
26
20
|
|
27
21
|
def self.initial_count_for(connection, name, table_joins)
|
28
|
-
|
29
|
-
quoted_name = connection.quote_table_name(name).downcase
|
22
|
+
quoted_name = nil
|
30
23
|
|
31
24
|
counts = table_joins.map do |join|
|
32
25
|
if join.is_a?(Arel::Nodes::StringJoin)
|
26
|
+
# quoted_name should be case ignored as some database adapters (Oracle) return quoted name in uppercase
|
27
|
+
quoted_name ||= connection.quote_table_name(name)
|
28
|
+
|
33
29
|
# Table names + table aliases
|
34
|
-
join.left.
|
35
|
-
/
|
30
|
+
join.left.scan(
|
31
|
+
/JOIN(?:\s+\w+)?\s+(?:\S+\s+)?(?:#{quoted_name}|#{name})\sON/i
|
36
32
|
).size
|
37
|
-
elsif join.
|
38
|
-
join.left.
|
33
|
+
elsif join.is_a?(Arel::Nodes::Join)
|
34
|
+
join.left.name == name ? 1 : 0
|
35
|
+
elsif join.is_a?(Hash)
|
36
|
+
join[name]
|
39
37
|
else
|
40
|
-
|
41
|
-
#
|
42
|
-
# activerecord/test/cases/associations/cascaded_eager_loading_test.rb:37
|
43
|
-
# with :posts
|
44
|
-
#
|
45
|
-
# activerecord/test/cases/associations/eager_test.rb:1133
|
46
|
-
# with :comments
|
47
|
-
#
|
48
|
-
0
|
38
|
+
raise ArgumentError, "joins list should be initialized by list of Arel::Nodes::Join"
|
49
39
|
end
|
50
40
|
end
|
51
41
|
|
@@ -53,17 +43,16 @@ module ActiveRecord
|
|
53
43
|
end
|
54
44
|
|
55
45
|
# table_joins is an array of arel joins which might conflict with the aliases we assign here
|
56
|
-
def initialize(connection, aliases
|
46
|
+
def initialize(connection, aliases)
|
57
47
|
@aliases = aliases
|
58
48
|
@connection = connection
|
59
|
-
@type_caster = type_caster
|
60
49
|
end
|
61
50
|
|
62
|
-
def aliased_table_for(table_name, aliased_name)
|
51
|
+
def aliased_table_for(table_name, aliased_name, type_caster)
|
63
52
|
if aliases[table_name].zero?
|
64
53
|
# If it's zero, we can have our table_name
|
65
54
|
aliases[table_name] = 1
|
66
|
-
Arel::Table.new(table_name, type_caster:
|
55
|
+
Arel::Table.new(table_name, type_caster: type_caster)
|
67
56
|
else
|
68
57
|
# Otherwise, we need to use an alias
|
69
58
|
aliased_name = @connection.table_alias_for(aliased_name)
|
@@ -76,10 +65,12 @@ module ActiveRecord
|
|
76
65
|
else
|
77
66
|
aliased_name
|
78
67
|
end
|
79
|
-
Arel::Table.new(table_name, type_caster:
|
68
|
+
Arel::Table.new(table_name, type_caster: type_caster).alias(table_alias)
|
80
69
|
end
|
81
70
|
end
|
82
71
|
|
72
|
+
attr_reader :aliases
|
73
|
+
|
83
74
|
private
|
84
75
|
|
85
76
|
def truncate(name)
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require "active_support/core_ext/array/wrap"
|
2
4
|
|
3
5
|
module ActiveRecord
|
@@ -17,7 +19,6 @@ module ActiveRecord
|
|
17
19
|
# HasManyThroughAssociation + ThroughAssociation
|
18
20
|
class Association #:nodoc:
|
19
21
|
attr_reader :owner, :target, :reflection
|
20
|
-
attr_accessor :inversed
|
21
22
|
|
22
23
|
delegate :options, to: :reflection
|
23
24
|
|
@@ -30,14 +31,6 @@ module ActiveRecord
|
|
30
31
|
reset_scope
|
31
32
|
end
|
32
33
|
|
33
|
-
# Returns the name of the table of the associated class:
|
34
|
-
#
|
35
|
-
# post.comments.aliased_table_name # => "comments"
|
36
|
-
#
|
37
|
-
def aliased_table_name
|
38
|
-
klass.table_name
|
39
|
-
end
|
40
|
-
|
41
34
|
# Resets the \loaded flag to +false+ and sets the \target to +nil+.
|
42
35
|
def reset
|
43
36
|
@loaded = false
|
@@ -73,7 +66,7 @@ module ActiveRecord
|
|
73
66
|
#
|
74
67
|
# Note that if the target has not been loaded, it is not considered stale.
|
75
68
|
def stale_target?
|
76
|
-
|
69
|
+
!@inversed && loaded? && @stale_state != stale_state
|
77
70
|
end
|
78
71
|
|
79
72
|
# Sets the target of this association to <tt>\target</tt>, and the \loaded flag to +true+.
|
@@ -94,7 +87,7 @@ module ActiveRecord
|
|
94
87
|
# actually gets built.
|
95
88
|
def association_scope
|
96
89
|
if klass
|
97
|
-
@association_scope ||= AssociationScope.scope(self
|
90
|
+
@association_scope ||= AssociationScope.scope(self)
|
98
91
|
end
|
99
92
|
end
|
100
93
|
|
@@ -104,23 +97,32 @@ module ActiveRecord
|
|
104
97
|
|
105
98
|
# Set the inverse association, if possible
|
106
99
|
def set_inverse_instance(record)
|
107
|
-
if
|
108
|
-
inverse
|
109
|
-
|
110
|
-
|
100
|
+
if inverse = inverse_association_for(record)
|
101
|
+
inverse.inversed_from(owner)
|
102
|
+
end
|
103
|
+
record
|
104
|
+
end
|
105
|
+
|
106
|
+
def set_inverse_instance_from_queries(record)
|
107
|
+
if inverse = inverse_association_for(record)
|
108
|
+
inverse.inversed_from_queries(owner)
|
111
109
|
end
|
112
110
|
record
|
113
111
|
end
|
114
112
|
|
115
113
|
# Remove the inverse association, if possible
|
116
114
|
def remove_inverse_instance(record)
|
117
|
-
if
|
118
|
-
inverse
|
119
|
-
inverse.target = nil
|
120
|
-
inverse.inversed = false
|
115
|
+
if inverse = inverse_association_for(record)
|
116
|
+
inverse.inversed_from(nil)
|
121
117
|
end
|
122
118
|
end
|
123
119
|
|
120
|
+
def inversed_from(record)
|
121
|
+
self.target = record
|
122
|
+
@inversed = !!record
|
123
|
+
end
|
124
|
+
alias :inversed_from_queries :inversed_from
|
125
|
+
|
124
126
|
# Returns the class of the target. belongs_to polymorphic overrides this to look at the
|
125
127
|
# polymorphic_type field on the owner.
|
126
128
|
def klass
|
@@ -130,7 +132,17 @@ module ActiveRecord
|
|
130
132
|
# Can be overridden (i.e. in ThroughAssociation) to merge in other scopes (i.e. the
|
131
133
|
# through association's scope)
|
132
134
|
def target_scope
|
133
|
-
AssociationRelation.create(klass,
|
135
|
+
AssociationRelation.create(klass, self).merge!(klass.all)
|
136
|
+
end
|
137
|
+
|
138
|
+
def extensions
|
139
|
+
extensions = klass.default_extensions | reflection.extensions
|
140
|
+
|
141
|
+
if reflection.scope
|
142
|
+
extensions |= reflection.scope_for(klass.unscoped, owner).extensions
|
143
|
+
end
|
144
|
+
|
145
|
+
extensions
|
134
146
|
end
|
135
147
|
|
136
148
|
# Loads the \target if needed and returns it.
|
@@ -152,17 +164,9 @@ module ActiveRecord
|
|
152
164
|
reset
|
153
165
|
end
|
154
166
|
|
155
|
-
|
156
|
-
if sql.respond_to?(:to_proc)
|
157
|
-
owner.instance_exec(record, &sql)
|
158
|
-
else
|
159
|
-
sql
|
160
|
-
end
|
161
|
-
end
|
162
|
-
|
163
|
-
# We can't dump @reflection since it contains the scope proc
|
167
|
+
# We can't dump @reflection and @through_reflection since it contains the scope proc
|
164
168
|
def marshal_dump
|
165
|
-
ivars = (instance_variables - [:@reflection]).map { |name| [name, instance_variable_get(name)] }
|
169
|
+
ivars = (instance_variables - [:@reflection, :@through_reflection]).map { |name| [name, instance_variable_get(name)] }
|
166
170
|
[@reflection.name, ivars]
|
167
171
|
end
|
168
172
|
|
@@ -177,8 +181,8 @@ module ActiveRecord
|
|
177
181
|
skip_assign = [reflection.foreign_key, reflection.type].compact
|
178
182
|
assigned_keys = record.changed_attribute_names_to_save
|
179
183
|
assigned_keys += except_from_scope_attributes.keys.map(&:to_s)
|
180
|
-
attributes =
|
181
|
-
record.
|
184
|
+
attributes = scope_for_create.except!(*(assigned_keys - skip_assign))
|
185
|
+
record.send(:_assign_attributes, attributes) if attributes.any?
|
182
186
|
set_inverse_instance(record)
|
183
187
|
end
|
184
188
|
|
@@ -191,6 +195,9 @@ module ActiveRecord
|
|
191
195
|
end
|
192
196
|
|
193
197
|
private
|
198
|
+
def scope_for_create
|
199
|
+
scope.scope_for_create
|
200
|
+
end
|
194
201
|
|
195
202
|
def find_target?
|
196
203
|
!loaded? && (!owner.new_record? || foreign_key_present?) && klass
|
@@ -202,8 +209,8 @@ module ActiveRecord
|
|
202
209
|
if (reflection.has_one? || reflection.collection?) && !options[:through]
|
203
210
|
attributes[reflection.foreign_key] = owner[reflection.active_record_primary_key]
|
204
211
|
|
205
|
-
if reflection.
|
206
|
-
attributes[reflection.type] = owner.class.
|
212
|
+
if reflection.type
|
213
|
+
attributes[reflection.type] = owner.class.polymorphic_name
|
207
214
|
end
|
208
215
|
end
|
209
216
|
|
@@ -241,6 +248,12 @@ module ActiveRecord
|
|
241
248
|
end
|
242
249
|
end
|
243
250
|
|
251
|
+
def inverse_association_for(record)
|
252
|
+
if invertible_for?(record)
|
253
|
+
record.association(inverse_reflection_for(record).name)
|
254
|
+
end
|
255
|
+
end
|
256
|
+
|
244
257
|
# Can be redefined by subclasses, notably polymorphic belongs_to
|
245
258
|
# The record parameter is necessary to support polymorphic inverses as we must check for
|
246
259
|
# the association in the specific class of the record.
|
@@ -270,11 +283,12 @@ module ActiveRecord
|
|
270
283
|
def build_record(attributes)
|
271
284
|
reflection.build_association(attributes) do |record|
|
272
285
|
initialize_attributes(record, attributes)
|
286
|
+
yield(record) if block_given?
|
273
287
|
end
|
274
288
|
end
|
275
289
|
|
276
290
|
# Returns true if statement cache should be skipped on the association reader.
|
277
|
-
def skip_statement_cache?
|
291
|
+
def skip_statement_cache?(scope)
|
278
292
|
reflection.has_scope? ||
|
279
293
|
scope.eager_loading? ||
|
280
294
|
klass.scope_attributes? ||
|
@@ -1,8 +1,10 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module ActiveRecord
|
2
4
|
module Associations
|
3
5
|
class AssociationScope #:nodoc:
|
4
|
-
def self.scope(association
|
5
|
-
INSTANCE.scope(association
|
6
|
+
def self.scope(association)
|
7
|
+
INSTANCE.scope(association)
|
6
8
|
end
|
7
9
|
|
8
10
|
def self.create(&block)
|
@@ -16,20 +18,15 @@ module ActiveRecord
|
|
16
18
|
|
17
19
|
INSTANCE = create
|
18
20
|
|
19
|
-
def scope(association
|
21
|
+
def scope(association)
|
20
22
|
klass = association.klass
|
21
23
|
reflection = association.reflection
|
22
24
|
scope = klass.unscoped
|
23
25
|
owner = association.owner
|
24
|
-
|
25
|
-
chain_head, chain_tail = get_chain(reflection, association, alias_tracker)
|
26
|
-
|
27
|
-
scope.extending! Array(reflection.options[:extend])
|
28
|
-
add_constraints(scope, owner, reflection, chain_head, chain_tail)
|
29
|
-
end
|
26
|
+
chain = get_chain(reflection, association, scope.alias_tracker)
|
30
27
|
|
31
|
-
|
32
|
-
|
28
|
+
scope.extending! reflection.extensions
|
29
|
+
add_constraints(scope, owner, chain)
|
33
30
|
end
|
34
31
|
|
35
32
|
def self.get_bind_values(owner, chain)
|
@@ -38,12 +35,12 @@ module ActiveRecord
|
|
38
35
|
|
39
36
|
binds << last_reflection.join_id_for(owner)
|
40
37
|
if last_reflection.type
|
41
|
-
binds << owner.class.
|
38
|
+
binds << owner.class.polymorphic_name
|
42
39
|
end
|
43
40
|
|
44
41
|
chain.each_cons(2).each do |reflection, next_reflection|
|
45
42
|
if reflection.type
|
46
|
-
binds << next_reflection.klass.
|
43
|
+
binds << next_reflection.klass.polymorphic_name
|
47
44
|
end
|
48
45
|
end
|
49
46
|
binds
|
@@ -57,20 +54,21 @@ module ActiveRecord
|
|
57
54
|
|
58
55
|
private
|
59
56
|
def join(table, constraint)
|
60
|
-
table.create_join(table, table.create_on(constraint)
|
57
|
+
table.create_join(table, table.create_on(constraint))
|
61
58
|
end
|
62
59
|
|
63
|
-
def last_chain_scope(scope,
|
60
|
+
def last_chain_scope(scope, reflection, owner)
|
64
61
|
join_keys = reflection.join_keys
|
65
62
|
key = join_keys.key
|
66
63
|
foreign_key = join_keys.foreign_key
|
67
64
|
|
65
|
+
table = reflection.aliased_table
|
68
66
|
value = transform_value(owner[foreign_key])
|
69
|
-
scope = scope
|
67
|
+
scope = apply_scope(scope, table, key, value)
|
70
68
|
|
71
69
|
if reflection.type
|
72
|
-
polymorphic_type = transform_value(owner.class.
|
73
|
-
scope = scope
|
70
|
+
polymorphic_type = transform_value(owner.class.polymorphic_name)
|
71
|
+
scope = apply_scope(scope, table, reflection.type, polymorphic_type)
|
74
72
|
end
|
75
73
|
|
76
74
|
scope
|
@@ -80,28 +78,29 @@ module ActiveRecord
|
|
80
78
|
value_transformation.call(value)
|
81
79
|
end
|
82
80
|
|
83
|
-
def next_chain_scope(scope,
|
81
|
+
def next_chain_scope(scope, reflection, next_reflection)
|
84
82
|
join_keys = reflection.join_keys
|
85
83
|
key = join_keys.key
|
86
84
|
foreign_key = join_keys.foreign_key
|
87
85
|
|
86
|
+
table = reflection.aliased_table
|
87
|
+
foreign_table = next_reflection.aliased_table
|
88
88
|
constraint = table[key].eq(foreign_table[foreign_key])
|
89
89
|
|
90
90
|
if reflection.type
|
91
|
-
value = transform_value(next_reflection.klass.
|
92
|
-
scope = scope
|
91
|
+
value = transform_value(next_reflection.klass.polymorphic_name)
|
92
|
+
scope = apply_scope(scope, table, reflection.type, value)
|
93
93
|
end
|
94
94
|
|
95
|
-
scope
|
95
|
+
scope.joins!(join(foreign_table, constraint))
|
96
96
|
end
|
97
97
|
|
98
98
|
class ReflectionProxy < SimpleDelegator # :nodoc:
|
99
|
-
|
100
|
-
attr_reader :alias_name
|
99
|
+
attr_reader :aliased_table
|
101
100
|
|
102
|
-
def initialize(reflection,
|
101
|
+
def initialize(reflection, aliased_table)
|
103
102
|
super(reflection)
|
104
|
-
@
|
103
|
+
@aliased_table = aliased_table
|
105
104
|
end
|
106
105
|
|
107
106
|
def all_includes; nil; end
|
@@ -109,39 +108,34 @@ module ActiveRecord
|
|
109
108
|
|
110
109
|
def get_chain(reflection, association, tracker)
|
111
110
|
name = reflection.name
|
112
|
-
|
113
|
-
previous_reflection = runtime_reflection
|
111
|
+
chain = [Reflection::RuntimeReflection.new(reflection, association)]
|
114
112
|
reflection.chain.drop(1).each do |refl|
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
113
|
+
aliased_table = tracker.aliased_table_for(
|
114
|
+
refl.table_name,
|
115
|
+
refl.alias_candidate(name),
|
116
|
+
refl.klass.type_caster
|
117
|
+
)
|
118
|
+
chain << ReflectionProxy.new(refl, aliased_table)
|
119
119
|
end
|
120
|
-
|
120
|
+
chain
|
121
121
|
end
|
122
122
|
|
123
|
-
def add_constraints(scope, owner,
|
124
|
-
|
125
|
-
table = owner_reflection.alias_name
|
126
|
-
scope = last_chain_scope(scope, table, owner_reflection, owner)
|
123
|
+
def add_constraints(scope, owner, chain)
|
124
|
+
scope = last_chain_scope(scope, chain.last, owner)
|
127
125
|
|
128
|
-
reflection
|
129
|
-
|
130
|
-
|
131
|
-
next_reflection = reflection.next
|
132
|
-
|
133
|
-
unless reflection == chain_tail
|
134
|
-
foreign_table = next_reflection.alias_name
|
135
|
-
scope = next_chain_scope(scope, table, reflection, foreign_table, next_reflection)
|
136
|
-
end
|
126
|
+
chain.each_cons(2) do |reflection, next_reflection|
|
127
|
+
scope = next_chain_scope(scope, reflection, next_reflection)
|
128
|
+
end
|
137
129
|
|
130
|
+
chain_head = chain.first
|
131
|
+
chain.reverse_each do |reflection|
|
138
132
|
# Exclude the scope of the association itself, because that
|
139
133
|
# was already merged in the #scope method.
|
140
134
|
reflection.constraints.each do |scope_chain_item|
|
141
|
-
item = eval_scope(reflection
|
135
|
+
item = eval_scope(reflection, scope_chain_item, owner)
|
142
136
|
|
143
|
-
if scope_chain_item ==
|
144
|
-
scope.merge! item.except(:where, :includes)
|
137
|
+
if scope_chain_item == chain_head.scope
|
138
|
+
scope.merge! item.except(:where, :includes, :unscope, :order)
|
145
139
|
end
|
146
140
|
|
147
141
|
reflection.all_includes do
|
@@ -150,18 +144,24 @@ module ActiveRecord
|
|
150
144
|
|
151
145
|
scope.unscope!(*item.unscope_values)
|
152
146
|
scope.where_clause += item.where_clause
|
153
|
-
scope.order_values
|
147
|
+
scope.order_values = item.order_values | scope.order_values
|
154
148
|
end
|
155
|
-
|
156
|
-
reflection = next_reflection
|
157
149
|
end
|
158
150
|
|
159
151
|
scope
|
160
152
|
end
|
161
153
|
|
162
|
-
def
|
163
|
-
|
164
|
-
|
154
|
+
def apply_scope(scope, table, key, value)
|
155
|
+
if scope.table == table
|
156
|
+
scope.where!(key => value)
|
157
|
+
else
|
158
|
+
scope.where!(table.name => { key => value })
|
159
|
+
end
|
160
|
+
end
|
161
|
+
|
162
|
+
def eval_scope(reflection, scope, owner)
|
163
|
+
relation = reflection.build_scope(reflection.aliased_table)
|
164
|
+
relation.instance_exec(owner, &scope) || relation
|
165
165
|
end
|
166
166
|
end
|
167
167
|
end
|