activerecord 4.1.16 → 4.2.11.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of activerecord might be problematic. Click here for more details.

Files changed (185) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG.md +1162 -1801
  3. data/README.rdoc +15 -10
  4. data/lib/active_record/aggregations.rb +15 -8
  5. data/lib/active_record/association_relation.rb +13 -0
  6. data/lib/active_record/associations/alias_tracker.rb +3 -12
  7. data/lib/active_record/associations/association.rb +16 -4
  8. data/lib/active_record/associations/association_scope.rb +83 -38
  9. data/lib/active_record/associations/belongs_to_association.rb +28 -10
  10. data/lib/active_record/associations/builder/association.rb +15 -4
  11. data/lib/active_record/associations/builder/belongs_to.rb +7 -29
  12. data/lib/active_record/associations/builder/collection_association.rb +5 -1
  13. data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +8 -13
  14. data/lib/active_record/associations/builder/has_many.rb +1 -1
  15. data/lib/active_record/associations/builder/has_one.rb +2 -2
  16. data/lib/active_record/associations/builder/singular_association.rb +8 -1
  17. data/lib/active_record/associations/collection_association.rb +63 -27
  18. data/lib/active_record/associations/collection_proxy.rb +29 -35
  19. data/lib/active_record/associations/foreign_association.rb +11 -0
  20. data/lib/active_record/associations/has_many_association.rb +83 -22
  21. data/lib/active_record/associations/has_many_through_association.rb +49 -26
  22. data/lib/active_record/associations/has_one_association.rb +1 -1
  23. data/lib/active_record/associations/join_dependency/join_association.rb +25 -15
  24. data/lib/active_record/associations/join_dependency/join_part.rb +0 -1
  25. data/lib/active_record/associations/join_dependency.rb +26 -13
  26. data/lib/active_record/associations/preloader/association.rb +14 -11
  27. data/lib/active_record/associations/preloader/through_association.rb +4 -3
  28. data/lib/active_record/associations/preloader.rb +36 -26
  29. data/lib/active_record/associations/singular_association.rb +17 -2
  30. data/lib/active_record/associations/through_association.rb +5 -12
  31. data/lib/active_record/associations.rb +158 -49
  32. data/lib/active_record/attribute.rb +163 -0
  33. data/lib/active_record/attribute_assignment.rb +19 -11
  34. data/lib/active_record/attribute_decorators.rb +66 -0
  35. data/lib/active_record/attribute_methods/before_type_cast.rb +7 -2
  36. data/lib/active_record/attribute_methods/dirty.rb +107 -43
  37. data/lib/active_record/attribute_methods/primary_key.rb +7 -8
  38. data/lib/active_record/attribute_methods/query.rb +1 -1
  39. data/lib/active_record/attribute_methods/read.rb +22 -59
  40. data/lib/active_record/attribute_methods/serialization.rb +16 -150
  41. data/lib/active_record/attribute_methods/time_zone_conversion.rb +38 -40
  42. data/lib/active_record/attribute_methods/write.rb +9 -24
  43. data/lib/active_record/attribute_methods.rb +56 -94
  44. data/lib/active_record/attribute_set/builder.rb +106 -0
  45. data/lib/active_record/attribute_set.rb +81 -0
  46. data/lib/active_record/attributes.rb +147 -0
  47. data/lib/active_record/autosave_association.rb +19 -12
  48. data/lib/active_record/base.rb +13 -24
  49. data/lib/active_record/callbacks.rb +6 -6
  50. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +84 -52
  51. data/lib/active_record/connection_adapters/abstract/database_statements.rb +52 -50
  52. data/lib/active_record/connection_adapters/abstract/query_cache.rb +1 -1
  53. data/lib/active_record/connection_adapters/abstract/quoting.rb +60 -60
  54. data/lib/active_record/connection_adapters/abstract/savepoints.rb +1 -1
  55. data/lib/active_record/connection_adapters/abstract/schema_creation.rb +39 -4
  56. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +138 -56
  57. data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +14 -34
  58. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +268 -71
  59. data/lib/active_record/connection_adapters/abstract/transaction.rb +125 -118
  60. data/lib/active_record/connection_adapters/abstract_adapter.rb +171 -59
  61. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +293 -139
  62. data/lib/active_record/connection_adapters/column.rb +29 -240
  63. data/lib/active_record/connection_adapters/connection_specification.rb +15 -24
  64. data/lib/active_record/connection_adapters/mysql2_adapter.rb +16 -32
  65. data/lib/active_record/connection_adapters/mysql_adapter.rb +67 -144
  66. data/lib/active_record/connection_adapters/postgresql/array_parser.rb +15 -27
  67. data/lib/active_record/connection_adapters/postgresql/column.rb +20 -0
  68. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +40 -25
  69. data/lib/active_record/connection_adapters/postgresql/oid/array.rb +100 -0
  70. data/lib/active_record/connection_adapters/postgresql/oid/bit.rb +52 -0
  71. data/lib/active_record/connection_adapters/postgresql/oid/bit_varying.rb +13 -0
  72. data/lib/active_record/connection_adapters/postgresql/oid/bytea.rb +15 -0
  73. data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +46 -0
  74. data/lib/active_record/connection_adapters/postgresql/oid/date.rb +11 -0
  75. data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +36 -0
  76. data/lib/active_record/connection_adapters/postgresql/oid/decimal.rb +13 -0
  77. data/lib/active_record/connection_adapters/postgresql/oid/enum.rb +19 -0
  78. data/lib/active_record/connection_adapters/postgresql/oid/float.rb +21 -0
  79. data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +59 -0
  80. data/lib/active_record/connection_adapters/postgresql/oid/inet.rb +13 -0
  81. data/lib/active_record/connection_adapters/postgresql/oid/infinity.rb +13 -0
  82. data/lib/active_record/connection_adapters/postgresql/oid/integer.rb +11 -0
  83. data/lib/active_record/connection_adapters/postgresql/oid/json.rb +35 -0
  84. data/lib/active_record/connection_adapters/postgresql/oid/jsonb.rb +23 -0
  85. data/lib/active_record/connection_adapters/postgresql/oid/money.rb +43 -0
  86. data/lib/active_record/connection_adapters/postgresql/oid/point.rb +43 -0
  87. data/lib/active_record/connection_adapters/postgresql/oid/range.rb +79 -0
  88. data/lib/active_record/connection_adapters/postgresql/oid/specialized_string.rb +19 -0
  89. data/lib/active_record/connection_adapters/postgresql/oid/time.rb +11 -0
  90. data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +109 -0
  91. data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +21 -0
  92. data/lib/active_record/connection_adapters/postgresql/oid/vector.rb +26 -0
  93. data/lib/active_record/connection_adapters/postgresql/oid/xml.rb +28 -0
  94. data/lib/active_record/connection_adapters/postgresql/oid.rb +29 -388
  95. data/lib/active_record/connection_adapters/postgresql/quoting.rb +46 -136
  96. data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +4 -4
  97. data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +152 -0
  98. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +131 -43
  99. data/lib/active_record/connection_adapters/postgresql/utils.rb +77 -0
  100. data/lib/active_record/connection_adapters/postgresql_adapter.rb +224 -477
  101. data/lib/active_record/connection_adapters/schema_cache.rb +14 -28
  102. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +61 -75
  103. data/lib/active_record/connection_handling.rb +1 -1
  104. data/lib/active_record/core.rb +163 -39
  105. data/lib/active_record/counter_cache.rb +60 -6
  106. data/lib/active_record/enum.rb +9 -11
  107. data/lib/active_record/errors.rb +53 -30
  108. data/lib/active_record/explain.rb +1 -1
  109. data/lib/active_record/explain_subscriber.rb +1 -1
  110. data/lib/active_record/fixtures.rb +55 -69
  111. data/lib/active_record/gem_version.rb +4 -4
  112. data/lib/active_record/inheritance.rb +35 -10
  113. data/lib/active_record/integration.rb +4 -4
  114. data/lib/active_record/legacy_yaml_adapter.rb +30 -0
  115. data/lib/active_record/locking/optimistic.rb +46 -26
  116. data/lib/active_record/migration/command_recorder.rb +19 -2
  117. data/lib/active_record/migration/join_table.rb +1 -1
  118. data/lib/active_record/migration.rb +71 -46
  119. data/lib/active_record/model_schema.rb +52 -58
  120. data/lib/active_record/nested_attributes.rb +5 -5
  121. data/lib/active_record/no_touching.rb +1 -1
  122. data/lib/active_record/persistence.rb +46 -26
  123. data/lib/active_record/query_cache.rb +3 -3
  124. data/lib/active_record/querying.rb +10 -7
  125. data/lib/active_record/railtie.rb +18 -11
  126. data/lib/active_record/railties/databases.rake +50 -51
  127. data/lib/active_record/readonly_attributes.rb +0 -1
  128. data/lib/active_record/reflection.rb +273 -114
  129. data/lib/active_record/relation/batches.rb +0 -2
  130. data/lib/active_record/relation/calculations.rb +41 -37
  131. data/lib/active_record/relation/finder_methods.rb +70 -47
  132. data/lib/active_record/relation/merger.rb +39 -29
  133. data/lib/active_record/relation/predicate_builder/array_handler.rb +32 -13
  134. data/lib/active_record/relation/predicate_builder/relation_handler.rb +1 -5
  135. data/lib/active_record/relation/predicate_builder.rb +16 -8
  136. data/lib/active_record/relation/query_methods.rb +114 -65
  137. data/lib/active_record/relation/spawn_methods.rb +3 -0
  138. data/lib/active_record/relation.rb +57 -25
  139. data/lib/active_record/result.rb +18 -7
  140. data/lib/active_record/sanitization.rb +12 -2
  141. data/lib/active_record/schema.rb +0 -1
  142. data/lib/active_record/schema_dumper.rb +59 -28
  143. data/lib/active_record/schema_migration.rb +5 -4
  144. data/lib/active_record/scoping/default.rb +6 -4
  145. data/lib/active_record/scoping/named.rb +4 -0
  146. data/lib/active_record/serializers/xml_serializer.rb +3 -7
  147. data/lib/active_record/statement_cache.rb +95 -10
  148. data/lib/active_record/store.rb +5 -5
  149. data/lib/active_record/tasks/database_tasks.rb +61 -6
  150. data/lib/active_record/tasks/mysql_database_tasks.rb +20 -11
  151. data/lib/active_record/tasks/postgresql_database_tasks.rb +20 -9
  152. data/lib/active_record/timestamp.rb +9 -7
  153. data/lib/active_record/transactions.rb +53 -27
  154. data/lib/active_record/type/big_integer.rb +13 -0
  155. data/lib/active_record/type/binary.rb +50 -0
  156. data/lib/active_record/type/boolean.rb +31 -0
  157. data/lib/active_record/type/date.rb +50 -0
  158. data/lib/active_record/type/date_time.rb +54 -0
  159. data/lib/active_record/type/decimal.rb +64 -0
  160. data/lib/active_record/type/decimal_without_scale.rb +11 -0
  161. data/lib/active_record/type/decorator.rb +14 -0
  162. data/lib/active_record/type/float.rb +19 -0
  163. data/lib/active_record/type/hash_lookup_type_map.rb +23 -0
  164. data/lib/active_record/type/integer.rb +59 -0
  165. data/lib/active_record/type/mutable.rb +16 -0
  166. data/lib/active_record/type/numeric.rb +36 -0
  167. data/lib/active_record/type/serialized.rb +62 -0
  168. data/lib/active_record/type/string.rb +40 -0
  169. data/lib/active_record/type/text.rb +11 -0
  170. data/lib/active_record/type/time.rb +26 -0
  171. data/lib/active_record/type/time_value.rb +38 -0
  172. data/lib/active_record/type/type_map.rb +64 -0
  173. data/lib/active_record/type/unsigned_integer.rb +15 -0
  174. data/lib/active_record/type/value.rb +110 -0
  175. data/lib/active_record/type.rb +23 -0
  176. data/lib/active_record/validations/associated.rb +5 -3
  177. data/lib/active_record/validations/presence.rb +5 -3
  178. data/lib/active_record/validations/uniqueness.rb +25 -29
  179. data/lib/active_record/validations.rb +25 -19
  180. data/lib/active_record.rb +4 -0
  181. data/lib/rails/generators/active_record/migration/migration_generator.rb +8 -4
  182. data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb +1 -1
  183. data/lib/rails/generators/active_record/model/templates/model.rb +1 -1
  184. metadata +66 -11
  185. data/lib/active_record/connection_adapters/postgresql/cast.rb +0 -168
