activerecord 4.2.0 → 5.0.0
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of activerecord might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/CHANGELOG.md +1537 -789
- data/MIT-LICENSE +2 -2
- data/README.rdoc +7 -8
- data/examples/performance.rb +2 -3
- data/examples/simple.rb +0 -1
- data/lib/active_record/aggregations.rb +37 -23
- data/lib/active_record/association_relation.rb +16 -3
- data/lib/active_record/associations/alias_tracker.rb +19 -16
- data/lib/active_record/associations/association.rb +23 -9
- data/lib/active_record/associations/association_scope.rb +74 -102
- data/lib/active_record/associations/belongs_to_association.rb +26 -29
- data/lib/active_record/associations/builder/association.rb +28 -34
- data/lib/active_record/associations/builder/belongs_to.rb +43 -18
- data/lib/active_record/associations/builder/collection_association.rb +12 -20
- data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +22 -15
- data/lib/active_record/associations/builder/has_many.rb +4 -4
- data/lib/active_record/associations/builder/has_one.rb +11 -6
- data/lib/active_record/associations/builder/singular_association.rb +3 -10
- data/lib/active_record/associations/collection_association.rb +61 -33
- data/lib/active_record/associations/collection_proxy.rb +81 -35
- data/lib/active_record/associations/foreign_association.rb +11 -0
- data/lib/active_record/associations/has_many_association.rb +21 -57
- data/lib/active_record/associations/has_many_through_association.rb +15 -45
- data/lib/active_record/associations/has_one_association.rb +13 -5
- data/lib/active_record/associations/join_dependency/join_association.rb +20 -8
- data/lib/active_record/associations/join_dependency.rb +37 -21
- data/lib/active_record/associations/preloader/association.rb +51 -53
- 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 +27 -14
- data/lib/active_record/associations/preloader.rb +18 -8
- data/lib/active_record/associations/singular_association.rb +8 -8
- data/lib/active_record/associations/through_association.rb +22 -9
- data/lib/active_record/associations.rb +321 -212
- data/lib/active_record/attribute/user_provided_default.rb +28 -0
- data/lib/active_record/attribute.rb +79 -15
- data/lib/active_record/attribute_assignment.rb +20 -141
- data/lib/active_record/attribute_decorators.rb +6 -5
- data/lib/active_record/attribute_methods/before_type_cast.rb +6 -1
- data/lib/active_record/attribute_methods/dirty.rb +51 -81
- 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 +31 -59
- data/lib/active_record/attribute_methods/serialization.rb +13 -16
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +65 -14
- data/lib/active_record/attribute_methods/write.rb +14 -38
- data/lib/active_record/attribute_methods.rb +70 -45
- data/lib/active_record/attribute_mutation_tracker.rb +70 -0
- data/lib/active_record/attribute_set/builder.rb +37 -15
- data/lib/active_record/attribute_set.rb +34 -3
- data/lib/active_record/attributes.rb +199 -73
- data/lib/active_record/autosave_association.rb +73 -25
- data/lib/active_record/base.rb +35 -27
- data/lib/active_record/callbacks.rb +39 -43
- data/lib/active_record/coders/json.rb +1 -1
- data/lib/active_record/coders/yaml_column.rb +20 -8
- data/lib/active_record/collection_cache_key.rb +40 -0
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +457 -181
- data/lib/active_record/connection_adapters/abstract/database_limits.rb +3 -3
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +83 -59
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +3 -3
- data/lib/active_record/connection_adapters/abstract/quoting.rb +74 -9
- data/lib/active_record/connection_adapters/abstract/savepoints.rb +4 -4
- data/lib/active_record/connection_adapters/abstract/schema_creation.rb +61 -39
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +246 -185
- data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +72 -17
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +438 -136
- data/lib/active_record/connection_adapters/abstract/transaction.rb +53 -40
- data/lib/active_record/connection_adapters/abstract_adapter.rb +166 -66
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +429 -335
- data/lib/active_record/connection_adapters/column.rb +28 -43
- data/lib/active_record/connection_adapters/connection_specification.rb +15 -27
- data/lib/active_record/connection_adapters/determine_if_preparable_visitor.rb +22 -0
- data/lib/active_record/connection_adapters/mysql/column.rb +50 -0
- data/lib/active_record/connection_adapters/mysql/database_statements.rb +125 -0
- data/lib/active_record/connection_adapters/mysql/explain_pretty_printer.rb +70 -0
- data/lib/active_record/connection_adapters/mysql/quoting.rb +51 -0
- data/lib/active_record/connection_adapters/mysql/schema_creation.rb +67 -0
- data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +93 -0
- data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +54 -0
- data/lib/active_record/connection_adapters/mysql/type_metadata.rb +32 -0
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +26 -177
- data/lib/active_record/connection_adapters/postgresql/column.rb +5 -10
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +11 -73
- data/lib/active_record/connection_adapters/postgresql/explain_pretty_printer.rb +42 -0
- data/lib/active_record/connection_adapters/postgresql/oid/array.rb +27 -56
- data/lib/active_record/connection_adapters/postgresql/oid/bit.rb +2 -2
- data/lib/active_record/connection_adapters/postgresql/oid/bytea.rb +2 -1
- data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +3 -1
- data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +7 -13
- data/lib/active_record/connection_adapters/postgresql/oid/enum.rb +3 -1
- 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 -4
- data/lib/active_record/connection_adapters/postgresql/oid/point.rb +4 -4
- data/lib/active_record/connection_adapters/postgresql/oid/rails_5_1_point.rb +50 -0
- data/lib/active_record/connection_adapters/postgresql/oid/range.rb +31 -17
- data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +17 -5
- 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/oid.rb +1 -6
- data/lib/active_record/connection_adapters/postgresql/quoting.rb +26 -18
- data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +29 -10
- data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +107 -79
- data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +47 -0
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +248 -154
- data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +35 -0
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +258 -170
- data/lib/active_record/connection_adapters/schema_cache.rb +36 -23
- data/lib/active_record/connection_adapters/sql_type_metadata.rb +32 -0
- data/lib/active_record/connection_adapters/sqlite3/explain_pretty_printer.rb +19 -0
- data/lib/active_record/connection_adapters/sqlite3/quoting.rb +48 -0
- data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +22 -0
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +150 -209
- data/lib/active_record/connection_adapters/statement_pool.rb +31 -12
- data/lib/active_record/connection_handling.rb +38 -15
- data/lib/active_record/core.rb +109 -114
- data/lib/active_record/counter_cache.rb +14 -25
- data/lib/active_record/dynamic_matchers.rb +1 -20
- data/lib/active_record/enum.rb +115 -79
- data/lib/active_record/errors.rb +88 -48
- data/lib/active_record/explain_registry.rb +1 -1
- data/lib/active_record/explain_subscriber.rb +2 -2
- data/lib/active_record/fixture_set/file.rb +26 -5
- data/lib/active_record/fixtures.rb +84 -46
- data/lib/active_record/gem_version.rb +2 -2
- data/lib/active_record/inheritance.rb +32 -40
- data/lib/active_record/integration.rb +4 -4
- data/lib/active_record/internal_metadata.rb +56 -0
- data/lib/active_record/legacy_yaml_adapter.rb +46 -0
- data/lib/active_record/locale/en.yml +3 -2
- data/lib/active_record/locking/optimistic.rb +27 -25
- data/lib/active_record/locking/pessimistic.rb +1 -1
- data/lib/active_record/log_subscriber.rb +43 -21
- data/lib/active_record/migration/command_recorder.rb +59 -18
- data/lib/active_record/migration/compatibility.rb +126 -0
- data/lib/active_record/migration.rb +372 -114
- data/lib/active_record/model_schema.rb +128 -38
- data/lib/active_record/nested_attributes.rb +71 -32
- data/lib/active_record/no_touching.rb +1 -1
- data/lib/active_record/null_relation.rb +16 -8
- data/lib/active_record/persistence.rb +124 -80
- data/lib/active_record/query_cache.rb +15 -18
- data/lib/active_record/querying.rb +10 -9
- data/lib/active_record/railtie.rb +28 -19
- data/lib/active_record/railties/controller_runtime.rb +1 -1
- data/lib/active_record/railties/databases.rake +67 -51
- data/lib/active_record/readonly_attributes.rb +1 -1
- data/lib/active_record/reflection.rb +318 -139
- data/lib/active_record/relation/batches/batch_enumerator.rb +67 -0
- data/lib/active_record/relation/batches.rb +139 -34
- data/lib/active_record/relation/calculations.rb +80 -102
- data/lib/active_record/relation/delegation.rb +7 -20
- data/lib/active_record/relation/finder_methods.rb +167 -97
- data/lib/active_record/relation/from_clause.rb +32 -0
- data/lib/active_record/relation/merger.rb +38 -41
- data/lib/active_record/relation/predicate_builder/array_handler.rb +12 -16
- data/lib/active_record/relation/predicate_builder/association_query_handler.rb +88 -0
- data/lib/active_record/relation/predicate_builder/base_handler.rb +17 -0
- data/lib/active_record/relation/predicate_builder/basic_object_handler.rb +17 -0
- data/lib/active_record/relation/predicate_builder/class_handler.rb +27 -0
- data/lib/active_record/relation/predicate_builder/polymorphic_array_handler.rb +57 -0
- data/lib/active_record/relation/predicate_builder/range_handler.rb +33 -0
- data/lib/active_record/relation/predicate_builder/relation_handler.rb +1 -1
- data/lib/active_record/relation/predicate_builder.rb +124 -82
- data/lib/active_record/relation/query_attribute.rb +19 -0
- data/lib/active_record/relation/query_methods.rb +323 -257
- data/lib/active_record/relation/record_fetch_warning.rb +49 -0
- data/lib/active_record/relation/spawn_methods.rb +11 -10
- data/lib/active_record/relation/where_clause.rb +174 -0
- data/lib/active_record/relation/where_clause_factory.rb +38 -0
- data/lib/active_record/relation.rb +176 -115
- data/lib/active_record/result.rb +4 -3
- data/lib/active_record/runtime_registry.rb +1 -1
- data/lib/active_record/sanitization.rb +95 -66
- data/lib/active_record/schema.rb +26 -22
- data/lib/active_record/schema_dumper.rb +62 -38
- data/lib/active_record/schema_migration.rb +11 -17
- data/lib/active_record/scoping/default.rb +24 -9
- data/lib/active_record/scoping/named.rb +49 -28
- data/lib/active_record/scoping.rb +32 -15
- data/lib/active_record/secure_token.rb +38 -0
- data/lib/active_record/serialization.rb +2 -4
- data/lib/active_record/statement_cache.rb +16 -14
- data/lib/active_record/store.rb +8 -3
- data/lib/active_record/suppressor.rb +58 -0
- data/lib/active_record/table_metadata.rb +68 -0
- data/lib/active_record/tasks/database_tasks.rb +59 -42
- data/lib/active_record/tasks/mysql_database_tasks.rb +32 -26
- data/lib/active_record/tasks/postgresql_database_tasks.rb +29 -9
- data/lib/active_record/tasks/sqlite_database_tasks.rb +5 -1
- data/lib/active_record/timestamp.rb +20 -9
- data/lib/active_record/touch_later.rb +58 -0
- data/lib/active_record/transactions.rb +159 -67
- data/lib/active_record/type/adapter_specific_registry.rb +130 -0
- data/lib/active_record/type/date.rb +2 -41
- data/lib/active_record/type/date_time.rb +2 -38
- data/lib/active_record/type/hash_lookup_type_map.rb +8 -2
- data/lib/active_record/type/internal/abstract_json.rb +29 -0
- data/lib/active_record/type/internal/timezone.rb +15 -0
- data/lib/active_record/type/serialized.rb +21 -14
- data/lib/active_record/type/time.rb +10 -16
- data/lib/active_record/type/type_map.rb +4 -4
- data/lib/active_record/type.rb +66 -17
- data/lib/active_record/type_caster/connection.rb +29 -0
- data/lib/active_record/type_caster/map.rb +19 -0
- data/lib/active_record/type_caster.rb +7 -0
- data/lib/active_record/validations/absence.rb +23 -0
- data/lib/active_record/validations/associated.rb +10 -3
- data/lib/active_record/validations/length.rb +24 -0
- data/lib/active_record/validations/presence.rb +11 -12
- data/lib/active_record/validations/uniqueness.rb +29 -18
- data/lib/active_record/validations.rb +33 -32
- data/lib/active_record.rb +9 -2
- 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 -6
- data/lib/rails/generators/active_record/migration/templates/migration.rb +8 -7
- data/lib/rails/generators/active_record/migration.rb +7 -0
- data/lib/rails/generators/active_record/model/model_generator.rb +32 -15
- data/lib/rails/generators/active_record/model/templates/application_record.rb +5 -0
- data/lib/rails/generators/active_record/model/templates/model.rb +3 -0
- metadata +60 -34
- data/lib/active_record/connection_adapters/mysql_adapter.rb +0 -491
- 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 -30
- data/lib/active_record/type/decimal.rb +0 -40
- 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 -55
- 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 -36
- 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 -101
@@ -7,8 +7,8 @@ module ActiveRecord
|
|
7
7
|
extend ActiveSupport::Concern
|
8
8
|
|
9
9
|
included do
|
10
|
-
class_attribute :_reflections
|
11
|
-
class_attribute :aggregate_reflections
|
10
|
+
class_attribute :_reflections, instance_writer: false
|
11
|
+
class_attribute :aggregate_reflections, instance_writer: false
|
12
12
|
self._reflections = {}
|
13
13
|
self.aggregate_reflections = {}
|
14
14
|
end
|
@@ -32,6 +32,7 @@ module ActiveRecord
|
|
32
32
|
end
|
33
33
|
|
34
34
|
def self.add_reflection(ar, name, reflection)
|
35
|
+
ar.clear_reflections_cache
|
35
36
|
ar._reflections = ar._reflections.merge(name.to_s => reflection)
|
36
37
|
end
|
37
38
|
|
@@ -39,9 +40,9 @@ module ActiveRecord
|
|
39
40
|
ar.aggregate_reflections = ar.aggregate_reflections.merge(name.to_s => reflection)
|
40
41
|
end
|
41
42
|
|
42
|
-
# \Reflection enables
|
43
|
-
#
|
44
|
-
#
|
43
|
+
# \Reflection enables the ability to examine the associations and aggregations of
|
44
|
+
# Active Record classes and objects. This information, for example,
|
45
|
+
# can be used in a form builder that takes an Active Record object
|
45
46
|
# and creates input fields for all of the attributes depending on their type
|
46
47
|
# and displays the associations to other objects.
|
47
48
|
#
|
@@ -61,22 +62,27 @@ module ActiveRecord
|
|
61
62
|
aggregate_reflections[aggregation.to_s]
|
62
63
|
end
|
63
64
|
|
64
|
-
# Returns a Hash of name of the reflection as the key and
|
65
|
+
# Returns a Hash of name of the reflection as the key and an AssociationReflection as the value.
|
65
66
|
#
|
66
67
|
# Account.reflections # => {"balance" => AggregateReflection}
|
67
68
|
#
|
68
|
-
# @api public
|
69
69
|
def reflections
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
70
|
+
@__reflections ||= begin
|
71
|
+
ref = {}
|
72
|
+
|
73
|
+
_reflections.each do |name, reflection|
|
74
|
+
parent_reflection = reflection.parent_reflection
|
75
|
+
|
76
|
+
if parent_reflection
|
77
|
+
parent_name = parent_reflection.name
|
78
|
+
ref[parent_name.to_s] = parent_reflection
|
79
|
+
else
|
80
|
+
ref[name] = reflection
|
81
|
+
end
|
77
82
|
end
|
83
|
+
|
84
|
+
ref
|
78
85
|
end
|
79
|
-
ref
|
80
86
|
end
|
81
87
|
|
82
88
|
# Returns an array of AssociationReflection objects for all the
|
@@ -89,10 +95,10 @@ module ActiveRecord
|
|
89
95
|
# Account.reflect_on_all_associations # returns an array of all associations
|
90
96
|
# Account.reflect_on_all_associations(:has_many) # returns an array of all has_many associations
|
91
97
|
#
|
92
|
-
# @api public
|
93
98
|
def reflect_on_all_associations(macro = nil)
|
94
99
|
association_reflections = reflections.values
|
95
|
-
|
100
|
+
association_reflections.select! { |reflection| reflection.macro == macro } if macro
|
101
|
+
association_reflections
|
96
102
|
end
|
97
103
|
|
98
104
|
# Returns the AssociationReflection object for the +association+ (use the symbol).
|
@@ -100,27 +106,42 @@ module ActiveRecord
|
|
100
106
|
# Account.reflect_on_association(:owner) # returns the owner AssociationReflection
|
101
107
|
# Invoice.reflect_on_association(:line_items).macro # returns :has_many
|
102
108
|
#
|
103
|
-
# @api public
|
104
109
|
def reflect_on_association(association)
|
105
110
|
reflections[association.to_s]
|
106
111
|
end
|
107
112
|
|
108
|
-
# @api private
|
109
113
|
def _reflect_on_association(association) #:nodoc:
|
110
114
|
_reflections[association.to_s]
|
111
115
|
end
|
112
116
|
|
113
117
|
# Returns an array of AssociationReflection objects for all associations which have <tt>:autosave</tt> enabled.
|
114
|
-
#
|
115
|
-
# @api public
|
116
118
|
def reflect_on_all_autosave_associations
|
117
119
|
reflections.values.select { |reflection| reflection.options[:autosave] }
|
118
120
|
end
|
121
|
+
|
122
|
+
def clear_reflections_cache # :nodoc:
|
123
|
+
@__reflections = nil
|
124
|
+
end
|
119
125
|
end
|
120
126
|
|
121
|
-
# Holds all the methods that are shared between MacroReflection
|
122
|
-
#
|
127
|
+
# Holds all the methods that are shared between MacroReflection and ThroughReflection.
|
128
|
+
#
|
129
|
+
# AbstractReflection
|
130
|
+
# MacroReflection
|
131
|
+
# AggregateReflection
|
132
|
+
# AssociationReflection
|
133
|
+
# HasManyReflection
|
134
|
+
# HasOneReflection
|
135
|
+
# BelongsToReflection
|
136
|
+
# HasAndBelongsToManyReflection
|
137
|
+
# ThroughReflection
|
138
|
+
# PolymorphicReflection
|
139
|
+
# RuntimeReflection
|
123
140
|
class AbstractReflection # :nodoc:
|
141
|
+
def through_reflection?
|
142
|
+
false
|
143
|
+
end
|
144
|
+
|
124
145
|
def table_name
|
125
146
|
klass.table_name
|
126
147
|
end
|
@@ -149,29 +170,87 @@ module ActiveRecord
|
|
149
170
|
|
150
171
|
JoinKeys = Struct.new(:key, :foreign_key) # :nodoc:
|
151
172
|
|
152
|
-
def join_keys(
|
173
|
+
def join_keys(association_klass)
|
153
174
|
JoinKeys.new(foreign_key, active_record_primary_key)
|
154
175
|
end
|
155
176
|
|
156
|
-
def
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
177
|
+
def constraints
|
178
|
+
scope_chain.flatten
|
179
|
+
end
|
180
|
+
|
181
|
+
def counter_cache_column
|
182
|
+
if belongs_to?
|
183
|
+
if options[:counter_cache] == true
|
184
|
+
"#{active_record.name.demodulize.underscore.pluralize}_count"
|
185
|
+
elsif options[:counter_cache]
|
186
|
+
options[:counter_cache].to_s
|
187
|
+
end
|
188
|
+
else
|
189
|
+
options[:counter_cache] ? options[:counter_cache].to_s : "#{name}_count"
|
190
|
+
end
|
191
|
+
end
|
192
|
+
|
193
|
+
def inverse_of
|
194
|
+
return unless inverse_name
|
161
195
|
|
162
|
-
|
196
|
+
@inverse_of ||= klass._reflect_on_association inverse_name
|
197
|
+
end
|
198
|
+
|
199
|
+
def check_validity_of_inverse!
|
200
|
+
unless polymorphic?
|
201
|
+
if has_inverse? && inverse_of.nil?
|
202
|
+
raise InverseOfAssociationNotFoundError.new(self)
|
203
|
+
end
|
204
|
+
end
|
205
|
+
end
|
206
|
+
|
207
|
+
# This shit is nasty. We need to avoid the following situation:
|
208
|
+
#
|
209
|
+
# * An associated record is deleted via record.destroy
|
210
|
+
# * Hence the callbacks run, and they find a belongs_to on the record with a
|
211
|
+
# :counter_cache options which points back at our owner. So they update the
|
212
|
+
# counter cache.
|
213
|
+
# * In which case, we must make sure to *not* update the counter cache, or else
|
214
|
+
# it will be decremented twice.
|
215
|
+
#
|
216
|
+
# Hence this method.
|
217
|
+
def inverse_which_updates_counter_cache
|
218
|
+
return @inverse_which_updates_counter_cache if defined?(@inverse_which_updates_counter_cache)
|
219
|
+
@inverse_which_updates_counter_cache = klass.reflect_on_all_associations(:belongs_to).find do |inverse|
|
220
|
+
inverse.counter_cache_column == counter_cache_column
|
221
|
+
end
|
222
|
+
end
|
223
|
+
alias inverse_updates_counter_cache? inverse_which_updates_counter_cache
|
224
|
+
|
225
|
+
def inverse_updates_counter_in_memory?
|
226
|
+
inverse_of && inverse_which_updates_counter_cache == inverse_of
|
227
|
+
end
|
228
|
+
|
229
|
+
# Returns whether a counter cache should be used for this association.
|
230
|
+
#
|
231
|
+
# The counter_cache option must be given on either the owner or inverse
|
232
|
+
# association, and the column must be present on the owner.
|
233
|
+
def has_cached_counter?
|
234
|
+
options[:counter_cache] ||
|
235
|
+
inverse_which_updates_counter_cache && inverse_which_updates_counter_cache.options[:counter_cache] &&
|
236
|
+
!!active_record.columns_hash[counter_cache_column]
|
237
|
+
end
|
238
|
+
|
239
|
+
def counter_must_be_updated_by_has_many?
|
240
|
+
!inverse_updates_counter_in_memory? && has_cached_counter?
|
241
|
+
end
|
242
|
+
|
243
|
+
def alias_candidate(name)
|
244
|
+
"#{plural_name}_#{name}"
|
245
|
+
end
|
246
|
+
|
247
|
+
def chain
|
248
|
+
collect_join_chain
|
163
249
|
end
|
164
250
|
end
|
251
|
+
|
165
252
|
# Base class for AggregateReflection and AssociationReflection. Objects of
|
166
253
|
# AggregateReflection and AssociationReflection are returned by the Reflection::ClassMethods.
|
167
|
-
#
|
168
|
-
# MacroReflection
|
169
|
-
# AssociationReflection
|
170
|
-
# AggregateReflection
|
171
|
-
# HasManyReflection
|
172
|
-
# HasOneReflection
|
173
|
-
# BelongsToReflection
|
174
|
-
# ThroughReflection
|
175
254
|
class MacroReflection < AbstractReflection
|
176
255
|
# Returns the name of the macro.
|
177
256
|
#
|
@@ -196,7 +275,7 @@ module ActiveRecord
|
|
196
275
|
@scope = scope
|
197
276
|
@options = options
|
198
277
|
@active_record = active_record
|
199
|
-
@klass = options[:
|
278
|
+
@klass = options[:anonymous_class]
|
200
279
|
@plural_name = active_record.pluralize_table_names ?
|
201
280
|
name.to_s.pluralize : name.to_s
|
202
281
|
end
|
@@ -204,7 +283,7 @@ module ActiveRecord
|
|
204
283
|
def autosave=(autosave)
|
205
284
|
@automatic_inverse_of = false
|
206
285
|
@options[:autosave] = autosave
|
207
|
-
|
286
|
+
parent_reflection = self.parent_reflection
|
208
287
|
if parent_reflection
|
209
288
|
parent_reflection.autosave = autosave
|
210
289
|
end
|
@@ -272,7 +351,7 @@ module ActiveRecord
|
|
272
351
|
end
|
273
352
|
|
274
353
|
attr_reader :type, :foreign_type
|
275
|
-
attr_accessor :parent_reflection #
|
354
|
+
attr_accessor :parent_reflection # Reflection
|
276
355
|
|
277
356
|
def initialize(name, scope, options, active_record)
|
278
357
|
super
|
@@ -303,7 +382,7 @@ module ActiveRecord
|
|
303
382
|
end
|
304
383
|
|
305
384
|
def foreign_key
|
306
|
-
@foreign_key ||= options[:foreign_key] || derive_foreign_key
|
385
|
+
@foreign_key ||= options[:foreign_key] || derive_foreign_key.freeze
|
307
386
|
end
|
308
387
|
|
309
388
|
def association_foreign_key
|
@@ -319,37 +398,18 @@ module ActiveRecord
|
|
319
398
|
@active_record_primary_key ||= options[:primary_key] || primary_key(active_record)
|
320
399
|
end
|
321
400
|
|
322
|
-
def counter_cache_column
|
323
|
-
if options[:counter_cache] == true
|
324
|
-
"#{active_record.name.demodulize.underscore.pluralize}_count"
|
325
|
-
elsif options[:counter_cache]
|
326
|
-
options[:counter_cache].to_s
|
327
|
-
end
|
328
|
-
end
|
329
|
-
|
330
401
|
def check_validity!
|
331
402
|
check_validity_of_inverse!
|
332
403
|
end
|
333
404
|
|
334
|
-
def check_validity_of_inverse!
|
335
|
-
unless polymorphic?
|
336
|
-
if has_inverse? && inverse_of.nil?
|
337
|
-
raise InverseOfAssociationNotFoundError.new(self)
|
338
|
-
end
|
339
|
-
end
|
340
|
-
end
|
341
|
-
|
342
405
|
def check_preloadable!
|
343
406
|
return unless scope
|
344
407
|
|
345
408
|
if scope.arity > 0
|
346
|
-
|
409
|
+
raise ArgumentError, <<-MSG.squish
|
347
410
|
The association scope '#{name}' is instance dependent (the scope
|
348
|
-
block takes an argument). Preloading
|
349
|
-
|
350
|
-
passed to the association scope. This will most likely result in
|
351
|
-
broken or incorrect behavior. Joining, Preloading and eager loading
|
352
|
-
of these associations is deprecated and will be removed in the future.
|
411
|
+
block takes an argument). Preloading instance dependent scopes is
|
412
|
+
not supported.
|
353
413
|
MSG
|
354
414
|
end
|
355
415
|
end
|
@@ -369,10 +429,16 @@ module ActiveRecord
|
|
369
429
|
|
370
430
|
# A chain of reflections from this one back to the owner. For more see the explanation in
|
371
431
|
# ThroughReflection.
|
372
|
-
def
|
432
|
+
def collect_join_chain
|
373
433
|
[self]
|
374
434
|
end
|
375
435
|
|
436
|
+
# This is for clearing cache on the reflection. Useful for tests that need to compare
|
437
|
+
# SQL queries on associations.
|
438
|
+
def clear_association_scope_cache # :nodoc:
|
439
|
+
@association_scope_cache.clear
|
440
|
+
end
|
441
|
+
|
376
442
|
def nested?
|
377
443
|
false
|
378
444
|
end
|
@@ -383,14 +449,12 @@ module ActiveRecord
|
|
383
449
|
scope ? [[scope]] : [[]]
|
384
450
|
end
|
385
451
|
|
386
|
-
def
|
387
|
-
|
452
|
+
def has_scope?
|
453
|
+
scope
|
388
454
|
end
|
389
455
|
|
390
|
-
def
|
391
|
-
|
392
|
-
|
393
|
-
@inverse_of ||= klass._reflect_on_association inverse_name
|
456
|
+
def has_inverse?
|
457
|
+
inverse_name
|
394
458
|
end
|
395
459
|
|
396
460
|
def polymorphic_inverse_of(associated_class)
|
@@ -434,28 +498,7 @@ module ActiveRecord
|
|
434
498
|
# Returns +true+ if +self+ is a +has_one+ reflection.
|
435
499
|
def has_one?; false; end
|
436
500
|
|
437
|
-
def association_class
|
438
|
-
case macro
|
439
|
-
when :belongs_to
|
440
|
-
if polymorphic?
|
441
|
-
Associations::BelongsToPolymorphicAssociation
|
442
|
-
else
|
443
|
-
Associations::BelongsToAssociation
|
444
|
-
end
|
445
|
-
when :has_many
|
446
|
-
if options[:through]
|
447
|
-
Associations::HasManyThroughAssociation
|
448
|
-
else
|
449
|
-
Associations::HasManyAssociation
|
450
|
-
end
|
451
|
-
when :has_one
|
452
|
-
if options[:through]
|
453
|
-
Associations::HasOneThroughAssociation
|
454
|
-
else
|
455
|
-
Associations::HasOneAssociation
|
456
|
-
end
|
457
|
-
end
|
458
|
-
end
|
501
|
+
def association_class; raise NotImplementedError; end
|
459
502
|
|
460
503
|
def polymorphic?
|
461
504
|
options[:polymorphic]
|
@@ -464,6 +507,18 @@ module ActiveRecord
|
|
464
507
|
VALID_AUTOMATIC_INVERSE_MACROS = [:has_many, :has_one, :belongs_to]
|
465
508
|
INVALID_AUTOMATIC_INVERSE_OPTIONS = [:conditions, :through, :polymorphic, :foreign_key]
|
466
509
|
|
510
|
+
def add_as_source(seed)
|
511
|
+
seed
|
512
|
+
end
|
513
|
+
|
514
|
+
def add_as_polymorphic_through(reflection, seed)
|
515
|
+
seed + [PolymorphicReflection.new(self, reflection)]
|
516
|
+
end
|
517
|
+
|
518
|
+
def add_as_through(seed)
|
519
|
+
seed + [self]
|
520
|
+
end
|
521
|
+
|
467
522
|
protected
|
468
523
|
|
469
524
|
def actual_source_reflection # FIXME: this is a horrible name
|
@@ -473,14 +528,7 @@ module ActiveRecord
|
|
473
528
|
private
|
474
529
|
|
475
530
|
def calculate_constructable(macro, options)
|
476
|
-
|
477
|
-
when :belongs_to
|
478
|
-
!polymorphic?
|
479
|
-
when :has_one
|
480
|
-
!options[:through]
|
481
|
-
else
|
482
|
-
true
|
483
|
-
end
|
531
|
+
true
|
484
532
|
end
|
485
533
|
|
486
534
|
# Attempts to find the inverse association name automatically.
|
@@ -496,10 +544,10 @@ module ActiveRecord
|
|
496
544
|
end
|
497
545
|
end
|
498
546
|
|
499
|
-
# returns either
|
547
|
+
# returns either false or the inverse association name that it finds.
|
500
548
|
def automatic_inverse_of
|
501
549
|
if can_find_inverse_of_automatically?(self)
|
502
|
-
inverse_name = ActiveSupport::Inflector.underscore(options[:as] || active_record.name).to_sym
|
550
|
+
inverse_name = ActiveSupport::Inflector.underscore(options[:as] || active_record.name.demodulize).to_sym
|
503
551
|
|
504
552
|
begin
|
505
553
|
reflection = klass._reflect_on_association(inverse_name)
|
@@ -573,42 +621,66 @@ module ActiveRecord
|
|
573
621
|
end
|
574
622
|
|
575
623
|
class HasManyReflection < AssociationReflection # :nodoc:
|
576
|
-
def initialize(name, scope, options, active_record)
|
577
|
-
super(name, scope, options, active_record)
|
578
|
-
end
|
579
|
-
|
580
624
|
def macro; :has_many; end
|
581
625
|
|
582
626
|
def collection?; true; end
|
583
|
-
end
|
584
627
|
|
585
|
-
|
586
|
-
|
587
|
-
|
628
|
+
def association_class
|
629
|
+
if options[:through]
|
630
|
+
Associations::HasManyThroughAssociation
|
631
|
+
else
|
632
|
+
Associations::HasManyAssociation
|
633
|
+
end
|
588
634
|
end
|
635
|
+
end
|
589
636
|
|
637
|
+
class HasOneReflection < AssociationReflection # :nodoc:
|
590
638
|
def macro; :has_one; end
|
591
639
|
|
592
640
|
def has_one?; true; end
|
593
|
-
end
|
594
641
|
|
595
|
-
|
596
|
-
|
597
|
-
|
642
|
+
def association_class
|
643
|
+
if options[:through]
|
644
|
+
Associations::HasOneThroughAssociation
|
645
|
+
else
|
646
|
+
Associations::HasOneAssociation
|
647
|
+
end
|
598
648
|
end
|
599
649
|
|
650
|
+
private
|
651
|
+
|
652
|
+
def calculate_constructable(macro, options)
|
653
|
+
!options[:through]
|
654
|
+
end
|
655
|
+
end
|
656
|
+
|
657
|
+
class BelongsToReflection < AssociationReflection # :nodoc:
|
600
658
|
def macro; :belongs_to; end
|
601
659
|
|
602
660
|
def belongs_to?; true; end
|
603
661
|
|
604
|
-
def
|
605
|
-
|
662
|
+
def association_class
|
663
|
+
if polymorphic?
|
664
|
+
Associations::BelongsToPolymorphicAssociation
|
665
|
+
else
|
666
|
+
Associations::BelongsToAssociation
|
667
|
+
end
|
668
|
+
end
|
669
|
+
|
670
|
+
def join_keys(association_klass)
|
671
|
+
key = polymorphic? ? association_primary_key(association_klass) : association_primary_key
|
606
672
|
JoinKeys.new(key, foreign_key)
|
607
673
|
end
|
608
674
|
|
609
675
|
def join_id_for(owner) # :nodoc:
|
610
676
|
owner[foreign_key]
|
611
677
|
end
|
678
|
+
|
679
|
+
private
|
680
|
+
|
681
|
+
def calculate_constructable(macro, options)
|
682
|
+
!polymorphic?
|
683
|
+
end
|
612
684
|
end
|
613
685
|
|
614
686
|
class HasAndBelongsToManyReflection < AssociationReflection # :nodoc:
|
@@ -632,10 +704,14 @@ module ActiveRecord
|
|
632
704
|
|
633
705
|
def initialize(delegate_reflection)
|
634
706
|
@delegate_reflection = delegate_reflection
|
635
|
-
@klass = delegate_reflection.options[:
|
707
|
+
@klass = delegate_reflection.options[:anonymous_class]
|
636
708
|
@source_reflection_name = delegate_reflection.options[:source]
|
637
709
|
end
|
638
710
|
|
711
|
+
def through_reflection?
|
712
|
+
true
|
713
|
+
end
|
714
|
+
|
639
715
|
def klass
|
640
716
|
@klass ||= delegate_reflection.compute_class(class_name)
|
641
717
|
end
|
@@ -694,14 +770,16 @@ module ActiveRecord
|
|
694
770
|
# # => [<ActiveRecord::Reflection::ThroughReflection: @delegate_reflection=#<ActiveRecord::Reflection::HasManyReflection: @name=:tags...>,
|
695
771
|
# <ActiveRecord::Reflection::HasManyReflection: @name=:taggings, @options={}, @active_record=Post>]
|
696
772
|
#
|
697
|
-
def
|
698
|
-
|
699
|
-
|
700
|
-
|
701
|
-
|
702
|
-
|
703
|
-
|
704
|
-
|
773
|
+
def collect_join_chain
|
774
|
+
collect_join_reflections [self]
|
775
|
+
end
|
776
|
+
|
777
|
+
# This is for clearing cache on the reflection. Useful for tests that need to compare
|
778
|
+
# SQL queries on associations.
|
779
|
+
def clear_association_scope_cache # :nodoc:
|
780
|
+
delegate_reflection.clear_association_scope_cache
|
781
|
+
source_reflection.clear_association_scope_cache
|
782
|
+
through_reflection.clear_association_scope_cache
|
705
783
|
end
|
706
784
|
|
707
785
|
# Consider the following example:
|
@@ -745,23 +823,19 @@ module ActiveRecord
|
|
745
823
|
end
|
746
824
|
end
|
747
825
|
|
748
|
-
def
|
749
|
-
|
826
|
+
def has_scope?
|
827
|
+
scope || options[:source_type] ||
|
828
|
+
source_reflection.has_scope? ||
|
829
|
+
through_reflection.has_scope?
|
750
830
|
end
|
751
831
|
|
752
|
-
|
753
|
-
|
754
|
-
ActiveSupport::Deprecation.warn(<<-MSG.squish)
|
755
|
-
ActiveRecord::Base.source_macro is deprecated and will be removed
|
756
|
-
without replacement.
|
757
|
-
MSG
|
758
|
-
|
759
|
-
source_reflection.source_macro
|
832
|
+
def join_keys(association_klass)
|
833
|
+
source_reflection.join_keys(association_klass)
|
760
834
|
end
|
761
835
|
|
762
836
|
# A through association is nested if there would be more than one join table
|
763
837
|
def nested?
|
764
|
-
|
838
|
+
source_reflection.through_reflection? || through_reflection.through_reflection?
|
765
839
|
end
|
766
840
|
|
767
841
|
# We want to use the klass from this reflection, rather than just delegate straight to
|
@@ -791,7 +865,7 @@ module ActiveRecord
|
|
791
865
|
def source_reflection_name # :nodoc:
|
792
866
|
return @source_reflection_name if @source_reflection_name
|
793
867
|
|
794
|
-
names = [name.to_s.singularize, name].collect
|
868
|
+
names = [name.to_s.singularize, name].collect(&:to_sym).uniq
|
795
869
|
names = names.find_all { |n|
|
796
870
|
through_reflection.klass._reflect_on_association(n)
|
797
871
|
}
|
@@ -800,7 +874,7 @@ module ActiveRecord
|
|
800
874
|
example_options = options.dup
|
801
875
|
example_options[:source] = source_reflection_names.first
|
802
876
|
ActiveSupport::Deprecation.warn \
|
803
|
-
"Ambiguous source reflection for through association.
|
877
|
+
"Ambiguous source reflection for through association. Please " \
|
804
878
|
"specify a :source directive on your declaration like:\n" \
|
805
879
|
"\n" \
|
806
880
|
" class #{active_record.name} < ActiveRecord::Base\n" \
|
@@ -855,6 +929,33 @@ module ActiveRecord
|
|
855
929
|
check_validity_of_inverse!
|
856
930
|
end
|
857
931
|
|
932
|
+
def constraints
|
933
|
+
scope_chain = source_reflection.constraints
|
934
|
+
scope_chain << scope if scope
|
935
|
+
scope_chain
|
936
|
+
end
|
937
|
+
|
938
|
+
def add_as_source(seed)
|
939
|
+
collect_join_reflections seed
|
940
|
+
end
|
941
|
+
|
942
|
+
def add_as_polymorphic_through(reflection, seed)
|
943
|
+
collect_join_reflections(seed + [PolymorphicReflection.new(self, reflection)])
|
944
|
+
end
|
945
|
+
|
946
|
+
def add_as_through(seed)
|
947
|
+
collect_join_reflections(seed + [self])
|
948
|
+
end
|
949
|
+
|
950
|
+
def collect_join_reflections(seed)
|
951
|
+
a = source_reflection.add_as_source seed
|
952
|
+
if options[:source_type]
|
953
|
+
through_reflection.add_as_polymorphic_through self, a
|
954
|
+
else
|
955
|
+
through_reflection.add_as_through a
|
956
|
+
end
|
957
|
+
end
|
958
|
+
|
858
959
|
protected
|
859
960
|
|
860
961
|
def actual_source_reflection # FIXME: this is a horrible name
|
@@ -865,6 +966,8 @@ module ActiveRecord
|
|
865
966
|
klass.primary_key || raise(UnknownPrimaryKey.new(klass))
|
866
967
|
end
|
867
968
|
|
969
|
+
def inverse_name; delegate_reflection.send(:inverse_name); end
|
970
|
+
|
868
971
|
private
|
869
972
|
def derive_class_name
|
870
973
|
# get the class_name of the belongs_to association of the through reflection
|
@@ -877,5 +980,81 @@ module ActiveRecord
|
|
877
980
|
delegate(*delegate_methods, to: :delegate_reflection)
|
878
981
|
|
879
982
|
end
|
983
|
+
|
984
|
+
class PolymorphicReflection < ThroughReflection # :nodoc:
|
985
|
+
def initialize(reflection, previous_reflection)
|
986
|
+
@reflection = reflection
|
987
|
+
@previous_reflection = previous_reflection
|
988
|
+
end
|
989
|
+
|
990
|
+
def klass
|
991
|
+
@reflection.klass
|
992
|
+
end
|
993
|
+
|
994
|
+
def scope
|
995
|
+
@reflection.scope
|
996
|
+
end
|
997
|
+
|
998
|
+
def table_name
|
999
|
+
@reflection.table_name
|
1000
|
+
end
|
1001
|
+
|
1002
|
+
def plural_name
|
1003
|
+
@reflection.plural_name
|
1004
|
+
end
|
1005
|
+
|
1006
|
+
def join_keys(association_klass)
|
1007
|
+
@reflection.join_keys(association_klass)
|
1008
|
+
end
|
1009
|
+
|
1010
|
+
def type
|
1011
|
+
@reflection.type
|
1012
|
+
end
|
1013
|
+
|
1014
|
+
def constraints
|
1015
|
+
@reflection.constraints + [source_type_info]
|
1016
|
+
end
|
1017
|
+
|
1018
|
+
def source_type_info
|
1019
|
+
type = @previous_reflection.foreign_type
|
1020
|
+
source_type = @previous_reflection.options[:source_type]
|
1021
|
+
lambda { |object| where(type => source_type) }
|
1022
|
+
end
|
1023
|
+
end
|
1024
|
+
|
1025
|
+
class RuntimeReflection < PolymorphicReflection # :nodoc:
|
1026
|
+
attr_accessor :next
|
1027
|
+
|
1028
|
+
def initialize(reflection, association)
|
1029
|
+
@reflection = reflection
|
1030
|
+
@association = association
|
1031
|
+
end
|
1032
|
+
|
1033
|
+
def klass
|
1034
|
+
@association.klass
|
1035
|
+
end
|
1036
|
+
|
1037
|
+
def table_name
|
1038
|
+
klass.table_name
|
1039
|
+
end
|
1040
|
+
|
1041
|
+
def constraints
|
1042
|
+
@reflection.constraints
|
1043
|
+
end
|
1044
|
+
|
1045
|
+
def source_type_info
|
1046
|
+
@reflection.source_type_info
|
1047
|
+
end
|
1048
|
+
|
1049
|
+
def alias_candidate(name)
|
1050
|
+
"#{plural_name}_#{name}_join"
|
1051
|
+
end
|
1052
|
+
|
1053
|
+
def alias_name
|
1054
|
+
Arel::Table.new(table_name)
|
1055
|
+
end
|
1056
|
+
|
1057
|
+
def all_includes; yield; end
|
1058
|
+
end
|
880
1059
|
end
|
881
1060
|
end
|