activerecord 4.1.0 → 4.2.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 +776 -1330
- data/README.rdoc +15 -10
- data/lib/active_record/aggregations.rb +12 -8
- data/lib/active_record/association_relation.rb +4 -0
- data/lib/active_record/associations/alias_tracker.rb +14 -13
- data/lib/active_record/associations/association.rb +2 -2
- data/lib/active_record/associations/association_scope.rb +83 -43
- data/lib/active_record/associations/belongs_to_association.rb +15 -5
- data/lib/active_record/associations/builder/association.rb +15 -4
- data/lib/active_record/associations/builder/belongs_to.rb +7 -29
- data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +9 -6
- data/lib/active_record/associations/builder/has_many.rb +1 -1
- data/lib/active_record/associations/builder/has_one.rb +2 -2
- data/lib/active_record/associations/builder/singular_association.rb +8 -1
- data/lib/active_record/associations/collection_association.rb +66 -29
- data/lib/active_record/associations/collection_proxy.rb +22 -26
- data/lib/active_record/associations/has_many_association.rb +65 -18
- data/lib/active_record/associations/has_many_through_association.rb +55 -27
- data/lib/active_record/associations/has_one_association.rb +0 -1
- data/lib/active_record/associations/join_dependency/join_association.rb +19 -15
- data/lib/active_record/associations/join_dependency/join_part.rb +0 -1
- data/lib/active_record/associations/join_dependency.rb +20 -12
- data/lib/active_record/associations/preloader/association.rb +34 -11
- data/lib/active_record/associations/preloader/through_association.rb +4 -3
- data/lib/active_record/associations/preloader.rb +49 -59
- data/lib/active_record/associations/singular_association.rb +25 -4
- data/lib/active_record/associations/through_association.rb +23 -14
- data/lib/active_record/associations.rb +171 -42
- data/lib/active_record/attribute.rb +149 -0
- data/lib/active_record/attribute_assignment.rb +18 -10
- data/lib/active_record/attribute_decorators.rb +66 -0
- data/lib/active_record/attribute_methods/before_type_cast.rb +2 -2
- data/lib/active_record/attribute_methods/dirty.rb +98 -44
- data/lib/active_record/attribute_methods/primary_key.rb +14 -8
- data/lib/active_record/attribute_methods/query.rb +1 -1
- data/lib/active_record/attribute_methods/read.rb +22 -59
- data/lib/active_record/attribute_methods/serialization.rb +37 -147
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +34 -28
- data/lib/active_record/attribute_methods/write.rb +14 -21
- data/lib/active_record/attribute_methods.rb +67 -94
- data/lib/active_record/attribute_set/builder.rb +86 -0
- data/lib/active_record/attribute_set.rb +77 -0
- data/lib/active_record/attributes.rb +139 -0
- data/lib/active_record/autosave_association.rb +45 -38
- data/lib/active_record/base.rb +10 -20
- data/lib/active_record/callbacks.rb +7 -7
- data/lib/active_record/coders/json.rb +13 -0
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +78 -52
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +38 -59
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +1 -0
- data/lib/active_record/connection_adapters/abstract/quoting.rb +59 -55
- data/lib/active_record/connection_adapters/abstract/schema_creation.rb +46 -5
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +126 -54
- data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +14 -34
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +198 -64
- data/lib/active_record/connection_adapters/abstract/transaction.rb +126 -114
- data/lib/active_record/connection_adapters/abstract_adapter.rb +154 -55
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +240 -135
- data/lib/active_record/connection_adapters/column.rb +28 -239
- data/lib/active_record/connection_adapters/connection_specification.rb +16 -25
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +20 -22
- data/lib/active_record/connection_adapters/mysql_adapter.rb +65 -149
- data/lib/active_record/connection_adapters/postgresql/array_parser.rb +15 -27
- data/lib/active_record/connection_adapters/postgresql/column.rb +20 -0
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +39 -27
- data/lib/active_record/connection_adapters/postgresql/oid/array.rb +99 -0
- data/lib/active_record/connection_adapters/postgresql/oid/bit.rb +52 -0
- data/lib/active_record/connection_adapters/postgresql/oid/bit_varying.rb +13 -0
- data/lib/active_record/connection_adapters/postgresql/oid/bytea.rb +14 -0
- data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +46 -0
- data/lib/active_record/connection_adapters/postgresql/oid/date.rb +11 -0
- data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +27 -0
- data/lib/active_record/connection_adapters/postgresql/oid/decimal.rb +13 -0
- data/lib/active_record/connection_adapters/postgresql/oid/enum.rb +17 -0
- data/lib/active_record/connection_adapters/postgresql/oid/float.rb +21 -0
- data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +59 -0
- data/lib/active_record/connection_adapters/postgresql/oid/inet.rb +13 -0
- data/lib/active_record/connection_adapters/postgresql/oid/infinity.rb +13 -0
- data/lib/active_record/connection_adapters/postgresql/oid/integer.rb +11 -0
- data/lib/active_record/connection_adapters/postgresql/oid/json.rb +35 -0
- data/lib/active_record/connection_adapters/postgresql/oid/jsonb.rb +23 -0
- data/lib/active_record/connection_adapters/postgresql/oid/money.rb +43 -0
- data/lib/active_record/connection_adapters/postgresql/oid/point.rb +43 -0
- data/lib/active_record/connection_adapters/postgresql/oid/range.rb +79 -0
- data/lib/active_record/connection_adapters/postgresql/oid/specialized_string.rb +15 -0
- data/lib/active_record/connection_adapters/postgresql/oid/time.rb +11 -0
- data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +97 -0
- data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +21 -0
- data/lib/active_record/connection_adapters/postgresql/oid/vector.rb +26 -0
- data/lib/active_record/connection_adapters/postgresql/oid/xml.rb +28 -0
- data/lib/active_record/connection_adapters/postgresql/oid.rb +29 -374
- data/lib/active_record/connection_adapters/postgresql/quoting.rb +55 -135
- data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +4 -4
- data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +152 -0
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +127 -38
- data/lib/active_record/connection_adapters/postgresql/utils.rb +77 -0
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +220 -466
- data/lib/active_record/connection_adapters/schema_cache.rb +14 -28
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +66 -61
- data/lib/active_record/connection_handling.rb +3 -3
- data/lib/active_record/core.rb +143 -32
- data/lib/active_record/counter_cache.rb +60 -7
- data/lib/active_record/enum.rb +10 -11
- data/lib/active_record/errors.rb +49 -27
- data/lib/active_record/explain.rb +1 -1
- data/lib/active_record/fixtures.rb +56 -70
- data/lib/active_record/gem_version.rb +2 -2
- data/lib/active_record/inheritance.rb +35 -10
- data/lib/active_record/integration.rb +4 -4
- data/lib/active_record/locking/optimistic.rb +35 -17
- data/lib/active_record/log_subscriber.rb +1 -1
- data/lib/active_record/migration/command_recorder.rb +19 -2
- data/lib/active_record/migration/join_table.rb +1 -1
- data/lib/active_record/migration.rb +52 -49
- data/lib/active_record/model_schema.rb +49 -57
- data/lib/active_record/nested_attributes.rb +7 -7
- data/lib/active_record/null_relation.rb +19 -5
- data/lib/active_record/persistence.rb +50 -31
- data/lib/active_record/query_cache.rb +3 -3
- data/lib/active_record/querying.rb +10 -7
- data/lib/active_record/railtie.rb +14 -11
- data/lib/active_record/railties/databases.rake +56 -54
- data/lib/active_record/readonly_attributes.rb +0 -1
- data/lib/active_record/reflection.rb +286 -102
- data/lib/active_record/relation/batches.rb +0 -1
- data/lib/active_record/relation/calculations.rb +39 -31
- data/lib/active_record/relation/delegation.rb +2 -2
- data/lib/active_record/relation/finder_methods.rb +80 -36
- data/lib/active_record/relation/merger.rb +25 -30
- data/lib/active_record/relation/predicate_builder/array_handler.rb +31 -13
- data/lib/active_record/relation/predicate_builder/relation_handler.rb +1 -1
- data/lib/active_record/relation/predicate_builder.rb +11 -10
- data/lib/active_record/relation/query_methods.rb +141 -55
- data/lib/active_record/relation/spawn_methods.rb +3 -0
- data/lib/active_record/relation.rb +69 -30
- data/lib/active_record/result.rb +18 -7
- data/lib/active_record/sanitization.rb +12 -2
- data/lib/active_record/schema.rb +0 -1
- data/lib/active_record/schema_dumper.rb +58 -26
- data/lib/active_record/schema_migration.rb +11 -0
- data/lib/active_record/scoping/default.rb +8 -7
- data/lib/active_record/scoping/named.rb +4 -0
- data/lib/active_record/serializers/xml_serializer.rb +3 -7
- data/lib/active_record/statement_cache.rb +95 -10
- data/lib/active_record/store.rb +19 -10
- data/lib/active_record/tasks/database_tasks.rb +73 -7
- data/lib/active_record/tasks/mysql_database_tasks.rb +3 -2
- data/lib/active_record/tasks/postgresql_database_tasks.rb +1 -1
- data/lib/active_record/tasks/sqlite_database_tasks.rb +5 -1
- data/lib/active_record/timestamp.rb +11 -9
- data/lib/active_record/transactions.rb +37 -21
- data/lib/active_record/type/big_integer.rb +13 -0
- data/lib/active_record/type/binary.rb +50 -0
- data/lib/active_record/type/boolean.rb +30 -0
- data/lib/active_record/type/date.rb +46 -0
- data/lib/active_record/type/date_time.rb +43 -0
- data/lib/active_record/type/decimal.rb +40 -0
- data/lib/active_record/type/decimal_without_scale.rb +11 -0
- data/lib/active_record/type/decorator.rb +14 -0
- data/lib/active_record/type/float.rb +19 -0
- data/lib/active_record/type/hash_lookup_type_map.rb +17 -0
- data/lib/active_record/type/integer.rb +55 -0
- data/lib/active_record/type/mutable.rb +16 -0
- data/lib/active_record/type/numeric.rb +36 -0
- data/lib/active_record/type/serialized.rb +56 -0
- data/lib/active_record/type/string.rb +36 -0
- data/lib/active_record/type/text.rb +11 -0
- data/lib/active_record/type/time.rb +26 -0
- data/lib/active_record/type/time_value.rb +38 -0
- data/lib/active_record/type/type_map.rb +64 -0
- data/lib/active_record/type/unsigned_integer.rb +15 -0
- data/lib/active_record/type/value.rb +101 -0
- data/lib/active_record/type.rb +23 -0
- data/lib/active_record/validations/associated.rb +5 -3
- data/lib/active_record/validations/presence.rb +6 -4
- data/lib/active_record/validations/uniqueness.rb +11 -17
- data/lib/active_record/validations.rb +25 -19
- data/lib/active_record.rb +3 -0
- data/lib/rails/generators/active_record/migration/migration_generator.rb +8 -4
- data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb +4 -1
- data/lib/rails/generators/active_record/migration/templates/migration.rb +6 -0
- data/lib/rails/generators/active_record/model/templates/model.rb +1 -1
- metadata +65 -10
- data/lib/active_record/connection_adapters/postgresql/cast.rb +0 -168
@@ -1,35 +1,45 @@
|
|
1
|
+
require 'thread'
|
2
|
+
require 'active_support/core_ext/string/filters'
|
3
|
+
|
1
4
|
module ActiveRecord
|
2
5
|
# = Active Record Reflection
|
3
6
|
module Reflection # :nodoc:
|
4
7
|
extend ActiveSupport::Concern
|
5
8
|
|
6
9
|
included do
|
7
|
-
class_attribute :
|
10
|
+
class_attribute :_reflections
|
8
11
|
class_attribute :aggregate_reflections
|
9
|
-
self.
|
12
|
+
self._reflections = {}
|
10
13
|
self.aggregate_reflections = {}
|
11
14
|
end
|
12
15
|
|
13
16
|
def self.create(macro, name, scope, options, ar)
|
14
|
-
case macro
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
17
|
+
klass = case macro
|
18
|
+
when :composed_of
|
19
|
+
AggregateReflection
|
20
|
+
when :has_many
|
21
|
+
HasManyReflection
|
22
|
+
when :has_one
|
23
|
+
HasOneReflection
|
24
|
+
when :belongs_to
|
25
|
+
BelongsToReflection
|
26
|
+
else
|
27
|
+
raise "Unsupported Macro: #{macro}"
|
28
|
+
end
|
29
|
+
|
30
|
+
reflection = klass.new(name, scope, options, ar)
|
31
|
+
options[:through] ? ThroughReflection.new(reflection) : reflection
|
22
32
|
end
|
23
33
|
|
24
34
|
def self.add_reflection(ar, name, reflection)
|
25
|
-
ar.
|
35
|
+
ar._reflections = ar._reflections.merge(name.to_s => reflection)
|
26
36
|
end
|
27
37
|
|
28
38
|
def self.add_aggregate_reflection(ar, name, reflection)
|
29
|
-
ar.aggregate_reflections = ar.aggregate_reflections.merge(name => reflection)
|
39
|
+
ar.aggregate_reflections = ar.aggregate_reflections.merge(name.to_s => reflection)
|
30
40
|
end
|
31
41
|
|
32
|
-
# \Reflection enables
|
42
|
+
# \Reflection enables interrogating of Active Record classes and objects
|
33
43
|
# about their associations and aggregations. This information can,
|
34
44
|
# for example, be used in a form builder that takes an Active Record object
|
35
45
|
# and creates input fields for all of the attributes depending on their type
|
@@ -48,7 +58,25 @@ module ActiveRecord
|
|
48
58
|
# Account.reflect_on_aggregation(:balance) # => the balance AggregateReflection
|
49
59
|
#
|
50
60
|
def reflect_on_aggregation(aggregation)
|
51
|
-
aggregate_reflections[aggregation]
|
61
|
+
aggregate_reflections[aggregation.to_s]
|
62
|
+
end
|
63
|
+
|
64
|
+
# Returns a Hash of name of the reflection as the key and a AssociationReflection as the value.
|
65
|
+
#
|
66
|
+
# Account.reflections # => {"balance" => AggregateReflection}
|
67
|
+
#
|
68
|
+
# @api public
|
69
|
+
def reflections
|
70
|
+
ref = {}
|
71
|
+
_reflections.each do |name, reflection|
|
72
|
+
parent_name, parent_reflection = reflection.parent_reflection
|
73
|
+
if parent_name
|
74
|
+
ref[parent_name] = parent_reflection
|
75
|
+
else
|
76
|
+
ref[name] = reflection
|
77
|
+
end
|
78
|
+
end
|
79
|
+
ref
|
52
80
|
end
|
53
81
|
|
54
82
|
# Returns an array of AssociationReflection objects for all the
|
@@ -61,6 +89,7 @@ module ActiveRecord
|
|
61
89
|
# Account.reflect_on_all_associations # returns an array of all associations
|
62
90
|
# Account.reflect_on_all_associations(:has_many) # returns an array of all has_many associations
|
63
91
|
#
|
92
|
+
# @api public
|
64
93
|
def reflect_on_all_associations(macro = nil)
|
65
94
|
association_reflections = reflections.values
|
66
95
|
macro ? association_reflections.select { |reflection| reflection.macro == macro } : association_reflections
|
@@ -71,36 +100,85 @@ module ActiveRecord
|
|
71
100
|
# Account.reflect_on_association(:owner) # returns the owner AssociationReflection
|
72
101
|
# Invoice.reflect_on_association(:line_items).macro # returns :has_many
|
73
102
|
#
|
103
|
+
# @api public
|
74
104
|
def reflect_on_association(association)
|
75
|
-
reflections[association]
|
105
|
+
reflections[association.to_s]
|
106
|
+
end
|
107
|
+
|
108
|
+
# @api private
|
109
|
+
def _reflect_on_association(association) #:nodoc:
|
110
|
+
_reflections[association.to_s]
|
76
111
|
end
|
77
112
|
|
78
113
|
# Returns an array of AssociationReflection objects for all associations which have <tt>:autosave</tt> enabled.
|
114
|
+
#
|
115
|
+
# @api public
|
79
116
|
def reflect_on_all_autosave_associations
|
80
117
|
reflections.values.select { |reflection| reflection.options[:autosave] }
|
81
118
|
end
|
82
119
|
end
|
83
120
|
|
121
|
+
# Holds all the methods that are shared between MacroReflection, AssociationReflection
|
122
|
+
# and ThroughReflection
|
123
|
+
class AbstractReflection # :nodoc:
|
124
|
+
def table_name
|
125
|
+
klass.table_name
|
126
|
+
end
|
127
|
+
|
128
|
+
# Returns a new, unsaved instance of the associated class. +attributes+ will
|
129
|
+
# be passed to the class's constructor.
|
130
|
+
def build_association(attributes, &block)
|
131
|
+
klass.new(attributes, &block)
|
132
|
+
end
|
133
|
+
|
134
|
+
def quoted_table_name
|
135
|
+
klass.quoted_table_name
|
136
|
+
end
|
137
|
+
|
138
|
+
def primary_key_type
|
139
|
+
klass.type_for_attribute(klass.primary_key)
|
140
|
+
end
|
141
|
+
|
142
|
+
# Returns the class name for the macro.
|
143
|
+
#
|
144
|
+
# <tt>composed_of :balance, class_name: 'Money'</tt> returns <tt>'Money'</tt>
|
145
|
+
# <tt>has_many :clients</tt> returns <tt>'Client'</tt>
|
146
|
+
def class_name
|
147
|
+
@class_name ||= (options[:class_name] || derive_class_name).to_s
|
148
|
+
end
|
149
|
+
|
150
|
+
JoinKeys = Struct.new(:key, :foreign_key) # :nodoc:
|
151
|
+
|
152
|
+
def join_keys(assoc_klass)
|
153
|
+
JoinKeys.new(foreign_key, active_record_primary_key)
|
154
|
+
end
|
155
|
+
|
156
|
+
def source_macro
|
157
|
+
ActiveSupport::Deprecation.warn(<<-MSG.squish)
|
158
|
+
ActiveRecord::Base.source_macro is deprecated and will be removed
|
159
|
+
without replacement.
|
160
|
+
MSG
|
161
|
+
|
162
|
+
macro
|
163
|
+
end
|
164
|
+
end
|
84
165
|
# Base class for AggregateReflection and AssociationReflection. Objects of
|
85
166
|
# AggregateReflection and AssociationReflection are returned by the Reflection::ClassMethods.
|
86
167
|
#
|
87
168
|
# MacroReflection
|
88
|
-
# AggregateReflection
|
89
169
|
# AssociationReflection
|
90
|
-
#
|
91
|
-
|
170
|
+
# AggregateReflection
|
171
|
+
# HasManyReflection
|
172
|
+
# HasOneReflection
|
173
|
+
# BelongsToReflection
|
174
|
+
# ThroughReflection
|
175
|
+
class MacroReflection < AbstractReflection
|
92
176
|
# Returns the name of the macro.
|
93
177
|
#
|
94
178
|
# <tt>composed_of :balance, class_name: 'Money'</tt> returns <tt>:balance</tt>
|
95
179
|
# <tt>has_many :clients</tt> returns <tt>:clients</tt>
|
96
180
|
attr_reader :name
|
97
181
|
|
98
|
-
# Returns the macro type.
|
99
|
-
#
|
100
|
-
# <tt>composed_of :balance, class_name: 'Money'</tt> returns <tt>:composed_of</tt>
|
101
|
-
# <tt>has_many :clients</tt> returns <tt>:has_many</tt>
|
102
|
-
attr_reader :macro
|
103
|
-
|
104
182
|
attr_reader :scope
|
105
183
|
|
106
184
|
# Returns the hash of options used for the macro.
|
@@ -113,8 +191,7 @@ module ActiveRecord
|
|
113
191
|
|
114
192
|
attr_reader :plural_name # :nodoc:
|
115
193
|
|
116
|
-
def initialize(
|
117
|
-
@macro = macro
|
194
|
+
def initialize(name, scope, options, active_record)
|
118
195
|
@name = name
|
119
196
|
@scope = scope
|
120
197
|
@options = options
|
@@ -127,6 +204,10 @@ module ActiveRecord
|
|
127
204
|
def autosave=(autosave)
|
128
205
|
@automatic_inverse_of = false
|
129
206
|
@options[:autosave] = autosave
|
207
|
+
_, parent_reflection = self.parent_reflection
|
208
|
+
if parent_reflection
|
209
|
+
parent_reflection.autosave = autosave
|
210
|
+
end
|
130
211
|
end
|
131
212
|
|
132
213
|
# Returns the class for the macro.
|
@@ -134,15 +215,11 @@ module ActiveRecord
|
|
134
215
|
# <tt>composed_of :balance, class_name: 'Money'</tt> returns the Money class
|
135
216
|
# <tt>has_many :clients</tt> returns the Client class
|
136
217
|
def klass
|
137
|
-
@klass ||= class_name
|
218
|
+
@klass ||= compute_class(class_name)
|
138
219
|
end
|
139
220
|
|
140
|
-
|
141
|
-
|
142
|
-
# <tt>composed_of :balance, class_name: 'Money'</tt> returns <tt>'Money'</tt>
|
143
|
-
# <tt>has_many :clients</tt> returns <tt>'Client'</tt>
|
144
|
-
def class_name
|
145
|
-
@class_name ||= (options[:class_name] || derive_class_name).to_s
|
221
|
+
def compute_class(name)
|
222
|
+
name.constantize
|
146
223
|
end
|
147
224
|
|
148
225
|
# Returns +true+ if +self+ and +other_aggregation+ have the same +name+ attribute, +active_record+ attribute,
|
@@ -187,38 +264,40 @@ module ActiveRecord
|
|
187
264
|
# a new association object. Use +build_association+ or +create_association+
|
188
265
|
# instead. This allows plugins to hook into association object creation.
|
189
266
|
def klass
|
190
|
-
@klass ||=
|
267
|
+
@klass ||= compute_class(class_name)
|
268
|
+
end
|
269
|
+
|
270
|
+
def compute_class(name)
|
271
|
+
active_record.send(:compute_type, name)
|
191
272
|
end
|
192
273
|
|
193
274
|
attr_reader :type, :foreign_type
|
275
|
+
attr_accessor :parent_reflection # [:name, Reflection]
|
194
276
|
|
195
|
-
def initialize(
|
277
|
+
def initialize(name, scope, options, active_record)
|
196
278
|
super
|
197
|
-
@collection = :has_many == macro
|
198
279
|
@automatic_inverse_of = nil
|
199
|
-
@type = options[:as] && "#{options[:as]}_type"
|
280
|
+
@type = options[:as] && (options[:foreign_type] || "#{options[:as]}_type")
|
200
281
|
@foreign_type = options[:foreign_type] || "#{name}_type"
|
201
282
|
@constructable = calculate_constructable(macro, options)
|
283
|
+
@association_scope_cache = {}
|
284
|
+
@scope_lock = Mutex.new
|
202
285
|
end
|
203
286
|
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
287
|
+
def association_scope_cache(conn, owner)
|
288
|
+
key = conn.prepared_statements
|
289
|
+
if polymorphic?
|
290
|
+
key = [key, owner._read_attribute(@foreign_type)]
|
291
|
+
end
|
292
|
+
@association_scope_cache[key] ||= @scope_lock.synchronize {
|
293
|
+
@association_scope_cache[key] ||= yield
|
294
|
+
}
|
208
295
|
end
|
209
296
|
|
210
297
|
def constructable? # :nodoc:
|
211
298
|
@constructable
|
212
299
|
end
|
213
300
|
|
214
|
-
def table_name
|
215
|
-
klass.table_name
|
216
|
-
end
|
217
|
-
|
218
|
-
def quoted_table_name
|
219
|
-
klass.quoted_table_name
|
220
|
-
end
|
221
|
-
|
222
301
|
def join_table
|
223
302
|
@join_table ||= options[:join_table] || derive_join_table
|
224
303
|
end
|
@@ -227,10 +306,6 @@ module ActiveRecord
|
|
227
306
|
@foreign_key ||= options[:foreign_key] || derive_foreign_key
|
228
307
|
end
|
229
308
|
|
230
|
-
def primary_key_column
|
231
|
-
klass.columns_hash[klass.primary_key]
|
232
|
-
end
|
233
|
-
|
234
309
|
def association_foreign_key
|
235
310
|
@association_foreign_key ||= options[:association_foreign_key] || class_name.foreign_key
|
236
311
|
end
|
@@ -257,13 +332,33 @@ module ActiveRecord
|
|
257
332
|
end
|
258
333
|
|
259
334
|
def check_validity_of_inverse!
|
260
|
-
unless
|
335
|
+
unless polymorphic?
|
261
336
|
if has_inverse? && inverse_of.nil?
|
262
337
|
raise InverseOfAssociationNotFoundError.new(self)
|
263
338
|
end
|
264
339
|
end
|
265
340
|
end
|
266
341
|
|
342
|
+
def check_preloadable!
|
343
|
+
return unless scope
|
344
|
+
|
345
|
+
if scope.arity > 0
|
346
|
+
ActiveSupport::Deprecation.warn(<<-MSG.squish)
|
347
|
+
The association scope '#{name}' is instance dependent (the scope
|
348
|
+
block takes an argument). Preloading happens before the individual
|
349
|
+
instances are created. This means that there is no instance being
|
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.
|
353
|
+
MSG
|
354
|
+
end
|
355
|
+
end
|
356
|
+
alias :check_eager_loadable! :check_preloadable!
|
357
|
+
|
358
|
+
def join_id_for(owner) # :nodoc:
|
359
|
+
owner[active_record_primary_key]
|
360
|
+
end
|
361
|
+
|
267
362
|
def through_reflection
|
268
363
|
nil
|
269
364
|
end
|
@@ -288,8 +383,6 @@ module ActiveRecord
|
|
288
383
|
scope ? [[scope]] : [[]]
|
289
384
|
end
|
290
385
|
|
291
|
-
alias :source_macro :macro
|
292
|
-
|
293
386
|
def has_inverse?
|
294
387
|
inverse_name
|
295
388
|
end
|
@@ -297,12 +390,12 @@ module ActiveRecord
|
|
297
390
|
def inverse_of
|
298
391
|
return unless inverse_name
|
299
392
|
|
300
|
-
@inverse_of ||= klass.
|
393
|
+
@inverse_of ||= klass._reflect_on_association inverse_name
|
301
394
|
end
|
302
395
|
|
303
396
|
def polymorphic_inverse_of(associated_class)
|
304
397
|
if has_inverse?
|
305
|
-
if inverse_relationship = associated_class.
|
398
|
+
if inverse_relationship = associated_class._reflect_on_association(options[:inverse_of])
|
306
399
|
inverse_relationship
|
307
400
|
else
|
308
401
|
raise InverseOfAssociationNotFoundError.new(self, associated_class)
|
@@ -310,11 +403,16 @@ module ActiveRecord
|
|
310
403
|
end
|
311
404
|
end
|
312
405
|
|
406
|
+
# Returns the macro type.
|
407
|
+
#
|
408
|
+
# <tt>has_many :clients</tt> returns <tt>:has_many</tt>
|
409
|
+
def macro; raise NotImplementedError; end
|
410
|
+
|
313
411
|
# Returns whether or not this association reflection is for a collection
|
314
412
|
# association. Returns +true+ if the +macro+ is either +has_many+ or
|
315
413
|
# +has_and_belongs_to_many+, +false+ otherwise.
|
316
414
|
def collection?
|
317
|
-
|
415
|
+
false
|
318
416
|
end
|
319
417
|
|
320
418
|
# Returns whether or not the association should be validated as part of
|
@@ -327,18 +425,19 @@ module ActiveRecord
|
|
327
425
|
# * you use autosave; <tt>autosave: true</tt>
|
328
426
|
# * the association is a +has_many+ association
|
329
427
|
def validate?
|
330
|
-
!options[:validate].nil? ? options[:validate] : (options[:autosave] == true ||
|
428
|
+
!options[:validate].nil? ? options[:validate] : (options[:autosave] == true || collection?)
|
331
429
|
end
|
332
430
|
|
333
431
|
# Returns +true+ if +self+ is a +belongs_to+ reflection.
|
334
|
-
def belongs_to
|
335
|
-
|
336
|
-
|
432
|
+
def belongs_to?; false; end
|
433
|
+
|
434
|
+
# Returns +true+ if +self+ is a +has_one+ reflection.
|
435
|
+
def has_one?; false; end
|
337
436
|
|
338
437
|
def association_class
|
339
438
|
case macro
|
340
439
|
when :belongs_to
|
341
|
-
if
|
440
|
+
if polymorphic?
|
342
441
|
Associations::BelongsToPolymorphicAssociation
|
343
442
|
else
|
344
443
|
Associations::BelongsToAssociation
|
@@ -359,7 +458,7 @@ module ActiveRecord
|
|
359
458
|
end
|
360
459
|
|
361
460
|
def polymorphic?
|
362
|
-
options
|
461
|
+
options[:polymorphic]
|
363
462
|
end
|
364
463
|
|
365
464
|
VALID_AUTOMATIC_INVERSE_MACROS = [:has_many, :has_one, :belongs_to]
|
@@ -376,7 +475,7 @@ module ActiveRecord
|
|
376
475
|
def calculate_constructable(macro, options)
|
377
476
|
case macro
|
378
477
|
when :belongs_to
|
379
|
-
!
|
478
|
+
!polymorphic?
|
380
479
|
when :has_one
|
381
480
|
!options[:through]
|
382
481
|
else
|
@@ -400,10 +499,10 @@ module ActiveRecord
|
|
400
499
|
# returns either nil or the inverse association name that it finds.
|
401
500
|
def automatic_inverse_of
|
402
501
|
if can_find_inverse_of_automatically?(self)
|
403
|
-
inverse_name = ActiveSupport::Inflector.underscore(active_record.name).to_sym
|
502
|
+
inverse_name = ActiveSupport::Inflector.underscore(options[:as] || active_record.name).to_sym
|
404
503
|
|
405
504
|
begin
|
406
|
-
reflection = klass.
|
505
|
+
reflection = klass._reflect_on_association(inverse_name)
|
407
506
|
rescue NameError
|
408
507
|
# Give up: we couldn't compute the klass type so we won't be able
|
409
508
|
# to find any associations either.
|
@@ -449,9 +548,9 @@ module ActiveRecord
|
|
449
548
|
end
|
450
549
|
|
451
550
|
def derive_class_name
|
452
|
-
class_name = name.to_s
|
551
|
+
class_name = name.to_s
|
453
552
|
class_name = class_name.singularize if collection?
|
454
|
-
class_name
|
553
|
+
class_name.camelize
|
455
554
|
end
|
456
555
|
|
457
556
|
def derive_foreign_key
|
@@ -465,7 +564,7 @@ module ActiveRecord
|
|
465
564
|
end
|
466
565
|
|
467
566
|
def derive_join_table
|
468
|
-
|
567
|
+
ModelSchema.derive_join_table_name active_record.table_name, klass.table_name
|
469
568
|
end
|
470
569
|
|
471
570
|
def primary_key(klass)
|
@@ -473,15 +572,72 @@ module ActiveRecord
|
|
473
572
|
end
|
474
573
|
end
|
475
574
|
|
575
|
+
class HasManyReflection < AssociationReflection # :nodoc:
|
576
|
+
def initialize(name, scope, options, active_record)
|
577
|
+
super(name, scope, options, active_record)
|
578
|
+
end
|
579
|
+
|
580
|
+
def macro; :has_many; end
|
581
|
+
|
582
|
+
def collection?; true; end
|
583
|
+
end
|
584
|
+
|
585
|
+
class HasOneReflection < AssociationReflection # :nodoc:
|
586
|
+
def initialize(name, scope, options, active_record)
|
587
|
+
super(name, scope, options, active_record)
|
588
|
+
end
|
589
|
+
|
590
|
+
def macro; :has_one; end
|
591
|
+
|
592
|
+
def has_one?; true; end
|
593
|
+
end
|
594
|
+
|
595
|
+
class BelongsToReflection < AssociationReflection # :nodoc:
|
596
|
+
def initialize(name, scope, options, active_record)
|
597
|
+
super(name, scope, options, active_record)
|
598
|
+
end
|
599
|
+
|
600
|
+
def macro; :belongs_to; end
|
601
|
+
|
602
|
+
def belongs_to?; true; end
|
603
|
+
|
604
|
+
def join_keys(assoc_klass)
|
605
|
+
key = polymorphic? ? association_primary_key(assoc_klass) : association_primary_key
|
606
|
+
JoinKeys.new(key, foreign_key)
|
607
|
+
end
|
608
|
+
|
609
|
+
def join_id_for(owner) # :nodoc:
|
610
|
+
owner[foreign_key]
|
611
|
+
end
|
612
|
+
end
|
613
|
+
|
614
|
+
class HasAndBelongsToManyReflection < AssociationReflection # :nodoc:
|
615
|
+
def initialize(name, scope, options, active_record)
|
616
|
+
super
|
617
|
+
end
|
618
|
+
|
619
|
+
def macro; :has_and_belongs_to_many; end
|
620
|
+
|
621
|
+
def collection?
|
622
|
+
true
|
623
|
+
end
|
624
|
+
end
|
625
|
+
|
476
626
|
# Holds all the meta-data about a :through association as it was specified
|
477
627
|
# in the Active Record class.
|
478
|
-
class ThroughReflection <
|
628
|
+
class ThroughReflection < AbstractReflection #:nodoc:
|
629
|
+
attr_reader :delegate_reflection
|
479
630
|
delegate :foreign_key, :foreign_type, :association_foreign_key,
|
480
631
|
:active_record_primary_key, :type, :to => :source_reflection
|
481
632
|
|
482
|
-
def initialize(
|
483
|
-
|
484
|
-
@
|
633
|
+
def initialize(delegate_reflection)
|
634
|
+
@delegate_reflection = delegate_reflection
|
635
|
+
@klass = delegate_reflection.options[:class]
|
636
|
+
@source_reflection_name = delegate_reflection.options[:source]
|
637
|
+
end
|
638
|
+
|
639
|
+
def klass
|
640
|
+
@klass ||= delegate_reflection.compute_class(class_name)
|
485
641
|
end
|
486
642
|
|
487
643
|
# Returns the source of the through reflection. It checks both a singularized
|
@@ -499,10 +655,10 @@ module ActiveRecord
|
|
499
655
|
#
|
500
656
|
# tags_reflection = Post.reflect_on_association(:tags)
|
501
657
|
# tags_reflection.source_reflection
|
502
|
-
# # => <ActiveRecord::Reflection::
|
658
|
+
# # => <ActiveRecord::Reflection::BelongsToReflection: @name=:tag, @active_record=Tagging, @plural_name="tags">
|
503
659
|
#
|
504
660
|
def source_reflection
|
505
|
-
through_reflection.klass.
|
661
|
+
through_reflection.klass._reflect_on_association(source_reflection_name)
|
506
662
|
end
|
507
663
|
|
508
664
|
# Returns the AssociationReflection object specified in the <tt>:through</tt> option
|
@@ -515,10 +671,10 @@ module ActiveRecord
|
|
515
671
|
#
|
516
672
|
# tags_reflection = Post.reflect_on_association(:tags)
|
517
673
|
# tags_reflection.through_reflection
|
518
|
-
# # => <ActiveRecord::Reflection::
|
674
|
+
# # => <ActiveRecord::Reflection::HasManyReflection: @name=:taggings, @active_record=Post, @plural_name="taggings">
|
519
675
|
#
|
520
676
|
def through_reflection
|
521
|
-
active_record.
|
677
|
+
active_record._reflect_on_association(options[:through])
|
522
678
|
end
|
523
679
|
|
524
680
|
# Returns an array of reflections which are involved in this association. Each item in the
|
@@ -535,8 +691,8 @@ module ActiveRecord
|
|
535
691
|
#
|
536
692
|
# tags_reflection = Post.reflect_on_association(:tags)
|
537
693
|
# tags_reflection.chain
|
538
|
-
# # => [<ActiveRecord::Reflection::ThroughReflection: @
|
539
|
-
# <ActiveRecord::Reflection::
|
694
|
+
# # => [<ActiveRecord::Reflection::ThroughReflection: @delegate_reflection=#<ActiveRecord::Reflection::HasManyReflection: @name=:tags...>,
|
695
|
+
# <ActiveRecord::Reflection::HasManyReflection: @name=:taggings, @options={}, @active_record=Post>]
|
540
696
|
#
|
541
697
|
def chain
|
542
698
|
@chain ||= begin
|
@@ -577,8 +733,11 @@ module ActiveRecord
|
|
577
733
|
through_scope_chain = through_reflection.scope_chain.map(&:dup)
|
578
734
|
|
579
735
|
if options[:source_type]
|
580
|
-
|
581
|
-
|
736
|
+
type = foreign_type
|
737
|
+
source_type = options[:source_type]
|
738
|
+
through_scope_chain.first << lambda { |object|
|
739
|
+
where(type => source_type)
|
740
|
+
}
|
582
741
|
end
|
583
742
|
|
584
743
|
# Recursively fill out the rest of the array from the through reflection
|
@@ -586,8 +745,17 @@ module ActiveRecord
|
|
586
745
|
end
|
587
746
|
end
|
588
747
|
|
748
|
+
def join_keys(assoc_klass)
|
749
|
+
source_reflection.join_keys(assoc_klass)
|
750
|
+
end
|
751
|
+
|
589
752
|
# The macro used by the source association
|
590
753
|
def source_macro
|
754
|
+
ActiveSupport::Deprecation.warn(<<-MSG.squish)
|
755
|
+
ActiveRecord::Base.source_macro is deprecated and will be removed
|
756
|
+
without replacement.
|
757
|
+
MSG
|
758
|
+
|
591
759
|
source_reflection.source_macro
|
592
760
|
end
|
593
761
|
|
@@ -617,7 +785,7 @@ module ActiveRecord
|
|
617
785
|
# # => [:tag, :tags]
|
618
786
|
#
|
619
787
|
def source_reflection_names
|
620
|
-
|
788
|
+
options[:source] ? [options[:source]] : [name.to_s.singularize, name].uniq
|
621
789
|
end
|
622
790
|
|
623
791
|
def source_reflection_name # :nodoc:
|
@@ -625,21 +793,19 @@ module ActiveRecord
|
|
625
793
|
|
626
794
|
names = [name.to_s.singularize, name].collect { |n| n.to_sym }.uniq
|
627
795
|
names = names.find_all { |n|
|
628
|
-
through_reflection.klass.
|
796
|
+
through_reflection.klass._reflect_on_association(n)
|
629
797
|
}
|
630
798
|
|
631
799
|
if names.length > 1
|
632
800
|
example_options = options.dup
|
633
801
|
example_options[:source] = source_reflection_names.first
|
634
|
-
ActiveSupport::Deprecation.warn
|
635
|
-
Ambiguous source reflection for through association. Please
|
636
|
-
directive on your declaration like
|
637
|
-
|
638
|
-
class #{active_record.name} < ActiveRecord::Base
|
639
|
-
#{macro} :#{name}, #{example_options}
|
640
|
-
end
|
641
|
-
|
642
|
-
eowarn
|
802
|
+
ActiveSupport::Deprecation.warn \
|
803
|
+
"Ambiguous source reflection for through association. Please " \
|
804
|
+
"specify a :source directive on your declaration like:\n" \
|
805
|
+
"\n" \
|
806
|
+
" class #{active_record.name} < ActiveRecord::Base\n" \
|
807
|
+
" #{macro} :#{name}, #{example_options}\n" \
|
808
|
+
" end"
|
643
809
|
end
|
644
810
|
|
645
811
|
@source_reflection_name = names.first
|
@@ -653,28 +819,36 @@ directive on your declaration like:
|
|
653
819
|
through_reflection.options
|
654
820
|
end
|
655
821
|
|
822
|
+
def join_id_for(owner) # :nodoc:
|
823
|
+
source_reflection.join_id_for(owner)
|
824
|
+
end
|
825
|
+
|
656
826
|
def check_validity!
|
657
827
|
if through_reflection.nil?
|
658
828
|
raise HasManyThroughAssociationNotFoundError.new(active_record.name, self)
|
659
829
|
end
|
660
830
|
|
661
|
-
if through_reflection.
|
662
|
-
|
831
|
+
if through_reflection.polymorphic?
|
832
|
+
if has_one?
|
833
|
+
raise HasOneAssociationPolymorphicThroughError.new(active_record.name, self)
|
834
|
+
else
|
835
|
+
raise HasManyThroughAssociationPolymorphicThroughError.new(active_record.name, self)
|
836
|
+
end
|
663
837
|
end
|
664
838
|
|
665
839
|
if source_reflection.nil?
|
666
840
|
raise HasManyThroughSourceAssociationNotFoundError.new(self)
|
667
841
|
end
|
668
842
|
|
669
|
-
if options[:source_type] && source_reflection.
|
843
|
+
if options[:source_type] && !source_reflection.polymorphic?
|
670
844
|
raise HasManyThroughAssociationPointlessSourceTypeError.new(active_record.name, self, source_reflection)
|
671
845
|
end
|
672
846
|
|
673
|
-
if source_reflection.
|
847
|
+
if source_reflection.polymorphic? && options[:source_type].nil?
|
674
848
|
raise HasManyThroughAssociationPolymorphicSourceError.new(active_record.name, self, source_reflection)
|
675
849
|
end
|
676
850
|
|
677
|
-
if
|
851
|
+
if has_one? && through_reflection.collection?
|
678
852
|
raise HasOneThroughCantAssociateThroughCollection.new(active_record.name, self, through_reflection)
|
679
853
|
end
|
680
854
|
|
@@ -683,15 +857,25 @@ directive on your declaration like:
|
|
683
857
|
|
684
858
|
protected
|
685
859
|
|
686
|
-
|
687
|
-
|
688
|
-
|
860
|
+
def actual_source_reflection # FIXME: this is a horrible name
|
861
|
+
source_reflection.send(:actual_source_reflection)
|
862
|
+
end
|
863
|
+
|
864
|
+
def primary_key(klass)
|
865
|
+
klass.primary_key || raise(UnknownPrimaryKey.new(klass))
|
866
|
+
end
|
689
867
|
|
690
868
|
private
|
691
869
|
def derive_class_name
|
692
870
|
# get the class_name of the belongs_to association of the through reflection
|
693
871
|
options[:source_type] || source_reflection.class_name
|
694
872
|
end
|
873
|
+
|
874
|
+
delegate_methods = AssociationReflection.public_instance_methods -
|
875
|
+
public_instance_methods
|
876
|
+
|
877
|
+
delegate(*delegate_methods, to: :delegate_reflection)
|
878
|
+
|
695
879
|
end
|
696
880
|
end
|
697
881
|
end
|