@@ -1,3 +1,6 @@
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:
@@ -11,25 +14,33 @@ module ActiveRecord
11
14
  end
12
15
 
13
16
  def self.create(macro, name, scope, options, ar)
14
- case macro
15
- when :has_many, :belongs_to, :has_one
16
- klass = options[:through] ? ThroughReflection : AssociationReflection
17
- when :composed_of
18
- klass = AggregateReflection
19
- end
20
-
21
- klass.new(macro, name, scope, options, ar)
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._reflections = ar._reflections.merge(name.to_sym => reflection)
35
+ ar.clear_reflections_cache
36
+ ar._reflections = ar._reflections.merge(name.to_s => reflection)
26
37
  end
27
38
 
28
39
  def self.add_aggregate_reflection(ar, name, reflection)
29
- ar.aggregate_reflections = ar.aggregate_reflections.merge(name.to_sym => reflection)
40
+ ar.aggregate_reflections = ar.aggregate_reflections.merge(name.to_s => reflection)
30
41
  end
31
42
 
32
- # \Reflection enables to interrogate Active Record classes and objects
43
+ # \Reflection enables interrogating of Active Record classes and objects
33
44
  # about their associations and aggregations. This information can,
34
45
  # for example, be used in a form builder that takes an Active Record object
35
46
  # and creates input fields for all of the attributes depending on their type
