activerecord 4.1.15 → 4.2.0.beta1
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 +634 -2176
- data/README.rdoc +15 -10
- data/lib/active_record/aggregations.rb +12 -8
- data/lib/active_record/associations/association.rb +1 -1
- data/lib/active_record/associations/association_scope.rb +53 -21
- data/lib/active_record/associations/belongs_to_association.rb +15 -5
- data/lib/active_record/associations/builder/association.rb +16 -5
- data/lib/active_record/associations/builder/belongs_to.rb +7 -29
- data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +2 -11
- 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 +32 -44
- data/lib/active_record/associations/collection_proxy.rb +1 -10
- data/lib/active_record/associations/has_many_association.rb +60 -14
- data/lib/active_record/associations/has_many_through_association.rb +34 -23
- data/lib/active_record/associations/has_one_association.rb +0 -1
- data/lib/active_record/associations/join_dependency/join_association.rb +18 -14
- data/lib/active_record/associations/join_dependency.rb +7 -9
- data/lib/active_record/associations/preloader/association.rb +9 -5
- data/lib/active_record/associations/preloader/through_association.rb +3 -3
- data/lib/active_record/associations/preloader.rb +2 -2
- data/lib/active_record/associations/singular_association.rb +16 -1
- data/lib/active_record/associations/through_association.rb +6 -22
- data/lib/active_record/associations.rb +58 -33
- data/lib/active_record/attribute.rb +131 -0
- data/lib/active_record/attribute_assignment.rb +19 -11
- 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 +85 -42
- data/lib/active_record/attribute_methods/primary_key.rb +6 -8
- data/lib/active_record/attribute_methods/read.rb +14 -57
- data/lib/active_record/attribute_methods/serialization.rb +12 -146
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +32 -40
- data/lib/active_record/attribute_methods/write.rb +8 -23
- data/lib/active_record/attribute_methods.rb +53 -90
- data/lib/active_record/attribute_set/builder.rb +32 -0
- data/lib/active_record/attribute_set.rb +77 -0
- data/lib/active_record/attributes.rb +122 -0
- data/lib/active_record/autosave_association.rb +11 -21
- data/lib/active_record/base.rb +9 -19
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +69 -45
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +22 -42
- data/lib/active_record/connection_adapters/abstract/quoting.rb +59 -60
- data/lib/active_record/connection_adapters/abstract/schema_creation.rb +37 -2
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +102 -21
- data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +9 -33
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +178 -55
- data/lib/active_record/connection_adapters/abstract/transaction.rb +120 -115
- data/lib/active_record/connection_adapters/abstract_adapter.rb +143 -57
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +156 -107
- data/lib/active_record/connection_adapters/column.rb +13 -244
- data/lib/active_record/connection_adapters/connection_specification.rb +6 -20
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +12 -15
- data/lib/active_record/connection_adapters/mysql_adapter.rb +55 -143
- 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 -20
- data/lib/active_record/connection_adapters/postgresql/oid/array.rb +96 -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 +76 -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 +85 -0
- data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +26 -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 -388
- data/lib/active_record/connection_adapters/postgresql/quoting.rb +42 -122
- data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +4 -4
- data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +154 -0
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +86 -34
- data/lib/active_record/connection_adapters/postgresql/utils.rb +66 -0
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +188 -452
- data/lib/active_record/connection_adapters/schema_cache.rb +14 -28
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +54 -47
- data/lib/active_record/connection_handling.rb +1 -1
- data/lib/active_record/core.rb +119 -22
- data/lib/active_record/counter_cache.rb +60 -6
- data/lib/active_record/enum.rb +9 -10
- data/lib/active_record/errors.rb +27 -26
- data/lib/active_record/explain.rb +1 -1
- data/lib/active_record/fixtures.rb +52 -45
- data/lib/active_record/gem_version.rb +3 -3
- data/lib/active_record/inheritance.rb +33 -8
- data/lib/active_record/integration.rb +4 -4
- data/lib/active_record/locking/optimistic.rb +34 -16
- 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 +22 -32
- data/lib/active_record/model_schema.rb +39 -48
- data/lib/active_record/nested_attributes.rb +8 -18
- data/lib/active_record/persistence.rb +39 -22
- data/lib/active_record/query_cache.rb +3 -3
- data/lib/active_record/querying.rb +1 -8
- data/lib/active_record/railtie.rb +17 -10
- data/lib/active_record/railties/databases.rake +47 -42
- data/lib/active_record/readonly_attributes.rb +0 -1
- data/lib/active_record/reflection.rb +225 -92
- data/lib/active_record/relation/batches.rb +0 -2
- data/lib/active_record/relation/calculations.rb +28 -32
- data/lib/active_record/relation/delegation.rb +1 -1
- data/lib/active_record/relation/finder_methods.rb +42 -20
- data/lib/active_record/relation/merger.rb +0 -1
- data/lib/active_record/relation/predicate_builder/array_handler.rb +16 -11
- data/lib/active_record/relation/predicate_builder/relation_handler.rb +0 -4
- data/lib/active_record/relation/predicate_builder.rb +1 -22
- data/lib/active_record/relation/query_methods.rb +98 -62
- data/lib/active_record/relation/spawn_methods.rb +6 -7
- data/lib/active_record/relation.rb +35 -11
- data/lib/active_record/result.rb +16 -9
- data/lib/active_record/sanitization.rb +8 -1
- data/lib/active_record/schema.rb +0 -1
- data/lib/active_record/schema_dumper.rb +51 -9
- data/lib/active_record/schema_migration.rb +4 -0
- data/lib/active_record/scoping/default.rb +5 -4
- data/lib/active_record/serializers/xml_serializer.rb +3 -7
- data/lib/active_record/statement_cache.rb +79 -5
- data/lib/active_record/store.rb +5 -5
- data/lib/active_record/tasks/database_tasks.rb +37 -5
- data/lib/active_record/tasks/mysql_database_tasks.rb +1 -1
- data/lib/active_record/tasks/postgresql_database_tasks.rb +2 -2
- data/lib/active_record/timestamp.rb +9 -7
- data/lib/active_record/transactions.rb +35 -21
- data/lib/active_record/type/binary.rb +40 -0
- data/lib/active_record/type/boolean.rb +19 -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/float.rb +19 -0
- data/lib/active_record/type/hash_lookup_type_map.rb +19 -0
- data/lib/active_record/type/integer.rb +23 -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 +51 -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 +48 -0
- data/lib/active_record/type/value.rb +101 -0
- data/lib/active_record/type.rb +20 -0
- data/lib/active_record/validations/uniqueness.rb +9 -23
- data/lib/active_record/validations.rb +21 -16
- data/lib/active_record.rb +2 -1
- data/lib/rails/generators/active_record/migration/migration_generator.rb +8 -4
- data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb +1 -1
- data/lib/rails/generators/active_record/model/templates/model.rb +1 -1
- metadata +71 -14
- data/lib/active_record/connection_adapters/postgresql/cast.rb +0 -168
@@ -1,35 +1,44 @@
|
|
1
|
+
require 'thread'
|
2
|
+
|
1
3
|
module ActiveRecord
|
2
4
|
# = Active Record Reflection
|
3
5
|
module Reflection # :nodoc:
|
4
6
|
extend ActiveSupport::Concern
|
5
7
|
|
6
8
|
included do
|
7
|
-
class_attribute :_reflections
|
8
|
-
class_attribute :aggregate_reflections
|
9
|
+
class_attribute :_reflections
|
10
|
+
class_attribute :aggregate_reflections
|
9
11
|
self._reflections = {}
|
10
12
|
self.aggregate_reflections = {}
|
11
13
|
end
|
12
14
|
|
13
15
|
def self.create(macro, name, scope, options, ar)
|
14
|
-
case macro
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
16
|
+
klass = case macro
|
17
|
+
when :composed_of
|
18
|
+
AggregateReflection
|
19
|
+
when :has_many
|
20
|
+
HasManyReflection
|
21
|
+
when :has_one
|
22
|
+
HasOneReflection
|
23
|
+
when :belongs_to
|
24
|
+
BelongsToReflection
|
25
|
+
else
|
26
|
+
raise "Unsupported Macro: #{macro}"
|
27
|
+
end
|
28
|
+
|
29
|
+
reflection = klass.new(name, scope, options, ar)
|
30
|
+
options[:through] ? ThroughReflection.new(reflection) : reflection
|
22
31
|
end
|
23
32
|
|
24
33
|
def self.add_reflection(ar, name, reflection)
|
25
|
-
ar._reflections = ar._reflections.merge(name.
|
34
|
+
ar._reflections = ar._reflections.merge(name.to_s => reflection)
|
26
35
|
end
|
27
36
|
|
28
37
|
def self.add_aggregate_reflection(ar, name, reflection)
|
29
|
-
ar.aggregate_reflections = ar.aggregate_reflections.merge(name.
|
38
|
+
ar.aggregate_reflections = ar.aggregate_reflections.merge(name.to_s => reflection)
|
30
39
|
end
|
31
40
|
|
32
|
-
# \Reflection enables
|
41
|
+
# \Reflection enables interrogating Active Record classes and objects
|
33
42
|
# about their associations and aggregations. This information can,
|
34
43
|
# for example, be used in a form builder that takes an Active Record object
|
35
44
|
# and creates input fields for all of the attributes depending on their type
|
@@ -48,7 +57,7 @@ module ActiveRecord
|
|
48
57
|
# Account.reflect_on_aggregation(:balance) # => the balance AggregateReflection
|
49
58
|
#
|
50
59
|
def reflect_on_aggregation(aggregation)
|
51
|
-
aggregate_reflections[aggregation.
|
60
|
+
aggregate_reflections[aggregation.to_s]
|
52
61
|
end
|
53
62
|
|
54
63
|
# Returns a Hash of name of the reflection as the key and a AssociationReflection as the value.
|
@@ -92,12 +101,12 @@ module ActiveRecord
|
|
92
101
|
#
|
93
102
|
# @api public
|
94
103
|
def reflect_on_association(association)
|
95
|
-
reflections[association.
|
104
|
+
reflections[association.to_s]
|
96
105
|
end
|
97
106
|
|
98
107
|
# @api private
|
99
108
|
def _reflect_on_association(association) #:nodoc:
|
100
|
-
_reflections[association.
|
109
|
+
_reflections[association.to_s]
|
101
110
|
end
|
102
111
|
|
103
112
|
# Returns an array of AssociationReflection objects for all associations which have <tt>:autosave</tt> enabled.
|
@@ -108,26 +117,64 @@ module ActiveRecord
|
|
108
117
|
end
|
109
118
|
end
|
110
119
|
|
120
|
+
# Holds all the methods that are shared between MacroReflection, AssociationReflection
|
121
|
+
# and ThroughReflection
|
122
|
+
class AbstractReflection # :nodoc:
|
123
|
+
def table_name
|
124
|
+
klass.table_name
|
125
|
+
end
|
126
|
+
|
127
|
+
# Returns a new, unsaved instance of the associated class. +attributes+ will
|
128
|
+
# be passed to the class's constructor.
|
129
|
+
def build_association(attributes, &block)
|
130
|
+
klass.new(attributes, &block)
|
131
|
+
end
|
132
|
+
|
133
|
+
def quoted_table_name
|
134
|
+
klass.quoted_table_name
|
135
|
+
end
|
136
|
+
|
137
|
+
def primary_key_type
|
138
|
+
klass.type_for_attribute(klass.primary_key)
|
139
|
+
end
|
140
|
+
|
141
|
+
# Returns the class name for the macro.
|
142
|
+
#
|
143
|
+
# <tt>composed_of :balance, class_name: 'Money'</tt> returns <tt>'Money'</tt>
|
144
|
+
# <tt>has_many :clients</tt> returns <tt>'Client'</tt>
|
145
|
+
def class_name
|
146
|
+
@class_name ||= (options[:class_name] || derive_class_name).to_s
|
147
|
+
end
|
148
|
+
|
149
|
+
JoinKeys = Struct.new(:key, :foreign_key) # :nodoc:
|
150
|
+
|
151
|
+
def join_keys(assoc_klass)
|
152
|
+
JoinKeys.new(foreign_key, active_record_primary_key)
|
153
|
+
end
|
154
|
+
|
155
|
+
def source_macro
|
156
|
+
ActiveSupport::Deprecation.warn("ActiveRecord::Base.source_macro is deprecated and " \
|
157
|
+
"will be removed without replacement.")
|
158
|
+
macro
|
159
|
+
end
|
160
|
+
end
|
111
161
|
# Base class for AggregateReflection and AssociationReflection. Objects of
|
112
162
|
# AggregateReflection and AssociationReflection are returned by the Reflection::ClassMethods.
|
113
163
|
#
|
114
164
|
# MacroReflection
|
115
|
-
# AggregateReflection
|
116
165
|
# AssociationReflection
|
117
|
-
#
|
118
|
-
|
166
|
+
# AggregateReflection
|
167
|
+
# HasManyReflection
|
168
|
+
# HasOneReflection
|
169
|
+
# BelongsToReflection
|
170
|
+
# ThroughReflection
|
171
|
+
class MacroReflection < AbstractReflection
|
119
172
|
# Returns the name of the macro.
|
120
173
|
#
|
121
174
|
# <tt>composed_of :balance, class_name: 'Money'</tt> returns <tt>:balance</tt>
|
122
175
|
# <tt>has_many :clients</tt> returns <tt>:clients</tt>
|
123
176
|
attr_reader :name
|
124
177
|
|
125
|
-
# Returns the macro type.
|
126
|
-
#
|
127
|
-
# <tt>composed_of :balance, class_name: 'Money'</tt> returns <tt>:composed_of</tt>
|
128
|
-
# <tt>has_many :clients</tt> returns <tt>:has_many</tt>
|
129
|
-
attr_reader :macro
|
130
|
-
|
131
178
|
attr_reader :scope
|
132
179
|
|
133
180
|
# Returns the hash of options used for the macro.
|
@@ -140,13 +187,12 @@ module ActiveRecord
|
|
140
187
|
|
141
188
|
attr_reader :plural_name # :nodoc:
|
142
189
|
|
143
|
-
def initialize(
|
144
|
-
@macro = macro
|
190
|
+
def initialize(name, scope, options, active_record)
|
145
191
|
@name = name
|
146
192
|
@scope = scope
|
147
193
|
@options = options
|
148
194
|
@active_record = active_record
|
149
|
-
@klass = options[:
|
195
|
+
@klass = options[:class]
|
150
196
|
@plural_name = active_record.pluralize_table_names ?
|
151
197
|
name.to_s.pluralize : name.to_s
|
152
198
|
end
|
@@ -165,15 +211,11 @@ module ActiveRecord
|
|
165
211
|
# <tt>composed_of :balance, class_name: 'Money'</tt> returns the Money class
|
166
212
|
# <tt>has_many :clients</tt> returns the Client class
|
167
213
|
def klass
|
168
|
-
@klass ||= class_name
|
214
|
+
@klass ||= compute_class(class_name)
|
169
215
|
end
|
170
216
|
|
171
|
-
|
172
|
-
|
173
|
-
# <tt>composed_of :balance, class_name: 'Money'</tt> returns <tt>'Money'</tt>
|
174
|
-
# <tt>has_many :clients</tt> returns <tt>'Client'</tt>
|
175
|
-
def class_name
|
176
|
-
@class_name ||= (options[:class_name] || derive_class_name).to_s
|
217
|
+
def compute_class(name)
|
218
|
+
name.constantize
|
177
219
|
end
|
178
220
|
|
179
221
|
# Returns +true+ if +self+ and +other_aggregation+ have the same +name+ attribute, +active_record+ attribute,
|
@@ -218,39 +260,40 @@ module ActiveRecord
|
|
218
260
|
# a new association object. Use +build_association+ or +create_association+
|
219
261
|
# instead. This allows plugins to hook into association object creation.
|
220
262
|
def klass
|
221
|
-
@klass ||=
|
263
|
+
@klass ||= compute_class(class_name)
|
264
|
+
end
|
265
|
+
|
266
|
+
def compute_class(name)
|
267
|
+
active_record.send(:compute_type, name)
|
222
268
|
end
|
223
269
|
|
224
270
|
attr_reader :type, :foreign_type
|
225
271
|
attr_accessor :parent_reflection # [:name, Reflection]
|
226
272
|
|
227
|
-
def initialize(
|
273
|
+
def initialize(name, scope, options, active_record)
|
228
274
|
super
|
229
|
-
@collection = [:has_many, :has_and_belongs_to_many].include?(macro)
|
230
275
|
@automatic_inverse_of = nil
|
231
276
|
@type = options[:as] && "#{options[:as]}_type"
|
232
277
|
@foreign_type = options[:foreign_type] || "#{name}_type"
|
233
278
|
@constructable = calculate_constructable(macro, options)
|
279
|
+
@association_scope_cache = {}
|
280
|
+
@scope_lock = Mutex.new
|
234
281
|
end
|
235
282
|
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
|
283
|
+
def association_scope_cache(conn, owner)
|
284
|
+
key = conn.prepared_statements
|
285
|
+
if polymorphic?
|
286
|
+
key = [key, owner.read_attribute(@foreign_type)]
|
287
|
+
end
|
288
|
+
@association_scope_cache[key] ||= @scope_lock.synchronize {
|
289
|
+
@association_scope_cache[key] ||= yield
|
290
|
+
}
|
240
291
|
end
|
241
292
|
|
242
293
|
def constructable? # :nodoc:
|
243
294
|
@constructable
|
244
295
|
end
|
245
296
|
|
246
|
-
def table_name
|
247
|
-
klass.table_name
|
248
|
-
end
|
249
|
-
|
250
|
-
def quoted_table_name
|
251
|
-
klass.quoted_table_name
|
252
|
-
end
|
253
|
-
|
254
297
|
def join_table
|
255
298
|
@join_table ||= options[:join_table] || derive_join_table
|
256
299
|
end
|
@@ -259,10 +302,6 @@ module ActiveRecord
|
|
259
302
|
@foreign_key ||= options[:foreign_key] || derive_foreign_key
|
260
303
|
end
|
261
304
|
|
262
|
-
def primary_key_column
|
263
|
-
klass.columns_hash[klass.primary_key]
|
264
|
-
end
|
265
|
-
|
266
305
|
def association_foreign_key
|
267
306
|
@association_foreign_key ||= options[:association_foreign_key] || class_name.foreign_key
|
268
307
|
end
|
@@ -289,13 +328,31 @@ module ActiveRecord
|
|
289
328
|
end
|
290
329
|
|
291
330
|
def check_validity_of_inverse!
|
292
|
-
unless
|
331
|
+
unless polymorphic?
|
293
332
|
if has_inverse? && inverse_of.nil?
|
294
333
|
raise InverseOfAssociationNotFoundError.new(self)
|
295
334
|
end
|
296
335
|
end
|
297
336
|
end
|
298
337
|
|
338
|
+
def check_preloadable!
|
339
|
+
return unless scope
|
340
|
+
|
341
|
+
if scope.arity > 0
|
342
|
+
ActiveSupport::Deprecation.warn <<-WARNING
|
343
|
+
The association scope '#{name}' is instance dependent (the scope block takes an argument).
|
344
|
+
Preloading happens before the individual instances are created. This means that there is no instance
|
345
|
+
being passed to the association scope. This will most likely result in broken or incorrect behavior.
|
346
|
+
Joining, Preloading and eager loading of these associations is deprecated and will be removed in the future.
|
347
|
+
WARNING
|
348
|
+
end
|
349
|
+
end
|
350
|
+
alias :check_eager_loadable! :check_preloadable!
|
351
|
+
|
352
|
+
def join_id_for(owner) # :nodoc:
|
353
|
+
owner[active_record_primary_key]
|
354
|
+
end
|
355
|
+
|
299
356
|
def through_reflection
|
300
357
|
nil
|
301
358
|
end
|
@@ -320,8 +377,6 @@ module ActiveRecord
|
|
320
377
|
scope ? [[scope]] : [[]]
|
321
378
|
end
|
322
379
|
|
323
|
-
alias :source_macro :macro
|
324
|
-
|
325
380
|
def has_inverse?
|
326
381
|
inverse_name
|
327
382
|
end
|
@@ -342,11 +397,16 @@ module ActiveRecord
|
|
342
397
|
end
|
343
398
|
end
|
344
399
|
|
400
|
+
# Returns the macro type.
|
401
|
+
#
|
402
|
+
# <tt>has_many :clients</tt> returns <tt>:has_many</tt>
|
403
|
+
def macro; raise NotImplementedError; end
|
404
|
+
|
345
405
|
# Returns whether or not this association reflection is for a collection
|
346
406
|
# association. Returns +true+ if the +macro+ is either +has_many+ or
|
347
407
|
# +has_and_belongs_to_many+, +false+ otherwise.
|
348
408
|
def collection?
|
349
|
-
|
409
|
+
false
|
350
410
|
end
|
351
411
|
|
352
412
|
# Returns whether or not the association should be validated as part of
|
@@ -359,18 +419,19 @@ module ActiveRecord
|
|
359
419
|
# * you use autosave; <tt>autosave: true</tt>
|
360
420
|
# * the association is a +has_many+ association
|
361
421
|
def validate?
|
362
|
-
!options[:validate].nil? ? options[:validate] : (options[:autosave] == true ||
|
422
|
+
!options[:validate].nil? ? options[:validate] : (options[:autosave] == true || collection?)
|
363
423
|
end
|
364
424
|
|
365
425
|
# Returns +true+ if +self+ is a +belongs_to+ reflection.
|
366
|
-
def belongs_to
|
367
|
-
|
368
|
-
|
426
|
+
def belongs_to?; false; end
|
427
|
+
|
428
|
+
# Returns +true+ if +self+ is a +has_one+ reflection.
|
429
|
+
def has_one?; false; end
|
369
430
|
|
370
431
|
def association_class
|
371
432
|
case macro
|
372
433
|
when :belongs_to
|
373
|
-
if
|
434
|
+
if polymorphic?
|
374
435
|
Associations::BelongsToPolymorphicAssociation
|
375
436
|
else
|
376
437
|
Associations::BelongsToAssociation
|
@@ -391,7 +452,7 @@ module ActiveRecord
|
|
391
452
|
end
|
392
453
|
|
393
454
|
def polymorphic?
|
394
|
-
options
|
455
|
+
options[:polymorphic]
|
395
456
|
end
|
396
457
|
|
397
458
|
VALID_AUTOMATIC_INVERSE_MACROS = [:has_many, :has_one, :belongs_to]
|
@@ -408,7 +469,7 @@ module ActiveRecord
|
|
408
469
|
def calculate_constructable(macro, options)
|
409
470
|
case macro
|
410
471
|
when :belongs_to
|
411
|
-
!
|
472
|
+
!polymorphic?
|
412
473
|
when :has_one
|
413
474
|
!options[:through]
|
414
475
|
else
|
@@ -432,7 +493,7 @@ module ActiveRecord
|
|
432
493
|
# returns either nil or the inverse association name that it finds.
|
433
494
|
def automatic_inverse_of
|
434
495
|
if can_find_inverse_of_automatically?(self)
|
435
|
-
inverse_name = ActiveSupport::Inflector.underscore(options[:as] || active_record.name
|
496
|
+
inverse_name = ActiveSupport::Inflector.underscore(options[:as] || active_record.name).to_sym
|
436
497
|
|
437
498
|
begin
|
438
499
|
reflection = klass._reflect_on_association(inverse_name)
|
@@ -497,7 +558,7 @@ module ActiveRecord
|
|
497
558
|
end
|
498
559
|
|
499
560
|
def derive_join_table
|
500
|
-
|
561
|
+
ModelSchema.derive_join_table_name active_record.table_name, klass.table_name
|
501
562
|
end
|
502
563
|
|
503
564
|
def primary_key(klass)
|
@@ -505,15 +566,72 @@ module ActiveRecord
|
|
505
566
|
end
|
506
567
|
end
|
507
568
|
|
569
|
+
class HasManyReflection < AssociationReflection # :nodoc:
|
570
|
+
def initialize(name, scope, options, active_record)
|
571
|
+
super(name, scope, options, active_record)
|
572
|
+
end
|
573
|
+
|
574
|
+
def macro; :has_many; end
|
575
|
+
|
576
|
+
def collection?; true; end
|
577
|
+
end
|
578
|
+
|
579
|
+
class HasOneReflection < AssociationReflection # :nodoc:
|
580
|
+
def initialize(name, scope, options, active_record)
|
581
|
+
super(name, scope, options, active_record)
|
582
|
+
end
|
583
|
+
|
584
|
+
def macro; :has_one; end
|
585
|
+
|
586
|
+
def has_one?; true; end
|
587
|
+
end
|
588
|
+
|
589
|
+
class BelongsToReflection < AssociationReflection # :nodoc:
|
590
|
+
def initialize(name, scope, options, active_record)
|
591
|
+
super(name, scope, options, active_record)
|
592
|
+
end
|
593
|
+
|
594
|
+
def macro; :belongs_to; end
|
595
|
+
|
596
|
+
def belongs_to?; true; end
|
597
|
+
|
598
|
+
def join_keys(assoc_klass)
|
599
|
+
key = polymorphic? ? association_primary_key(assoc_klass) : association_primary_key
|
600
|
+
JoinKeys.new(key, foreign_key)
|
601
|
+
end
|
602
|
+
|
603
|
+
def join_id_for(owner) # :nodoc:
|
604
|
+
owner[foreign_key]
|
605
|
+
end
|
606
|
+
end
|
607
|
+
|
608
|
+
class HasAndBelongsToManyReflection < AssociationReflection # :nodoc:
|
609
|
+
def initialize(name, scope, options, active_record)
|
610
|
+
super
|
611
|
+
end
|
612
|
+
|
613
|
+
def macro; :has_and_belongs_to_many; end
|
614
|
+
|
615
|
+
def collection?
|
616
|
+
true
|
617
|
+
end
|
618
|
+
end
|
619
|
+
|
508
620
|
# Holds all the meta-data about a :through association as it was specified
|
509
621
|
# in the Active Record class.
|
510
|
-
class ThroughReflection <
|
622
|
+
class ThroughReflection < AbstractReflection #:nodoc:
|
623
|
+
attr_reader :delegate_reflection
|
511
624
|
delegate :foreign_key, :foreign_type, :association_foreign_key,
|
512
625
|
:active_record_primary_key, :type, :to => :source_reflection
|
513
626
|
|
514
|
-
def initialize(
|
515
|
-
|
516
|
-
@
|
627
|
+
def initialize(delegate_reflection)
|
628
|
+
@delegate_reflection = delegate_reflection
|
629
|
+
@klass = delegate_reflection.options[:class]
|
630
|
+
@source_reflection_name = delegate_reflection.options[:source]
|
631
|
+
end
|
632
|
+
|
633
|
+
def klass
|
634
|
+
@klass ||= delegate_reflection.compute_class(class_name)
|
517
635
|
end
|
518
636
|
|
519
637
|
# Returns the source of the through reflection. It checks both a singularized
|
@@ -531,12 +649,10 @@ module ActiveRecord
|
|
531
649
|
#
|
532
650
|
# tags_reflection = Post.reflect_on_association(:tags)
|
533
651
|
# tags_reflection.source_reflection
|
534
|
-
# # => <ActiveRecord::Reflection::
|
652
|
+
# # => <ActiveRecord::Reflection::BelongsToReflection: @name=:tag, @active_record=Tagging, @plural_name="tags">
|
535
653
|
#
|
536
654
|
def source_reflection
|
537
|
-
|
538
|
-
through_reflection.klass._reflect_on_association(source_reflection_name)
|
539
|
-
end
|
655
|
+
through_reflection.klass._reflect_on_association(source_reflection_name)
|
540
656
|
end
|
541
657
|
|
542
658
|
# Returns the AssociationReflection object specified in the <tt>:through</tt> option
|
@@ -549,7 +665,7 @@ module ActiveRecord
|
|
549
665
|
#
|
550
666
|
# tags_reflection = Post.reflect_on_association(:tags)
|
551
667
|
# tags_reflection.through_reflection
|
552
|
-
# # => <ActiveRecord::Reflection::
|
668
|
+
# # => <ActiveRecord::Reflection::HasManyReflection: @name=:taggings, @active_record=Post, @plural_name="taggings">
|
553
669
|
#
|
554
670
|
def through_reflection
|
555
671
|
active_record._reflect_on_association(options[:through])
|
@@ -569,8 +685,8 @@ module ActiveRecord
|
|
569
685
|
#
|
570
686
|
# tags_reflection = Post.reflect_on_association(:tags)
|
571
687
|
# tags_reflection.chain
|
572
|
-
# # => [<ActiveRecord::Reflection::ThroughReflection: @
|
573
|
-
# <ActiveRecord::Reflection::
|
688
|
+
# # => [<ActiveRecord::Reflection::ThroughReflection: @delegate_reflection=#<ActiveRecord::Reflection::HasManyReflection: @name=:tags...>,
|
689
|
+
# <ActiveRecord::Reflection::HasManyReflection: @name=:taggings, @options={}, @active_record=Post>]
|
574
690
|
#
|
575
691
|
def chain
|
576
692
|
@chain ||= begin
|
@@ -611,11 +727,8 @@ module ActiveRecord
|
|
611
727
|
through_scope_chain = through_reflection.scope_chain.map(&:dup)
|
612
728
|
|
613
729
|
if options[:source_type]
|
614
|
-
|
615
|
-
|
616
|
-
through_scope_chain.first << lambda { |object|
|
617
|
-
where(type => source_type)
|
618
|
-
}
|
730
|
+
through_scope_chain.first <<
|
731
|
+
through_reflection.klass.where(foreign_type => options[:source_type])
|
619
732
|
end
|
620
733
|
|
621
734
|
# Recursively fill out the rest of the array from the through reflection
|
@@ -623,8 +736,14 @@ module ActiveRecord
|
|
623
736
|
end
|
624
737
|
end
|
625
738
|
|
739
|
+
def join_keys(assoc_klass)
|
740
|
+
source_reflection.join_keys(assoc_klass)
|
741
|
+
end
|
742
|
+
|
626
743
|
# The macro used by the source association
|
627
744
|
def source_macro
|
745
|
+
ActiveSupport::Deprecation.warn("ActiveRecord::Base.source_macro is deprecated and " \
|
746
|
+
"will be removed without replacement.")
|
628
747
|
source_reflection.source_macro
|
629
748
|
end
|
630
749
|
|
@@ -654,11 +773,11 @@ module ActiveRecord
|
|
654
773
|
# # => [:tag, :tags]
|
655
774
|
#
|
656
775
|
def source_reflection_names
|
657
|
-
|
776
|
+
options[:source] ? [options[:source]] : [name.to_s.singularize, name].uniq
|
658
777
|
end
|
659
778
|
|
660
779
|
def source_reflection_name # :nodoc:
|
661
|
-
return @source_reflection_name
|
780
|
+
return @source_reflection_name if @source_reflection_name
|
662
781
|
|
663
782
|
names = [name.to_s.singularize, name].collect { |n| n.to_sym }.uniq
|
664
783
|
names = names.find_all { |n|
|
@@ -690,12 +809,16 @@ directive on your declaration like:
|
|
690
809
|
through_reflection.options
|
691
810
|
end
|
692
811
|
|
812
|
+
def join_id_for(owner) # :nodoc:
|
813
|
+
source_reflection.join_id_for(owner)
|
814
|
+
end
|
815
|
+
|
693
816
|
def check_validity!
|
694
817
|
if through_reflection.nil?
|
695
818
|
raise HasManyThroughAssociationNotFoundError.new(active_record.name, self)
|
696
819
|
end
|
697
820
|
|
698
|
-
if through_reflection.
|
821
|
+
if through_reflection.polymorphic?
|
699
822
|
raise HasManyThroughAssociationPolymorphicThroughError.new(active_record.name, self)
|
700
823
|
end
|
701
824
|
|
@@ -703,15 +826,15 @@ directive on your declaration like:
|
|
703
826
|
raise HasManyThroughSourceAssociationNotFoundError.new(self)
|
704
827
|
end
|
705
828
|
|
706
|
-
if options[:source_type] && source_reflection.
|
829
|
+
if options[:source_type] && !source_reflection.polymorphic?
|
707
830
|
raise HasManyThroughAssociationPointlessSourceTypeError.new(active_record.name, self, source_reflection)
|
708
831
|
end
|
709
832
|
|
710
|
-
if source_reflection.
|
833
|
+
if source_reflection.polymorphic? && options[:source_type].nil?
|
711
834
|
raise HasManyThroughAssociationPolymorphicSourceError.new(active_record.name, self, source_reflection)
|
712
835
|
end
|
713
836
|
|
714
|
-
if
|
837
|
+
if has_one? && through_reflection.collection?
|
715
838
|
raise HasOneThroughCantAssociateThroughCollection.new(active_record.name, self, through_reflection)
|
716
839
|
end
|
717
840
|
|
@@ -720,15 +843,25 @@ directive on your declaration like:
|
|
720
843
|
|
721
844
|
protected
|
722
845
|
|
723
|
-
|
724
|
-
|
725
|
-
|
846
|
+
def actual_source_reflection # FIXME: this is a horrible name
|
847
|
+
source_reflection.send(:actual_source_reflection)
|
848
|
+
end
|
849
|
+
|
850
|
+
def primary_key(klass)
|
851
|
+
klass.primary_key || raise(UnknownPrimaryKey.new(klass))
|
852
|
+
end
|
726
853
|
|
727
854
|
private
|
728
855
|
def derive_class_name
|
729
856
|
# get the class_name of the belongs_to association of the through reflection
|
730
857
|
options[:source_type] || source_reflection.class_name
|
731
858
|
end
|
859
|
+
|
860
|
+
delegate_methods = AssociationReflection.public_instance_methods -
|
861
|
+
public_instance_methods
|
862
|
+
|
863
|
+
delegate(*delegate_methods, to: :delegate_reflection)
|
864
|
+
|
732
865
|
end
|
733
866
|
end
|
734
867
|
end
|
@@ -1,4 +1,3 @@
|
|
1
|
-
|
2
1
|
module ActiveRecord
|
3
2
|
module Batches
|
4
3
|
# Looping through a collection of records from the database
|
@@ -115,7 +114,6 @@ module ActiveRecord
|
|
115
114
|
end
|
116
115
|
|
117
116
|
relation = relation.reorder(batch_order).limit(batch_size)
|
118
|
-
relation.reverse_order_value = false
|
119
117
|
records = start ? relation.where(table[primary_key].gteq(start)).to_a : relation.to_a
|
120
118
|
|
121
119
|
while records.any?
|