activerecord 4.2.11.3 → 5.0.0.beta1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of activerecord might be problematic. Click here for more details.
- checksums.yaml +5 -5
- data/CHANGELOG.md +1029 -1349
- data/MIT-LICENSE +1 -1
- data/README.rdoc +6 -7
- data/examples/performance.rb +2 -2
- data/lib/active_record.rb +7 -3
- data/lib/active_record/aggregations.rb +35 -25
- data/lib/active_record/association_relation.rb +2 -2
- data/lib/active_record/associations.rb +305 -204
- data/lib/active_record/associations/alias_tracker.rb +19 -16
- data/lib/active_record/associations/association.rb +10 -8
- data/lib/active_record/associations/association_scope.rb +73 -102
- data/lib/active_record/associations/belongs_to_association.rb +20 -32
- data/lib/active_record/associations/builder/association.rb +28 -34
- data/lib/active_record/associations/builder/belongs_to.rb +41 -18
- data/lib/active_record/associations/builder/collection_association.rb +8 -24
- data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +11 -11
- data/lib/active_record/associations/builder/has_many.rb +4 -4
- data/lib/active_record/associations/builder/has_one.rb +10 -5
- data/lib/active_record/associations/builder/singular_association.rb +2 -9
- data/lib/active_record/associations/collection_association.rb +40 -43
- data/lib/active_record/associations/collection_proxy.rb +55 -29
- data/lib/active_record/associations/foreign_association.rb +1 -1
- data/lib/active_record/associations/has_many_association.rb +20 -71
- data/lib/active_record/associations/has_many_through_association.rb +8 -52
- data/lib/active_record/associations/has_one_association.rb +12 -5
- data/lib/active_record/associations/join_dependency.rb +28 -18
- data/lib/active_record/associations/join_dependency/join_association.rb +13 -12
- data/lib/active_record/associations/preloader.rb +13 -4
- data/lib/active_record/associations/preloader/association.rb +45 -51
- data/lib/active_record/associations/preloader/collection_association.rb +0 -6
- 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/through_association.rb +5 -4
- data/lib/active_record/associations/singular_association.rb +6 -0
- data/lib/active_record/associations/through_association.rb +11 -3
- data/lib/active_record/attribute.rb +61 -17
- data/lib/active_record/attribute/user_provided_default.rb +23 -0
- data/lib/active_record/attribute_assignment.rb +27 -140
- data/lib/active_record/attribute_decorators.rb +6 -5
- data/lib/active_record/attribute_methods.rb +79 -26
- 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 +2 -2
- data/lib/active_record/attribute_methods/query.rb +2 -2
- data/lib/active_record/attribute_methods/read.rb +26 -42
- data/lib/active_record/attribute_methods/serialization.rb +13 -16
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +42 -9
- data/lib/active_record/attribute_methods/write.rb +13 -24
- data/lib/active_record/attribute_mutation_tracker.rb +70 -0
- data/lib/active_record/attribute_set.rb +30 -3
- data/lib/active_record/attribute_set/builder.rb +6 -4
- data/lib/active_record/attributes.rb +194 -81
- data/lib/active_record/autosave_association.rb +33 -15
- data/lib/active_record/base.rb +30 -18
- data/lib/active_record/callbacks.rb +36 -40
- data/lib/active_record/coders/yaml_column.rb +20 -8
- data/lib/active_record/collection_cache_key.rb +31 -0
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +431 -122
- data/lib/active_record/connection_adapters/abstract/database_limits.rb +3 -3
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +40 -22
- data/lib/active_record/connection_adapters/abstract/quoting.rb +62 -8
- data/lib/active_record/connection_adapters/abstract/schema_creation.rb +46 -38
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +229 -185
- data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +52 -13
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +275 -115
- data/lib/active_record/connection_adapters/abstract/transaction.rb +32 -33
- data/lib/active_record/connection_adapters/abstract_adapter.rb +83 -32
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +384 -221
- data/lib/active_record/connection_adapters/column.rb +27 -41
- data/lib/active_record/connection_adapters/connection_specification.rb +2 -21
- data/lib/active_record/connection_adapters/determine_if_preparable_visitor.rb +22 -0
- data/lib/active_record/connection_adapters/mysql/schema_creation.rb +57 -0
- data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +69 -0
- data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +59 -0
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +22 -101
- data/lib/active_record/connection_adapters/postgresql/column.rb +6 -10
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +3 -3
- data/lib/active_record/connection_adapters/postgresql/oid.rb +1 -6
- data/lib/active_record/connection_adapters/postgresql/oid/array.rb +23 -57
- data/lib/active_record/connection_adapters/postgresql/oid/bit.rb +2 -2
- data/lib/active_record/connection_adapters/postgresql/oid/bytea.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +7 -22
- data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +3 -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 -2
- 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 +23 -16
- 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 +18 -11
- 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 +54 -0
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +174 -128
- data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +35 -0
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +184 -112
- 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/schema_creation.rb +15 -0
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +134 -110
- data/lib/active_record/connection_adapters/statement_pool.rb +28 -11
- data/lib/active_record/connection_handling.rb +5 -5
- data/lib/active_record/core.rb +72 -104
- data/lib/active_record/counter_cache.rb +9 -20
- data/lib/active_record/dynamic_matchers.rb +1 -20
- data/lib/active_record/enum.rb +110 -76
- data/lib/active_record/errors.rb +72 -47
- 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 +19 -4
- data/lib/active_record/fixtures.rb +76 -40
- data/lib/active_record/gem_version.rb +4 -4
- data/lib/active_record/inheritance.rb +27 -40
- data/lib/active_record/integration.rb +4 -4
- 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 +10 -14
- data/lib/active_record/locking/pessimistic.rb +1 -1
- data/lib/active_record/log_subscriber.rb +40 -22
- data/lib/active_record/migration.rb +304 -133
- data/lib/active_record/migration/command_recorder.rb +59 -18
- data/lib/active_record/migration/compatibility.rb +90 -0
- data/lib/active_record/model_schema.rb +92 -40
- data/lib/active_record/nested_attributes.rb +45 -34
- data/lib/active_record/null_relation.rb +15 -7
- data/lib/active_record/persistence.rb +112 -72
- data/lib/active_record/querying.rb +6 -5
- data/lib/active_record/railtie.rb +20 -13
- data/lib/active_record/railties/controller_runtime.rb +1 -1
- data/lib/active_record/railties/databases.rake +47 -38
- data/lib/active_record/readonly_attributes.rb +1 -1
- data/lib/active_record/reflection.rb +182 -57
- data/lib/active_record/relation.rb +152 -100
- data/lib/active_record/relation/batches.rb +133 -33
- data/lib/active_record/relation/batches/batch_enumerator.rb +67 -0
- data/lib/active_record/relation/calculations.rb +80 -101
- data/lib/active_record/relation/delegation.rb +6 -19
- data/lib/active_record/relation/finder_methods.rb +58 -46
- data/lib/active_record/relation/from_clause.rb +32 -0
- data/lib/active_record/relation/merger.rb +13 -42
- data/lib/active_record/relation/predicate_builder.rb +99 -105
- data/lib/active_record/relation/predicate_builder/array_handler.rb +11 -16
- data/lib/active_record/relation/predicate_builder/association_query_handler.rb +78 -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/range_handler.rb +17 -0
- data/lib/active_record/relation/query_attribute.rb +19 -0
- data/lib/active_record/relation/query_methods.rb +274 -238
- data/lib/active_record/relation/record_fetch_warning.rb +51 -0
- data/lib/active_record/relation/spawn_methods.rb +3 -6
- data/lib/active_record/relation/where_clause.rb +173 -0
- data/lib/active_record/relation/where_clause_factory.rb +37 -0
- data/lib/active_record/result.rb +4 -3
- data/lib/active_record/runtime_registry.rb +1 -1
- data/lib/active_record/sanitization.rb +94 -65
- data/lib/active_record/schema.rb +23 -22
- data/lib/active_record/schema_dumper.rb +33 -22
- data/lib/active_record/schema_migration.rb +10 -4
- data/lib/active_record/scoping.rb +17 -6
- data/lib/active_record/scoping/default.rb +19 -6
- data/lib/active_record/scoping/named.rb +39 -28
- data/lib/active_record/secure_token.rb +38 -0
- data/lib/active_record/serialization.rb +2 -4
- data/lib/active_record/statement_cache.rb +15 -13
- data/lib/active_record/store.rb +8 -3
- data/lib/active_record/suppressor.rb +54 -0
- data/lib/active_record/table_metadata.rb +64 -0
- data/lib/active_record/tasks/database_tasks.rb +30 -40
- data/lib/active_record/tasks/mysql_database_tasks.rb +7 -15
- data/lib/active_record/tasks/postgresql_database_tasks.rb +11 -2
- data/lib/active_record/tasks/sqlite_database_tasks.rb +5 -1
- data/lib/active_record/timestamp.rb +16 -9
- data/lib/active_record/touch_later.rb +58 -0
- data/lib/active_record/transactions.rb +138 -56
- 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 +9 -14
- data/lib/active_record/type/time.rb +3 -21
- 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 +24 -0
- data/lib/active_record/validations/associated.rb +10 -3
- data/lib/active_record/validations/length.rb +36 -0
- data/lib/active_record/validations/presence.rb +12 -12
- data/lib/active_record/validations/uniqueness.rb +24 -21
- data/lib/rails/generators/active_record/migration.rb +7 -0
- data/lib/rails/generators/active_record/migration/migration_generator.rb +7 -4
- data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb +8 -3
- data/lib/rails/generators/active_record/migration/templates/migration.rb +4 -1
- data/lib/rails/generators/active_record/model/model_generator.rb +21 -15
- data/lib/rails/generators/active_record/model/templates/model.rb +3 -0
- metadata +50 -35
- 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
@@ -2,23 +2,25 @@ require 'active_support/core_ext/string/conversions'
|
|
2
2
|
|
3
3
|
module ActiveRecord
|
4
4
|
module Associations
|
5
|
-
# Keeps track of table aliases for ActiveRecord::Associations::
|
6
|
-
# ActiveRecord::Associations::ThroughAssociationScope
|
5
|
+
# Keeps track of table aliases for ActiveRecord::Associations::JoinDependency
|
7
6
|
class AliasTracker # :nodoc:
|
8
|
-
attr_reader :aliases
|
7
|
+
attr_reader :aliases
|
9
8
|
|
10
|
-
def self.
|
11
|
-
|
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
|
12
13
|
end
|
13
14
|
|
14
|
-
def self.
|
15
|
-
if
|
16
|
-
|
15
|
+
def self.create_with_joins(connection, initial_table, joins, type_caster)
|
16
|
+
if joins.empty?
|
17
|
+
create(connection, initial_table, type_caster)
|
17
18
|
else
|
18
|
-
aliases = Hash.new { |h,k|
|
19
|
-
h[k] = initial_count_for(connection, k,
|
19
|
+
aliases = Hash.new { |h, k|
|
20
|
+
h[k] = initial_count_for(connection, k, joins)
|
20
21
|
}
|
21
|
-
|
22
|
+
aliases[initial_table] = 1
|
23
|
+
new connection, aliases, type_caster
|
22
24
|
end
|
23
25
|
end
|
24
26
|
|
@@ -51,19 +53,20 @@ module ActiveRecord
|
|
51
53
|
end
|
52
54
|
|
53
55
|
# table_joins is an array of arel joins which might conflict with the aliases we assign here
|
54
|
-
def initialize(connection, aliases)
|
56
|
+
def initialize(connection, aliases, type_caster)
|
55
57
|
@aliases = aliases
|
56
58
|
@connection = connection
|
59
|
+
@type_caster = type_caster
|
57
60
|
end
|
58
61
|
|
59
62
|
def aliased_table_for(table_name, aliased_name)
|
60
63
|
if aliases[table_name].zero?
|
61
64
|
# If it's zero, we can have our table_name
|
62
65
|
aliases[table_name] = 1
|
63
|
-
Arel::Table.new(table_name)
|
66
|
+
Arel::Table.new(table_name, type_caster: @type_caster)
|
64
67
|
else
|
65
68
|
# Otherwise, we need to use an alias
|
66
|
-
aliased_name = connection.table_alias_for(aliased_name)
|
69
|
+
aliased_name = @connection.table_alias_for(aliased_name)
|
67
70
|
|
68
71
|
# Update the count
|
69
72
|
aliases[aliased_name] += 1
|
@@ -73,14 +76,14 @@ module ActiveRecord
|
|
73
76
|
else
|
74
77
|
aliased_name
|
75
78
|
end
|
76
|
-
Arel::Table.new(table_name).alias(table_alias)
|
79
|
+
Arel::Table.new(table_name, type_caster: @type_caster).alias(table_alias)
|
77
80
|
end
|
78
81
|
end
|
79
82
|
|
80
83
|
private
|
81
84
|
|
82
85
|
def truncate(name)
|
83
|
-
name.slice(0, connection.table_alias_length - 2)
|
86
|
+
name.slice(0, @connection.table_alias_length - 2)
|
84
87
|
end
|
85
88
|
end
|
86
89
|
end
|
@@ -8,12 +8,12 @@ module ActiveRecord
|
|
8
8
|
#
|
9
9
|
# Association
|
10
10
|
# SingularAssociation
|
11
|
-
# HasOneAssociation
|
11
|
+
# HasOneAssociation + ForeignAssociation
|
12
12
|
# HasOneThroughAssociation + ThroughAssociation
|
13
13
|
# BelongsToAssociation
|
14
14
|
# BelongsToPolymorphicAssociation
|
15
15
|
# CollectionAssociation
|
16
|
-
# HasManyAssociation
|
16
|
+
# HasManyAssociation + ForeignAssociation
|
17
17
|
# HasManyThroughAssociation + ThroughAssociation
|
18
18
|
class Association #:nodoc:
|
19
19
|
attr_reader :owner, :target, :reflection
|
@@ -121,7 +121,7 @@ module ActiveRecord
|
|
121
121
|
# Can be overridden (i.e. in ThroughAssociation) to merge in other scopes (i.e. the
|
122
122
|
# through association's scope)
|
123
123
|
def target_scope
|
124
|
-
AssociationRelation.create(klass, klass.arel_table, self).merge!(klass.all)
|
124
|
+
AssociationRelation.create(klass, klass.arel_table, klass.predicate_builder, self).merge!(klass.all)
|
125
125
|
end
|
126
126
|
|
127
127
|
# Loads the \target if needed and returns it.
|
@@ -163,9 +163,12 @@ module ActiveRecord
|
|
163
163
|
@reflection = @owner.class._reflect_on_association(reflection_name)
|
164
164
|
end
|
165
165
|
|
166
|
-
def initialize_attributes(record) #:nodoc:
|
166
|
+
def initialize_attributes(record, except_from_scope_attributes = nil) #:nodoc:
|
167
|
+
except_from_scope_attributes ||= {}
|
167
168
|
skip_assign = [reflection.foreign_key, reflection.type].compact
|
168
|
-
|
169
|
+
assigned_keys = record.changed
|
170
|
+
assigned_keys += except_from_scope_attributes.keys.map(&:to_s)
|
171
|
+
attributes = create_scope.except(*(assigned_keys - skip_assign))
|
169
172
|
record.assign_attributes(attributes)
|
170
173
|
set_inverse_instance(record)
|
171
174
|
end
|
@@ -248,7 +251,7 @@ module ActiveRecord
|
|
248
251
|
|
249
252
|
def build_record(attributes)
|
250
253
|
reflection.build_association(attributes) do |record|
|
251
|
-
initialize_attributes(record)
|
254
|
+
initialize_attributes(record, attributes)
|
252
255
|
end
|
253
256
|
end
|
254
257
|
|
@@ -256,8 +259,7 @@ module ActiveRecord
|
|
256
259
|
def skip_statement_cache?
|
257
260
|
reflection.scope_chain.any?(&:any?) ||
|
258
261
|
scope.eager_loading? ||
|
259
|
-
klass.
|
260
|
-
klass.default_scopes.any? ||
|
262
|
+
klass.scope_attributes? ||
|
261
263
|
reflection.source_reflection.active_record.default_scopes.any?
|
262
264
|
end
|
263
265
|
end
|
@@ -2,41 +2,30 @@ module ActiveRecord
|
|
2
2
|
module Associations
|
3
3
|
class AssociationScope #:nodoc:
|
4
4
|
def self.scope(association, connection)
|
5
|
-
INSTANCE.scope
|
6
|
-
end
|
7
|
-
|
8
|
-
class BindSubstitution
|
9
|
-
def initialize(block)
|
10
|
-
@block = block
|
11
|
-
end
|
12
|
-
|
13
|
-
def bind_value(scope, column, value, alias_tracker)
|
14
|
-
substitute = alias_tracker.connection.substitute_at(column)
|
15
|
-
scope.bind_values += [[column, @block.call(value)]]
|
16
|
-
substitute
|
17
|
-
end
|
5
|
+
INSTANCE.scope(association, connection)
|
18
6
|
end
|
19
7
|
|
20
8
|
def self.create(&block)
|
21
|
-
block
|
22
|
-
new
|
9
|
+
block ||= lambda { |val| val }
|
10
|
+
new(block)
|
23
11
|
end
|
24
12
|
|
25
|
-
def initialize(
|
26
|
-
@
|
13
|
+
def initialize(value_transformation)
|
14
|
+
@value_transformation = value_transformation
|
27
15
|
end
|
28
16
|
|
29
17
|
INSTANCE = create
|
30
18
|
|
31
19
|
def scope(association, connection)
|
32
|
-
klass
|
33
|
-
reflection
|
34
|
-
scope
|
35
|
-
owner
|
36
|
-
alias_tracker = AliasTracker.
|
20
|
+
klass = association.klass
|
21
|
+
reflection = association.reflection
|
22
|
+
scope = klass.unscoped
|
23
|
+
owner = association.owner
|
24
|
+
alias_tracker = AliasTracker.create connection, association.klass.table_name, klass.type_caster
|
25
|
+
chain_head, chain_tail = get_chain(reflection, association, alias_tracker)
|
37
26
|
|
38
27
|
scope.extending! Array(reflection.options[:extend])
|
39
|
-
add_constraints(scope, owner, klass, reflection,
|
28
|
+
add_constraints(scope, owner, klass, reflection, chain_head, chain_tail)
|
40
29
|
end
|
41
30
|
|
42
31
|
def join_type
|
@@ -60,133 +49,115 @@ module ActiveRecord
|
|
60
49
|
binds
|
61
50
|
end
|
62
51
|
|
63
|
-
|
52
|
+
protected
|
64
53
|
|
65
|
-
|
66
|
-
chain.map do |reflection|
|
67
|
-
alias_tracker.aliased_table_for(
|
68
|
-
table_name_for(reflection, klass, refl),
|
69
|
-
table_alias_for(reflection, refl, reflection != refl)
|
70
|
-
)
|
71
|
-
end
|
72
|
-
end
|
73
|
-
|
74
|
-
def table_alias_for(reflection, refl, join = false)
|
75
|
-
name = "#{reflection.plural_name}_#{alias_suffix(refl)}"
|
76
|
-
name << "_join" if join
|
77
|
-
name
|
78
|
-
end
|
54
|
+
attr_reader :value_transformation
|
79
55
|
|
56
|
+
private
|
80
57
|
def join(table, constraint)
|
81
58
|
table.create_join(table, table.create_on(constraint), join_type)
|
82
59
|
end
|
83
60
|
|
84
|
-
def
|
85
|
-
|
86
|
-
columns[column_name]
|
87
|
-
end
|
88
|
-
|
89
|
-
def bind_value(scope, column, value, alias_tracker)
|
90
|
-
@bind_substitution.bind_value scope, column, value, alias_tracker
|
91
|
-
end
|
92
|
-
|
93
|
-
def bind(scope, table_name, column_name, value, tracker)
|
94
|
-
column = column_for table_name, column_name, tracker
|
95
|
-
bind_value scope, column, value, tracker
|
96
|
-
end
|
97
|
-
|
98
|
-
def last_chain_scope(scope, table, reflection, owner, tracker, assoc_klass)
|
99
|
-
join_keys = reflection.join_keys(assoc_klass)
|
61
|
+
def last_chain_scope(scope, table, reflection, owner, association_klass)
|
62
|
+
join_keys = reflection.join_keys(association_klass)
|
100
63
|
key = join_keys.key
|
101
64
|
foreign_key = join_keys.foreign_key
|
102
65
|
|
103
|
-
|
104
|
-
scope
|
66
|
+
value = transform_value(owner[foreign_key])
|
67
|
+
scope = scope.where(table.name => { key => value })
|
105
68
|
|
106
69
|
if reflection.type
|
107
|
-
|
108
|
-
|
109
|
-
scope = scope.where(table[reflection.type].eq(bind_val))
|
110
|
-
else
|
111
|
-
scope
|
70
|
+
polymorphic_type = transform_value(owner.class.base_class.name)
|
71
|
+
scope = scope.where(table.name => { reflection.type => polymorphic_type })
|
112
72
|
end
|
73
|
+
|
74
|
+
scope
|
113
75
|
end
|
114
76
|
|
115
|
-
def
|
116
|
-
|
77
|
+
def transform_value(value)
|
78
|
+
value_transformation.call(value)
|
79
|
+
end
|
80
|
+
|
81
|
+
def next_chain_scope(scope, table, reflection, association_klass, foreign_table, next_reflection)
|
82
|
+
join_keys = reflection.join_keys(association_klass)
|
117
83
|
key = join_keys.key
|
118
84
|
foreign_key = join_keys.foreign_key
|
119
85
|
|
120
86
|
constraint = table[key].eq(foreign_table[foreign_key])
|
121
87
|
|
122
88
|
if reflection.type
|
123
|
-
value
|
124
|
-
|
125
|
-
scope = scope.where(table[reflection.type].eq(bind_val))
|
89
|
+
value = transform_value(next_reflection.klass.base_class.name)
|
90
|
+
scope = scope.where(table.name => { reflection.type => value })
|
126
91
|
end
|
127
92
|
|
128
93
|
scope = scope.joins(join(foreign_table, constraint))
|
129
94
|
end
|
130
95
|
|
131
|
-
|
132
|
-
|
133
|
-
|
96
|
+
class ReflectionProxy < SimpleDelegator # :nodoc:
|
97
|
+
attr_accessor :next
|
98
|
+
attr_reader :alias_name
|
134
99
|
|
135
|
-
|
100
|
+
def initialize(reflection, alias_name)
|
101
|
+
super(reflection)
|
102
|
+
@alias_name = alias_name
|
103
|
+
end
|
136
104
|
|
137
|
-
|
138
|
-
|
139
|
-
scope = last_chain_scope(scope, table, owner_reflection, owner, tracker, assoc_klass)
|
105
|
+
def all_includes; nil; end
|
106
|
+
end
|
140
107
|
|
141
|
-
|
142
|
-
|
108
|
+
def get_chain(reflection, association, tracker)
|
109
|
+
name = reflection.name
|
110
|
+
runtime_reflection = Reflection::RuntimeReflection.new(reflection, association)
|
111
|
+
previous_reflection = runtime_reflection
|
112
|
+
reflection.chain.drop(1).each do |refl|
|
113
|
+
alias_name = tracker.aliased_table_for(refl.table_name, refl.alias_candidate(name))
|
114
|
+
proxy = ReflectionProxy.new(refl, alias_name)
|
115
|
+
previous_reflection.next = proxy
|
116
|
+
previous_reflection = proxy
|
117
|
+
end
|
118
|
+
[runtime_reflection, previous_reflection]
|
119
|
+
end
|
143
120
|
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
121
|
+
def add_constraints(scope, owner, association_klass, refl, chain_head, chain_tail)
|
122
|
+
owner_reflection = chain_tail
|
123
|
+
table = owner_reflection.alias_name
|
124
|
+
scope = last_chain_scope(scope, table, owner_reflection, owner, association_klass)
|
148
125
|
|
149
|
-
|
150
|
-
|
126
|
+
reflection = chain_head
|
127
|
+
loop do
|
128
|
+
break unless reflection
|
129
|
+
table = reflection.alias_name
|
130
|
+
|
131
|
+
unless reflection == chain_tail
|
132
|
+
next_reflection = reflection.next
|
133
|
+
foreign_table = next_reflection.alias_name
|
134
|
+
scope = next_chain_scope(scope, table, reflection, association_klass, foreign_table, next_reflection)
|
135
|
+
end
|
151
136
|
|
152
137
|
# Exclude the scope of the association itself, because that
|
153
138
|
# was already merged in the #scope method.
|
154
|
-
|
155
|
-
item = eval_scope(klass, scope_chain_item, owner)
|
139
|
+
reflection.constraints.each do |scope_chain_item|
|
140
|
+
item = eval_scope(reflection.klass, scope_chain_item, owner)
|
156
141
|
|
157
142
|
if scope_chain_item == refl.scope
|
158
|
-
scope.merge! item.except(:where, :includes
|
143
|
+
scope.merge! item.except(:where, :includes)
|
159
144
|
end
|
160
145
|
|
161
|
-
|
146
|
+
reflection.all_includes do
|
162
147
|
scope.includes! item.includes_values
|
163
148
|
end
|
164
149
|
|
165
150
|
scope.unscope!(*item.unscope_values)
|
166
|
-
scope.
|
167
|
-
scope.bind_values += item.bind_values
|
151
|
+
scope.where_clause += item.where_clause
|
168
152
|
scope.order_values |= item.order_values
|
169
153
|
end
|
154
|
+
|
155
|
+
reflection = reflection.next
|
170
156
|
end
|
171
157
|
|
172
158
|
scope
|
173
159
|
end
|
174
160
|
|
175
|
-
def alias_suffix(refl)
|
176
|
-
refl.name
|
177
|
-
end
|
178
|
-
|
179
|
-
def table_name_for(reflection, klass, refl)
|
180
|
-
if reflection == refl
|
181
|
-
# If this is a polymorphic belongs_to, we want to get the klass from the
|
182
|
-
# association because it depends on the polymorphic_type attribute of
|
183
|
-
# the owner
|
184
|
-
klass.table_name
|
185
|
-
else
|
186
|
-
reflection.table_name
|
187
|
-
end
|
188
|
-
end
|
189
|
-
|
190
161
|
def eval_scope(klass, scope, owner)
|
191
162
|
klass.unscoped.instance_exec(owner, &scope)
|
192
163
|
end
|
@@ -10,7 +10,7 @@ module ActiveRecord
|
|
10
10
|
def replace(record)
|
11
11
|
if record
|
12
12
|
raise_on_type_mismatch!(record)
|
13
|
-
|
13
|
+
update_counters_on_replace(record)
|
14
14
|
replace_keys(record)
|
15
15
|
set_inverse_instance(record)
|
16
16
|
@updated = true
|
@@ -32,45 +32,37 @@ module ActiveRecord
|
|
32
32
|
end
|
33
33
|
|
34
34
|
def decrement_counters # :nodoc:
|
35
|
-
|
35
|
+
update_counters(-1)
|
36
36
|
end
|
37
37
|
|
38
38
|
def increment_counters # :nodoc:
|
39
|
-
|
39
|
+
update_counters(1)
|
40
40
|
end
|
41
41
|
|
42
42
|
private
|
43
43
|
|
44
|
-
def
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
44
|
+
def update_counters(by)
|
45
|
+
if require_counter_update? && foreign_key_present?
|
46
|
+
if target && !stale_target?
|
47
|
+
target.increment!(reflection.counter_cache_column, by)
|
48
|
+
else
|
49
|
+
klass.update_counters(target_id, reflection.counter_cache_column => by)
|
50
|
+
end
|
51
|
+
end
|
52
52
|
end
|
53
53
|
|
54
|
-
def
|
55
|
-
|
56
|
-
return unless different_target? record
|
57
|
-
record.class.increment_counter(name, record.id)
|
58
|
-
decrement_counter name
|
59
|
-
end
|
54
|
+
def find_target?
|
55
|
+
!loaded? && foreign_key_present? && klass
|
60
56
|
end
|
61
57
|
|
62
|
-
def
|
63
|
-
|
64
|
-
klass.decrement_counter(counter_cache_name, target_id)
|
65
|
-
end
|
58
|
+
def require_counter_update?
|
59
|
+
reflection.counter_cache_column && owner.persisted?
|
66
60
|
end
|
67
61
|
|
68
|
-
def
|
69
|
-
if
|
70
|
-
|
71
|
-
|
72
|
-
target.increment(counter_cache_name)
|
73
|
-
end
|
62
|
+
def update_counters_on_replace(record)
|
63
|
+
if require_counter_update? && different_target?(record)
|
64
|
+
record.increment!(reflection.counter_cache_column)
|
65
|
+
decrement_counters
|
74
66
|
end
|
75
67
|
end
|
76
68
|
|
@@ -107,13 +99,9 @@ module ActiveRecord
|
|
107
99
|
end
|
108
100
|
|
109
101
|
def stale_state
|
110
|
-
result = owner._read_attribute(reflection.foreign_key)
|
102
|
+
result = owner._read_attribute(reflection.foreign_key) { |n| owner.send(:missing_attribute, n, caller) }
|
111
103
|
result && result.to_s
|
112
104
|
end
|
113
|
-
|
114
|
-
def counter_cache_available_in_memory?(counter_cache_name)
|
115
|
-
target.respond_to?(counter_cache_name)
|
116
|
-
end
|
117
105
|
end
|
118
106
|
end
|
119
107
|
end
|