@@ -48,25 +59,30 @@ module ActiveRecord
48
59
  # Account.reflect_on_aggregation(:balance) # => the balance AggregateReflection
49
60
  #
50
61
  def reflect_on_aggregation(aggregation)
51
- aggregate_reflections[aggregation.to_sym]
62
+ aggregate_reflections[aggregation.to_s]
52
63
  end
53
64
 
54
65
  # Returns a Hash of name of the reflection as the key and a AssociationReflection as the value.
55
66
  #
56
- # Account.reflections # => {balance: AggregateReflection}
67
+ # Account.reflections # => {"balance" => AggregateReflection}
57
68
  #
58
69
  # @api public
59
70
  def reflections
60
- ref = {}
61
- _reflections.each do |name, reflection|
62
- parent_name, parent_reflection = reflection.parent_reflection
63
- if parent_name
64
- ref[parent_name] = parent_reflection
65
- else
66
- ref[name] = reflection
71
+ @__reflections ||= begin
72
+ ref = {}
73
+
74
+ _reflections.each do |name, reflection|
75
+ parent_name, parent_reflection = reflection.parent_reflection
76
+
77
+ if parent_name
78
+ ref[parent_name] = parent_reflection
79
+ else
80
+ ref[name] = reflection
81
+ end
67
82
  end
83
+
84
+ ref
68
85
  end
69
- ref
70
86
  end
71
87
 
72
88
  # Returns an array of AssociationReflection objects for all the
@@ -92,12 +108,12 @@ module ActiveRecord
92
108
  #
93
109
  # @api public
94
110
  def reflect_on_association(association)
95
- reflections[association.to_sym]
111
+ reflections[association.to_s]
96
112
  end
97
113
 
98
114
  # @api private
99
115
  def _reflect_on_association(association) #:nodoc:
100
- _reflections[association.to_sym]
116
+ _reflections[association.to_s]
101
117
  end
102
118
 
103
119
  # Returns an array of AssociationReflection objects for all associations which have <tt>:autosave</tt> enabled.
@@ -106,28 +122,87 @@ module ActiveRecord
106
122
  def reflect_on_all_autosave_associations
107
123
  reflections.values.select { |reflection| reflection.options[:autosave] }
108
124
  end
125
+
126
+ def clear_reflections_cache #:nodoc:
127
+ @__reflections = nil
128
+ end
109
129
  end
110
130
 
131
+ # Holds all the methods that are shared between MacroReflection, AssociationReflection
132
+ # and ThroughReflection
133
+ class AbstractReflection # :nodoc:
134
+ def table_name
135
+ klass.table_name
136
+ end
137
+
138
+ # Returns a new, unsaved instance of the associated class. +attributes+ will
139
+ # be passed to the class's constructor.
140
+ def build_association(attributes, &block)
141
+ klass.new(attributes, &block)
142
+ end
143
+
144
+ def quoted_table_name
145
+ klass.quoted_table_name
146
+ end
147
+
148
+ def primary_key_type
149
+ klass.type_for_attribute(klass.primary_key)
150
+ end
151
+
152
+ # Returns the class name for the macro.
153
+ #
154
+ # <tt>composed_of :balance, class_name: 'Money'</tt> returns <tt>'Money'</tt>
155
+ # <tt>has_many :clients</tt> returns <tt>'Client'</tt>
156
+ def class_name
157
+ @class_name ||= (options[:class_name] || derive_class_name).to_s
158
+ end
159
+
160
+ JoinKeys = Struct.new(:key, :foreign_key) # :nodoc:
161
+
162
+ def join_keys(assoc_klass)
163
+ JoinKeys.new(foreign_key, active_record_primary_key)
164
+ end
165
+
166
+ def source_macro
167
+ ActiveSupport::Deprecation.warn(<<-MSG.squish)
168
+ ActiveRecord::Base.source_macro is deprecated and will be removed
169
+ without replacement.
170
+ MSG
171
+
172
+ macro
173
+ end
174
+
175
+ def inverse_of
176
+ return unless inverse_name
177
+
178
+ @inverse_of ||= klass._reflect_on_association inverse_name
179
+ end
180
+
181
+ def check_validity_of_inverse!
182
+ unless polymorphic?
183
+ if has_inverse? && inverse_of.nil?
184
+ raise InverseOfAssociationNotFoundError.new(self)
185
+ end
186
+ end
187
+ end
188
+ end
111
189
  # Base class for AggregateReflection and AssociationReflection. Objects of
112
190
  # AggregateReflection and AssociationReflection are returned by the Reflection::ClassMethods.
113
191
  #
114
192
  # MacroReflection
115
- # AggregateReflection
116
193
  # AssociationReflection
117
- # ThroughReflection
118
- class MacroReflection
194
+ # AggregateReflection
195
+ # HasManyReflection
196
+ # HasOneReflection
197
+ # BelongsToReflection
198
+ # ThroughReflection
199
+ class MacroReflection < AbstractReflection
119
200
  # Returns the name of the macro.
120
201
  #
121
202
  # <tt>composed_of :balance, class_name: 'Money'</tt> returns <tt>:balance</tt>
122
203
  # <tt>has_many :clients</tt> returns <tt>:clients</tt>
123
204
  attr_reader :name
124
205
 
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
206
  attr_reader :scope
132
207
 
133
208
  # Returns the hash of options used for the macro.
@@ -140,8 +215,7 @@ module ActiveRecord
140
215
 
141
216
  attr_reader :plural_name # :nodoc:
142
217
 
143
- def initialize(macro, name, scope, options, active_record)
144
- @macro = macro
218
+ def initialize(name, scope, options, active_record)
145
219
  @name = name
146
220
  @scope = scope
147
221
  @options = options
@@ -165,15 +239,11 @@ module ActiveRecord
165
239
  # <tt>composed_of :balance, class_name: 'Money'</tt> returns the Money class
166
240
  # <tt>has_many :clients</tt> returns the Client class
167
241
  def klass
168
- @klass ||= class_name.constantize
242
+ @klass ||= compute_class(class_name)
169
243
  end
170
244
 
171
- # Returns the class name for the macro.
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
245
+ def compute_class(name)
246
+ name.constantize
177
247
  end
178
248
 
179
249
  # Returns +true+ if +self+ and +other_aggregation+ have the same +name+ attribute, +active_record+ attribute,
@@ -218,49 +288,46 @@ module ActiveRecord
218
288
  # a new association object. Use +build_association+ or +create_association+
219
289
  # instead. This allows plugins to hook into association object creation.
220
290
  def klass
221
- @klass ||= active_record.send(:compute_type, class_name)
291
+ @klass ||= compute_class(class_name)
292
+ end
293
+
294
+ def compute_class(name)
295
+ active_record.send(:compute_type, name)
222
296
  end
223
297
 
224
298
  attr_reader :type, :foreign_type
225
299
  attr_accessor :parent_reflection # [:name, Reflection]
226
300
 
227
- def initialize(macro, name, scope, options, active_record)
301
+ def initialize(name, scope, options, active_record)
228
302
  super
229
- @collection = [:has_many, :has_and_belongs_to_many].include?(macro)
230
303
  @automatic_inverse_of = nil
231
- @type = options[:as] && "#{options[:as]}_type"
304
+ @type = options[:as] && (options[:foreign_type] || "#{options[:as]}_type")
232
305
  @foreign_type = options[:foreign_type] || "#{name}_type"
233
306
  @constructable = calculate_constructable(macro, options)
307
+ @association_scope_cache = {}
308
+ @scope_lock = Mutex.new
234
309
  end
235
310
 
236
- # Returns a new, unsaved instance of the associated class. +attributes+ will
237
- # be passed to the class's constructor.
238
- def build_association(attributes, &block)
239
- klass.new(attributes, &block)
311
+ def association_scope_cache(conn, owner)
312
+ key = conn.prepared_statements
313
+ if polymorphic?
314
+ key = [key, owner._read_attribute(@foreign_type)]
315
+ end
316
+ @association_scope_cache[key] ||= @scope_lock.synchronize {
317
+ @association_scope_cache[key] ||= yield
318
+ }
240
319
  end
241
320
 
242
321
  def constructable? # :nodoc:
243
322
  @constructable
244
323
  end
245
324
 
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
325
  def join_table
255
326
  @join_table ||= options[:join_table] || derive_join_table
256
327
  end
257
328
 
258
329
  def foreign_key
259
- @foreign_key ||= options[:foreign_key] || derive_foreign_key
260
- end
261
-
262
- def primary_key_column
263
- klass.columns_hash[klass.primary_key]
330
+ @foreign_key ||= options[:foreign_key] || derive_foreign_key.freeze
264
331
  end
265
332
 
266
333
  def association_foreign_key
@@ -288,13 +355,25 @@ module ActiveRecord
288
355
  check_validity_of_inverse!
289
356
  end
290
357
 
291
- def check_validity_of_inverse!
292
- unless options[:polymorphic]
293
- if has_inverse? && inverse_of.nil?
294
- raise InverseOfAssociationNotFoundError.new(self)
295
- end
358
+ def check_preloadable!
359
+ return unless scope
360
+
361
+ if scope.arity > 0
362
+ ActiveSupport::Deprecation.warn(<<-MSG.squish)
363
+ The association scope '#{name}' is instance dependent (the scope
364
+ block takes an argument). Preloading happens before the individual
365
+ instances are created. This means that there is no instance being
366
+ passed to the association scope. This will most likely result in
367
+ broken or incorrect behavior. Joining, Preloading and eager loading
368
+ of these associations is deprecated and will be removed in the future.
369
+ MSG
296
370
  end
297
371
  end
372
+ alias :check_eager_loadable! :check_preloadable!
373
+
374
+ def join_id_for(owner) # :nodoc:
375
+ owner[active_record_primary_key]
376
+ end
298
377
 
299
378
  def through_reflection
300
379
  nil
@@ -320,18 +399,10 @@ module ActiveRecord
320
399
  scope ? [[scope]] : [[]]
321
400
  end
322
401
 
323
- alias :source_macro :macro
324
-
325
402
  def has_inverse?
326
403
  inverse_name
327
404
  end
328
405
 
329
- def inverse_of
330
- return unless inverse_name
331
-
332
- @inverse_of ||= klass._reflect_on_association inverse_name
333
- end
334
-
335
406
  def polymorphic_inverse_of(associated_class)
336
407
  if has_inverse?
337
408
  if inverse_relationship = associated_class._reflect_on_association(options[:inverse_of])
@@ -342,11 +413,16 @@ module ActiveRecord
342
413
  end
343
414
  end
344
415
 
416
+ # Returns the macro type.
417
+ #
418
+ # <tt>has_many :clients</tt> returns <tt>:has_many</tt>
419
+ def macro; raise NotImplementedError; end
420
+
345
421
  # Returns whether or not this association reflection is for a collection
346
422
  # association. Returns +true+ if the +macro+ is either +has_many+ or
347
423
  # +has_and_belongs_to_many+, +false+ otherwise.
348
424
  def collection?
349
- @collection
425
+ false
350
426
  end
351
427
 
352
428
  # Returns whether or not the association should be validated as part of
@@ -359,18 +435,19 @@ module ActiveRecord
359
435
  # * you use autosave; <tt>autosave: true</tt>
360
436
  # * the association is a +has_many+ association
361
437
  def validate?
362
- !options[:validate].nil? ? options[:validate] : (options[:autosave] == true || macro == :has_many)
438
+ !options[:validate].nil? ? options[:validate] : (options[:autosave] == true || collection?)
363
439
  end
364
440
 
365
441
  # Returns +true+ if +self+ is a +belongs_to+ reflection.
366
- def belongs_to?
367
- macro == :belongs_to
368
- end
442
+ def belongs_to?; false; end
443
+
444
+ # Returns +true+ if +self+ is a +has_one+ reflection.
445
+ def has_one?; false; end
369
446
 
370
447
  def association_class
371
448
  case macro
372
449
  when :belongs_to
373
- if options[:polymorphic]
450
+ if polymorphic?
374
451
  Associations::BelongsToPolymorphicAssociation
375
452
  else
376
453
  Associations::BelongsToAssociation
@@ -391,7 +468,7 @@ module ActiveRecord
391
468
  end
392
469
 
393
470
  def polymorphic?
394
- options.key? :polymorphic
471
+ options[:polymorphic]
395
472
  end
396
473
 
397
474
  VALID_AUTOMATIC_INVERSE_MACROS = [:has_many, :has_one, :belongs_to]
@@ -408,7 +485,7 @@ module ActiveRecord
408
485
  def calculate_constructable(macro, options)
409
486
  case macro
410
487
  when :belongs_to
411
- !options[:polymorphic]
488
+ !polymorphic?
412
489
  when :has_one
413
490
  !options[:through]
414
491
  else
@@ -497,7 +574,7 @@ module ActiveRecord
497
574
  end
498
575
 
499
576
  def derive_join_table
500
- [active_record.table_name, klass.table_name].sort.join("\0").gsub(/^(.*_)(.+)\0\1(.+)/, '\1\2_\3').gsub("\0", "_")
577
+ ModelSchema.derive_join_table_name active_record.table_name, klass.table_name
501
578
  end
502
579
 
503
580
  def primary_key(klass)
@@ -505,15 +582,72 @@ module ActiveRecord
505
582
  end
506
583
  end
507
584
 
585
+ class HasManyReflection < AssociationReflection # :nodoc:
586
+ def initialize(name, scope, options, active_record)
587
+ super(name, scope, options, active_record)
588
+ end
589
+
590
+ def macro; :has_many; end
591
+
592
+ def collection?; true; end
593
+ end
594
+
595
+ class HasOneReflection < AssociationReflection # :nodoc:
596
+ def initialize(name, scope, options, active_record)
597
+ super(name, scope, options, active_record)
598
+ end
599
+
600
+ def macro; :has_one; end
601
+
602
+ def has_one?; true; end
603
+ end
604
+
605
+ class BelongsToReflection < AssociationReflection # :nodoc:
606
+ def initialize(name, scope, options, active_record)
607
+ super(name, scope, options, active_record)
608
+ end
609
+
610
+ def macro; :belongs_to; end
611
+
612
+ def belongs_to?; true; end
613
+
614
+ def join_keys(assoc_klass)
615
+ key = polymorphic? ? association_primary_key(assoc_klass) : association_primary_key
616
+ JoinKeys.new(key, foreign_key)
617
+ end
618
+
619
+ def join_id_for(owner) # :nodoc:
620
+ owner[foreign_key]
621
+ end
622
+ end
623
+
624
+ class HasAndBelongsToManyReflection < AssociationReflection # :nodoc:
625
+ def initialize(name, scope, options, active_record)
626
+ super
627
+ end
628
+
629
+ def macro; :has_and_belongs_to_many; end
630
+
631
+ def collection?
632
+ true
633
+ end
634
+ end
635
+
508
636
  # Holds all the meta-data about a :through association as it was specified
509
637
  # in the Active Record class.
510
- class ThroughReflection < AssociationReflection #:nodoc:
638
+ class ThroughReflection < AbstractReflection #:nodoc:
639
+ attr_reader :delegate_reflection
511
640
  delegate :foreign_key, :foreign_type, :association_foreign_key,
512
641
  :active_record_primary_key, :type, :to => :source_reflection
513
642
 
514
- def initialize(macro, name, scope, options, active_record)
515
- super
516
- @source_reflection_name = options[:source]
643
+ def initialize(delegate_reflection)
644
+ @delegate_reflection = delegate_reflection
645
+ @klass = delegate_reflection.options[:anonymous_class]
646
+ @source_reflection_name = delegate_reflection.options[:source]
647
+ end
648
+
649
+ def klass
650
+ @klass ||= delegate_reflection.compute_class(class_name)
517
651
  end
518
652
 
519
653
  # Returns the source of the through reflection. It checks both a singularized
@@ -531,12 +665,10 @@ module ActiveRecord
531
665
  #
532
666
  # tags_reflection = Post.reflect_on_association(:tags)
533
667
  # tags_reflection.source_reflection
534
- # # => <ActiveRecord::Reflection::AssociationReflection: @macro=:belongs_to, @name=:tag, @active_record=Tagging, @plural_name="tags">
668
+ # # => <ActiveRecord::Reflection::BelongsToReflection: @name=:tag, @active_record=Tagging, @plural_name="tags">
535
669
  #
536
670
  def source_reflection
537
- if source_reflection_name
538
- through_reflection.klass._reflect_on_association(source_reflection_name)
539
- end
671
+ through_reflection.klass._reflect_on_association(source_reflection_name)
540
672
  end
541
673
 
542
674
  # Returns the AssociationReflection object specified in the <tt>:through</tt> option
@@ -549,7 +681,7 @@ module ActiveRecord
549
681
  #
550
682
  # tags_reflection = Post.reflect_on_association(:tags)
551
683
  # tags_reflection.through_reflection
552
- # # => <ActiveRecord::Reflection::AssociationReflection: @macro=:has_many, @name=:taggings, @active_record=Post, @plural_name="taggings">
684
+ # # => <ActiveRecord::Reflection::HasManyReflection: @name=:taggings, @active_record=Post, @plural_name="taggings">
553
685
  #
554
686
  def through_reflection
555
687
  active_record._reflect_on_association(options[:through])
@@ -569,8 +701,8 @@ module ActiveRecord
569
701
  #
570
702
  # tags_reflection = Post.reflect_on_association(:tags)
571
703
  # tags_reflection.chain
572
- # # => [<ActiveRecord::Reflection::ThroughReflection: @macro=:has_many, @name=:tags, @options={:through=>:taggings}, @active_record=Post>,
573
- # <ActiveRecord::Reflection::AssociationReflection: @macro=:has_many, @name=:taggings, @options={}, @active_record=Post>]
704
+ # # => [<ActiveRecord::Reflection::ThroughReflection: @delegate_reflection=#<ActiveRecord::Reflection::HasManyReflection: @name=:tags...>,
705
+ # <ActiveRecord::Reflection::HasManyReflection: @name=:taggings, @options={}, @active_record=Post>]
574
706
  #
575
707
  def chain
576
708
  @chain ||= begin
@@ -623,8 +755,17 @@ module ActiveRecord
623
755
  end
624
756
  end
625
757
 
758
+ def join_keys(assoc_klass)
759
+ source_reflection.join_keys(assoc_klass)
760
+ end
761
+
626
762
  # The macro used by the source association
627
763
  def source_macro
764
+ ActiveSupport::Deprecation.warn(<<-MSG.squish)
765
+ ActiveRecord::Base.source_macro is deprecated and will be removed
766
+ without replacement.
767
+ MSG
768
+
628
769
  source_reflection.source_macro
629
770
  end
630
771
 
@@ -654,11 +795,11 @@ module ActiveRecord
654
795
  # # => [:tag, :tags]
655
796
  #
656
797
  def source_reflection_names
657
- (options[:source] ? [options[:source]] : [name.to_s.singularize, name]).collect { |n| n.to_sym }.uniq
798
+ options[:source] ? [options[:source]] : [name.to_s.singularize, name].uniq
658
799
  end
659
800
 
660
801
  def source_reflection_name # :nodoc:
661
- return @source_reflection_name.to_sym if @source_reflection_name
802
+ return @source_reflection_name if @source_reflection_name
662
803
 
663
804
  names = [name.to_s.singularize, name].collect { |n| n.to_sym }.uniq
664
805
  names = names.find_all { |n|
@@ -668,15 +809,13 @@ module ActiveRecord
668
809
  if names.length > 1
669
810
  example_options = options.dup
670
811
  example_options[:source] = source_reflection_names.first
671
- ActiveSupport::Deprecation.warn <<-eowarn
672
- Ambiguous source reflection for through association. Please specify a :source
673
- directive on your declaration like:
674
-
675
- class #{active_record.name} < ActiveRecord::Base
676
- #{macro} :#{name}, #{example_options}
677
- end
678
-
679
- eowarn
812
+ ActiveSupport::Deprecation.warn \
813
+ "Ambiguous source reflection for through association. Please " \
814
+ "specify a :source directive on your declaration like:\n" \
815
+ "\n" \
816
+ " class #{active_record.name} < ActiveRecord::Base\n" \
817
+ " #{macro} :#{name}, #{example_options}\n" \
818
+ " end"
680
819
  end
681
820
 
682
821
  @source_reflection_name = names.first
@@ -690,28 +829,36 @@ directive on your declaration like:
690
829
  through_reflection.options
691
830
  end
692
831
 
832
+ def join_id_for(owner) # :nodoc:
833
+ source_reflection.join_id_for(owner)
834
+ end
835
+
693
836
  def check_validity!
694
837
  if through_reflection.nil?
695
838
  raise HasManyThroughAssociationNotFoundError.new(active_record.name, self)
696
839
  end
697
840
 
698
- if through_reflection.options[:polymorphic]
699
- raise HasManyThroughAssociationPolymorphicThroughError.new(active_record.name, self)
841
+ if through_reflection.polymorphic?
842
+ if has_one?
843
+ raise HasOneAssociationPolymorphicThroughError.new(active_record.name, self)
844
+ else
845
+ raise HasManyThroughAssociationPolymorphicThroughError.new(active_record.name, self)
846
+ end
700
847
  end
701
848
 
702
849
  if source_reflection.nil?
703
850
  raise HasManyThroughSourceAssociationNotFoundError.new(self)
704
851
  end
705
852
 
706
- if options[:source_type] && source_reflection.options[:polymorphic].nil?
853
+ if options[:source_type] && !source_reflection.polymorphic?
707
854
  raise HasManyThroughAssociationPointlessSourceTypeError.new(active_record.name, self, source_reflection)
708
855
  end
709
856
 
710
- if source_reflection.options[:polymorphic] && options[:source_type].nil?
857
+ if source_reflection.polymorphic? && options[:source_type].nil?
711
858
  raise HasManyThroughAssociationPolymorphicSourceError.new(active_record.name, self, source_reflection)
712
859
  end
713
860
 
714
- if macro == :has_one && through_reflection.collection?
861
+ if has_one? && through_reflection.collection?
715
862
  raise HasOneThroughCantAssociateThroughCollection.new(active_record.name, self, through_reflection)
716
863
  end
717
864
 
@@ -720,15 +867,27 @@ directive on your declaration like:
720
867
 
721
868
  protected
722
869
 
723
- def actual_source_reflection # FIXME: this is a horrible name
724
- source_reflection.actual_source_reflection
725
- end
870
+ def actual_source_reflection # FIXME: this is a horrible name
871
+ source_reflection.send(:actual_source_reflection)
872
+ end
873
+
874
+ def primary_key(klass)
875
+ klass.primary_key || raise(UnknownPrimaryKey.new(klass))
876
+ end
877
+
878
+ def inverse_name; delegate_reflection.send(:inverse_name); end
726
879
 
727
880
  private
728
881
  def derive_class_name
729
882
  # get the class_name of the belongs_to association of the through reflection
730
883
  options[:source_type] || source_reflection.class_name
731
884
  end
885
+
886
+ delegate_methods = AssociationReflection.public_instance_methods -
887
+ public_instance_methods
888
+
889
+ delegate(*delegate_methods, to: :delegate_reflection)
890
+
732
891
  end
733
892
  end
734
893
  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?