activerecord 4.2.11.3 → 5.0.7.2

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.

Files changed (251) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +1638 -1132
  3. data/MIT-LICENSE +2 -2
  4. data/README.rdoc +7 -8
  5. data/examples/performance.rb +2 -3
  6. data/examples/simple.rb +0 -1
  7. data/lib/active_record.rb +7 -2
  8. data/lib/active_record/aggregations.rb +34 -21
  9. data/lib/active_record/association_relation.rb +7 -4
  10. data/lib/active_record/associations.rb +347 -218
  11. data/lib/active_record/associations/alias_tracker.rb +19 -16
  12. data/lib/active_record/associations/association.rb +22 -10
  13. data/lib/active_record/associations/association_scope.rb +75 -104
  14. data/lib/active_record/associations/belongs_to_association.rb +21 -32
  15. data/lib/active_record/associations/builder/association.rb +28 -34
  16. data/lib/active_record/associations/builder/belongs_to.rb +43 -18
  17. data/lib/active_record/associations/builder/collection_association.rb +7 -19
  18. data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +16 -11
  19. data/lib/active_record/associations/builder/has_many.rb +4 -4
  20. data/lib/active_record/associations/builder/has_one.rb +11 -6
  21. data/lib/active_record/associations/builder/singular_association.rb +13 -11
  22. data/lib/active_record/associations/collection_association.rb +85 -69
  23. data/lib/active_record/associations/collection_proxy.rb +104 -46
  24. data/lib/active_record/associations/foreign_association.rb +1 -1
  25. data/lib/active_record/associations/has_many_association.rb +21 -78
  26. data/lib/active_record/associations/has_many_through_association.rb +6 -47
  27. data/lib/active_record/associations/has_one_association.rb +12 -5
  28. data/lib/active_record/associations/join_dependency.rb +38 -22
  29. data/lib/active_record/associations/join_dependency/join_association.rb +15 -14
  30. data/lib/active_record/associations/join_dependency/join_part.rb +2 -2
  31. data/lib/active_record/associations/preloader.rb +14 -4
  32. data/lib/active_record/associations/preloader/association.rb +52 -71
  33. data/lib/active_record/associations/preloader/collection_association.rb +0 -7
  34. data/lib/active_record/associations/preloader/has_many_through.rb +1 -1
  35. data/lib/active_record/associations/preloader/has_one.rb +0 -8
  36. data/lib/active_record/associations/preloader/singular_association.rb +0 -1
  37. data/lib/active_record/associations/preloader/through_association.rb +36 -17
  38. data/lib/active_record/associations/singular_association.rb +13 -1
  39. data/lib/active_record/associations/through_association.rb +12 -4
  40. data/lib/active_record/attribute.rb +69 -19
  41. data/lib/active_record/attribute/user_provided_default.rb +28 -0
  42. data/lib/active_record/attribute_assignment.rb +19 -140
  43. data/lib/active_record/attribute_decorators.rb +6 -5
  44. data/lib/active_record/attribute_methods.rb +69 -44
  45. data/lib/active_record/attribute_methods/before_type_cast.rb +1 -1
  46. data/lib/active_record/attribute_methods/dirty.rb +46 -86
  47. data/lib/active_record/attribute_methods/primary_key.rb +16 -3
  48. data/lib/active_record/attribute_methods/query.rb +2 -2
  49. data/lib/active_record/attribute_methods/read.rb +31 -59
  50. data/lib/active_record/attribute_methods/serialization.rb +13 -16
  51. data/lib/active_record/attribute_methods/time_zone_conversion.rb +61 -14
  52. data/lib/active_record/attribute_methods/write.rb +13 -37
  53. data/lib/active_record/attribute_mutation_tracker.rb +70 -0
  54. data/lib/active_record/attribute_set.rb +32 -3
  55. data/lib/active_record/attribute_set/builder.rb +42 -16
  56. data/lib/active_record/attributes.rb +199 -81
  57. data/lib/active_record/autosave_association.rb +54 -17
  58. data/lib/active_record/base.rb +32 -23
  59. data/lib/active_record/callbacks.rb +39 -43
  60. data/lib/active_record/coders/json.rb +1 -1
  61. data/lib/active_record/coders/yaml_column.rb +20 -8
  62. data/lib/active_record/collection_cache_key.rb +50 -0
  63. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +467 -189
  64. data/lib/active_record/connection_adapters/abstract/database_limits.rb +3 -3
  65. data/lib/active_record/connection_adapters/abstract/database_statements.rb +66 -62
  66. data/lib/active_record/connection_adapters/abstract/query_cache.rb +39 -4
  67. data/lib/active_record/connection_adapters/abstract/quoting.rb +86 -13
  68. data/lib/active_record/connection_adapters/abstract/savepoints.rb +3 -3
  69. data/lib/active_record/connection_adapters/abstract/schema_creation.rb +61 -39
  70. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +236 -188
  71. data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +72 -17
  72. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +407 -156
  73. data/lib/active_record/connection_adapters/abstract/transaction.rb +51 -34
  74. data/lib/active_record/connection_adapters/abstract_adapter.rb +177 -71
  75. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +433 -399
  76. data/lib/active_record/connection_adapters/column.rb +28 -43
  77. data/lib/active_record/connection_adapters/connection_specification.rb +15 -27
  78. data/lib/active_record/connection_adapters/determine_if_preparable_visitor.rb +22 -0
  79. data/lib/active_record/connection_adapters/mysql/column.rb +50 -0
  80. data/lib/active_record/connection_adapters/mysql/database_statements.rb +108 -0
  81. data/lib/active_record/connection_adapters/mysql/explain_pretty_printer.rb +70 -0
  82. data/lib/active_record/connection_adapters/mysql/quoting.rb +51 -0
  83. data/lib/active_record/connection_adapters/mysql/schema_creation.rb +67 -0
  84. data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +93 -0
  85. data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +54 -0
  86. data/lib/active_record/connection_adapters/mysql/type_metadata.rb +32 -0
  87. data/lib/active_record/connection_adapters/mysql2_adapter.rb +25 -166
  88. data/lib/active_record/connection_adapters/postgresql/column.rb +33 -11
  89. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +18 -72
  90. data/lib/active_record/connection_adapters/postgresql/explain_pretty_printer.rb +42 -0
  91. data/lib/active_record/connection_adapters/postgresql/oid.rb +1 -6
  92. data/lib/active_record/connection_adapters/postgresql/oid/array.rb +37 -57
  93. data/lib/active_record/connection_adapters/postgresql/oid/bit.rb +3 -3
  94. data/lib/active_record/connection_adapters/postgresql/oid/bytea.rb +2 -2
  95. data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +3 -1
  96. data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +7 -22
  97. data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +13 -3
  98. data/lib/active_record/connection_adapters/postgresql/oid/json.rb +1 -26
  99. data/lib/active_record/connection_adapters/postgresql/oid/jsonb.rb +2 -2
  100. data/lib/active_record/connection_adapters/postgresql/oid/money.rb +0 -4
  101. data/lib/active_record/connection_adapters/postgresql/oid/point.rb +4 -4
  102. data/lib/active_record/connection_adapters/postgresql/oid/rails_5_1_point.rb +50 -0
  103. data/lib/active_record/connection_adapters/postgresql/oid/range.rb +31 -17
  104. data/lib/active_record/connection_adapters/postgresql/oid/specialized_string.rb +0 -4
  105. data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +2 -2
  106. data/lib/active_record/connection_adapters/postgresql/oid/vector.rb +1 -1
  107. data/lib/active_record/connection_adapters/postgresql/oid/xml.rb +1 -1
  108. data/lib/active_record/connection_adapters/postgresql/quoting.rb +56 -19
  109. data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +29 -10
  110. data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +107 -79
  111. data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +47 -0
  112. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +250 -154
  113. data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +35 -0
  114. data/lib/active_record/connection_adapters/postgresql/utils.rb +2 -2
  115. data/lib/active_record/connection_adapters/postgresql_adapter.rb +264 -170
  116. data/lib/active_record/connection_adapters/schema_cache.rb +36 -23
  117. data/lib/active_record/connection_adapters/sql_type_metadata.rb +32 -0
  118. data/lib/active_record/connection_adapters/sqlite3/explain_pretty_printer.rb +19 -0
  119. data/lib/active_record/connection_adapters/sqlite3/quoting.rb +48 -0
  120. data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +22 -0
  121. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +151 -194
  122. data/lib/active_record/connection_adapters/statement_pool.rb +31 -12
  123. data/lib/active_record/connection_handling.rb +37 -14
  124. data/lib/active_record/core.rb +92 -108
  125. data/lib/active_record/counter_cache.rb +13 -24
  126. data/lib/active_record/dynamic_matchers.rb +1 -20
  127. data/lib/active_record/enum.rb +116 -76
  128. data/lib/active_record/errors.rb +87 -48
  129. data/lib/active_record/explain.rb +20 -9
  130. data/lib/active_record/explain_registry.rb +1 -1
  131. data/lib/active_record/explain_subscriber.rb +1 -1
  132. data/lib/active_record/fixture_set/file.rb +26 -5
  133. data/lib/active_record/fixtures.rb +77 -41
  134. data/lib/active_record/gem_version.rb +4 -4
  135. data/lib/active_record/inheritance.rb +32 -40
  136. data/lib/active_record/integration.rb +17 -14
  137. data/lib/active_record/internal_metadata.rb +56 -0
  138. data/lib/active_record/legacy_yaml_adapter.rb +18 -2
  139. data/lib/active_record/locale/en.yml +3 -2
  140. data/lib/active_record/locking/optimistic.rb +15 -15
  141. data/lib/active_record/locking/pessimistic.rb +1 -1
  142. data/lib/active_record/log_subscriber.rb +48 -24
  143. data/lib/active_record/migration.rb +362 -111
  144. data/lib/active_record/migration/command_recorder.rb +59 -18
  145. data/lib/active_record/migration/compatibility.rb +126 -0
  146. data/lib/active_record/model_schema.rb +270 -73
  147. data/lib/active_record/nested_attributes.rb +58 -29
  148. data/lib/active_record/no_touching.rb +4 -0
  149. data/lib/active_record/null_relation.rb +16 -8
  150. data/lib/active_record/persistence.rb +152 -90
  151. data/lib/active_record/query_cache.rb +18 -23
  152. data/lib/active_record/querying.rb +12 -11
  153. data/lib/active_record/railtie.rb +23 -16
  154. data/lib/active_record/railties/controller_runtime.rb +1 -1
  155. data/lib/active_record/railties/databases.rake +52 -41
  156. data/lib/active_record/readonly_attributes.rb +1 -1
  157. data/lib/active_record/reflection.rb +302 -115
  158. data/lib/active_record/relation.rb +187 -120
  159. data/lib/active_record/relation/batches.rb +141 -36
  160. data/lib/active_record/relation/batches/batch_enumerator.rb +67 -0
  161. data/lib/active_record/relation/calculations.rb +92 -117
  162. data/lib/active_record/relation/delegation.rb +8 -20
  163. data/lib/active_record/relation/finder_methods.rb +173 -89
  164. data/lib/active_record/relation/from_clause.rb +32 -0
  165. data/lib/active_record/relation/merger.rb +16 -42
  166. data/lib/active_record/relation/predicate_builder.rb +120 -107
  167. data/lib/active_record/relation/predicate_builder/array_handler.rb +11 -16
  168. data/lib/active_record/relation/predicate_builder/association_query_handler.rb +88 -0
  169. data/lib/active_record/relation/predicate_builder/base_handler.rb +17 -0
  170. data/lib/active_record/relation/predicate_builder/basic_object_handler.rb +17 -0
  171. data/lib/active_record/relation/predicate_builder/class_handler.rb +27 -0
  172. data/lib/active_record/relation/predicate_builder/polymorphic_array_handler.rb +57 -0
  173. data/lib/active_record/relation/predicate_builder/range_handler.rb +33 -0
  174. data/lib/active_record/relation/predicate_builder/relation_handler.rb +1 -1
  175. data/lib/active_record/relation/query_attribute.rb +19 -0
  176. data/lib/active_record/relation/query_methods.rb +308 -244
  177. data/lib/active_record/relation/record_fetch_warning.rb +49 -0
  178. data/lib/active_record/relation/spawn_methods.rb +4 -7
  179. data/lib/active_record/relation/where_clause.rb +174 -0
  180. data/lib/active_record/relation/where_clause_factory.rb +38 -0
  181. data/lib/active_record/result.rb +11 -4
  182. data/lib/active_record/runtime_registry.rb +1 -1
  183. data/lib/active_record/sanitization.rb +105 -66
  184. data/lib/active_record/schema.rb +26 -22
  185. data/lib/active_record/schema_dumper.rb +54 -37
  186. data/lib/active_record/schema_migration.rb +11 -14
  187. data/lib/active_record/scoping.rb +34 -16
  188. data/lib/active_record/scoping/default.rb +28 -10
  189. data/lib/active_record/scoping/named.rb +59 -26
  190. data/lib/active_record/secure_token.rb +38 -0
  191. data/lib/active_record/serialization.rb +3 -5
  192. data/lib/active_record/statement_cache.rb +17 -15
  193. data/lib/active_record/store.rb +8 -3
  194. data/lib/active_record/suppressor.rb +58 -0
  195. data/lib/active_record/table_metadata.rb +69 -0
  196. data/lib/active_record/tasks/database_tasks.rb +66 -49
  197. data/lib/active_record/tasks/mysql_database_tasks.rb +6 -14
  198. data/lib/active_record/tasks/postgresql_database_tasks.rb +12 -3
  199. data/lib/active_record/tasks/sqlite_database_tasks.rb +5 -1
  200. data/lib/active_record/timestamp.rb +20 -9
  201. data/lib/active_record/touch_later.rb +63 -0
  202. data/lib/active_record/transactions.rb +139 -57
  203. data/lib/active_record/type.rb +66 -17
  204. data/lib/active_record/type/adapter_specific_registry.rb +130 -0
  205. data/lib/active_record/type/date.rb +2 -45
  206. data/lib/active_record/type/date_time.rb +2 -49
  207. data/lib/active_record/type/internal/abstract_json.rb +33 -0
  208. data/lib/active_record/type/internal/timezone.rb +15 -0
  209. data/lib/active_record/type/serialized.rb +15 -14
  210. data/lib/active_record/type/time.rb +10 -16
  211. data/lib/active_record/type/type_map.rb +4 -4
  212. data/lib/active_record/type_caster.rb +7 -0
  213. data/lib/active_record/type_caster/connection.rb +29 -0
  214. data/lib/active_record/type_caster/map.rb +19 -0
  215. data/lib/active_record/validations.rb +33 -32
  216. data/lib/active_record/validations/absence.rb +23 -0
  217. data/lib/active_record/validations/associated.rb +10 -3
  218. data/lib/active_record/validations/length.rb +24 -0
  219. data/lib/active_record/validations/presence.rb +11 -12
  220. data/lib/active_record/validations/uniqueness.rb +33 -33
  221. data/lib/rails/generators/active_record/migration.rb +15 -0
  222. data/lib/rails/generators/active_record/migration/migration_generator.rb +8 -5
  223. data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb +8 -3
  224. data/lib/rails/generators/active_record/migration/templates/migration.rb +8 -1
  225. data/lib/rails/generators/active_record/model/model_generator.rb +33 -16
  226. data/lib/rails/generators/active_record/model/templates/application_record.rb +5 -0
  227. data/lib/rails/generators/active_record/model/templates/model.rb +3 -0
  228. metadata +58 -34
  229. data/lib/active_record/connection_adapters/mysql_adapter.rb +0 -498
  230. data/lib/active_record/connection_adapters/postgresql/array_parser.rb +0 -93
  231. data/lib/active_record/connection_adapters/postgresql/oid/date.rb +0 -11
  232. data/lib/active_record/connection_adapters/postgresql/oid/float.rb +0 -21
  233. data/lib/active_record/connection_adapters/postgresql/oid/infinity.rb +0 -13
  234. data/lib/active_record/connection_adapters/postgresql/oid/integer.rb +0 -11
  235. data/lib/active_record/connection_adapters/postgresql/oid/time.rb +0 -11
  236. data/lib/active_record/serializers/xml_serializer.rb +0 -193
  237. data/lib/active_record/type/big_integer.rb +0 -13
  238. data/lib/active_record/type/binary.rb +0 -50
  239. data/lib/active_record/type/boolean.rb +0 -31
  240. data/lib/active_record/type/decimal.rb +0 -64
  241. data/lib/active_record/type/decimal_without_scale.rb +0 -11
  242. data/lib/active_record/type/decorator.rb +0 -14
  243. data/lib/active_record/type/float.rb +0 -19
  244. data/lib/active_record/type/integer.rb +0 -59
  245. data/lib/active_record/type/mutable.rb +0 -16
  246. data/lib/active_record/type/numeric.rb +0 -36
  247. data/lib/active_record/type/string.rb +0 -40
  248. data/lib/active_record/type/text.rb +0 -11
  249. data/lib/active_record/type/time_value.rb +0 -38
  250. data/lib/active_record/type/unsigned_integer.rb +0 -15
  251. data/lib/active_record/type/value.rb +0 -110
@@ -11,7 +11,7 @@ module ActiveRecord
11
11
  # Attributes listed as readonly will be used to create a new record but update operations will
12
12
  # ignore these fields.
13
13
  def attr_readonly(*attributes)
14
- self._attr_readonly = Set.new(attributes.map { |a| a.to_s }) + (self._attr_readonly || [])
14
+ self._attr_readonly = Set.new(attributes.map(&:to_s)) + (self._attr_readonly || [])
15
15
  end
16
16
 
17
17
  # Returns an array of all the attributes that have been specified as readonly.
@@ -40,9 +40,9 @@ module ActiveRecord
40
40
  ar.aggregate_reflections = ar.aggregate_reflections.merge(name.to_s => reflection)
41
41
  end
42
42
 
43
- # \Reflection enables interrogating of Active Record classes and objects
44
- # about their associations and aggregations. This information can,
45
- # for example, be used in a form builder that takes an Active Record object
43
+ # \Reflection enables the ability to examine the associations and aggregations of
44
+ # Active Record classes and objects. This information, for example,
45
+ # can be used in a form builder that takes an Active Record object
46
46
  # and creates input fields for all of the attributes depending on their type
47
47
  # and displays the associations to other objects.
48
48
  #
@@ -62,20 +62,20 @@ module ActiveRecord
62
62
  aggregate_reflections[aggregation.to_s]
63
63
  end
64
64
 
65
- # Returns a Hash of name of the reflection as the key and a AssociationReflection as the value.
65
+ # Returns a Hash of name of the reflection as the key and an AssociationReflection as the value.
66
66
  #
67
67
  # Account.reflections # => {"balance" => AggregateReflection}
68
68
  #
69
- # @api public
70
69
  def reflections
71
70
  @__reflections ||= begin
72
71
  ref = {}
73
72
 
74
73
  _reflections.each do |name, reflection|
75
- parent_name, parent_reflection = reflection.parent_reflection
74
+ parent_reflection = reflection.parent_reflection
76
75
 
77
- if parent_name
78
- ref[parent_name] = parent_reflection
76
+ if parent_reflection
77
+ parent_name = parent_reflection.name
78
+ ref[parent_name.to_s] = parent_reflection
79
79
  else
80
80
  ref[name] = reflection
81
81
  end
@@ -95,10 +95,10 @@ module ActiveRecord
95
95
  # Account.reflect_on_all_associations # returns an array of all associations
96
96
  # Account.reflect_on_all_associations(:has_many) # returns an array of all has_many associations
97
97
  #
98
- # @api public
99
98
  def reflect_on_all_associations(macro = nil)
100
99
  association_reflections = reflections.values
101
- macro ? association_reflections.select { |reflection| reflection.macro == macro } : association_reflections
100
+ association_reflections.select! { |reflection| reflection.macro == macro } if macro
101
+ association_reflections
102
102
  end
103
103
 
104
104
  # Returns the AssociationReflection object for the +association+ (use the symbol).
@@ -106,31 +106,42 @@ module ActiveRecord
106
106
  # Account.reflect_on_association(:owner) # returns the owner AssociationReflection
107
107
  # Invoice.reflect_on_association(:line_items).macro # returns :has_many
108
108
  #
109
- # @api public
110
109
  def reflect_on_association(association)
111
110
  reflections[association.to_s]
112
111
  end
113
112
 
114
- # @api private
115
113
  def _reflect_on_association(association) #:nodoc:
116
114
  _reflections[association.to_s]
117
115
  end
118
116
 
119
117
  # Returns an array of AssociationReflection objects for all associations which have <tt>:autosave</tt> enabled.
120
- #
121
- # @api public
122
118
  def reflect_on_all_autosave_associations
123
119
  reflections.values.select { |reflection| reflection.options[:autosave] }
124
120
  end
125
121
 
126
- def clear_reflections_cache #:nodoc:
122
+ def clear_reflections_cache # :nodoc:
127
123
  @__reflections = nil
128
124
  end
129
125
  end
130
126
 
131
- # Holds all the methods that are shared between MacroReflection, AssociationReflection
132
- # and ThroughReflection
127
+ # Holds all the methods that are shared between MacroReflection and ThroughReflection.
128
+ #
129
+ # AbstractReflection
130
+ # MacroReflection
131
+ # AggregateReflection
132
+ # AssociationReflection
133
+ # HasManyReflection
134
+ # HasOneReflection
135
+ # BelongsToReflection
136
+ # HasAndBelongsToManyReflection
137
+ # ThroughReflection
138
+ # PolymorphicReflection
139
+ # RuntimeReflection
133
140
  class AbstractReflection # :nodoc:
141
+ def through_reflection?
142
+ false
143
+ end
144
+
134
145
  def table_name
135
146
  klass.table_name
136
147
  end
@@ -159,17 +170,24 @@ module ActiveRecord
159
170
 
160
171
  JoinKeys = Struct.new(:key, :foreign_key) # :nodoc:
161
172
 
162
- def join_keys(assoc_klass)
173
+ def join_keys(association_klass)
163
174
  JoinKeys.new(foreign_key, active_record_primary_key)
164
175
  end
165
176
 
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
177
+ def constraints
178
+ scope_chain.flatten
179
+ end
171
180
 
172
- macro
181
+ def counter_cache_column
182
+ if belongs_to?
183
+ if options[:counter_cache] == true
184
+ "#{active_record.name.demodulize.underscore.pluralize}_count"
185
+ elsif options[:counter_cache]
186
+ options[:counter_cache].to_s
187
+ end
188
+ else
189
+ options[:counter_cache] ? options[:counter_cache].to_s : "#{name}_count"
190
+ end
173
191
  end
174
192
 
175
193
  def inverse_of
@@ -185,17 +203,54 @@ module ActiveRecord
185
203
  end
186
204
  end
187
205
  end
206
+
207
+ # This shit is nasty. We need to avoid the following situation:
208
+ #
209
+ # * An associated record is deleted via record.destroy
210
+ # * Hence the callbacks run, and they find a belongs_to on the record with a
211
+ # :counter_cache options which points back at our owner. So they update the
212
+ # counter cache.
213
+ # * In which case, we must make sure to *not* update the counter cache, or else
214
+ # it will be decremented twice.
215
+ #
216
+ # Hence this method.
217
+ def inverse_which_updates_counter_cache
218
+ return @inverse_which_updates_counter_cache if defined?(@inverse_which_updates_counter_cache)
219
+ @inverse_which_updates_counter_cache = klass.reflect_on_all_associations(:belongs_to).find do |inverse|
220
+ inverse.counter_cache_column == counter_cache_column
221
+ end
222
+ end
223
+ alias inverse_updates_counter_cache? inverse_which_updates_counter_cache
224
+
225
+ def inverse_updates_counter_in_memory?
226
+ inverse_of && inverse_which_updates_counter_cache == inverse_of
227
+ end
228
+
229
+ # Returns whether a counter cache should be used for this association.
230
+ #
231
+ # The counter_cache option must be given on either the owner or inverse
232
+ # association, and the column must be present on the owner.
233
+ def has_cached_counter?
234
+ options[:counter_cache] ||
235
+ inverse_which_updates_counter_cache && inverse_which_updates_counter_cache.options[:counter_cache] &&
236
+ !!active_record.columns_hash[counter_cache_column]
237
+ end
238
+
239
+ def counter_must_be_updated_by_has_many?
240
+ !inverse_updates_counter_in_memory? && has_cached_counter?
241
+ end
242
+
243
+ def alias_candidate(name)
244
+ "#{plural_name}_#{name}"
245
+ end
246
+
247
+ def chain
248
+ collect_join_chain
249
+ end
188
250
  end
251
+
189
252
  # Base class for AggregateReflection and AssociationReflection. Objects of
190
253
  # AggregateReflection and AssociationReflection are returned by the Reflection::ClassMethods.
191
- #
192
- # MacroReflection
193
- # AssociationReflection
194
- # AggregateReflection
195
- # HasManyReflection
196
- # HasOneReflection
197
- # BelongsToReflection
198
- # ThroughReflection
199
254
  class MacroReflection < AbstractReflection
200
255
  # Returns the name of the macro.
201
256
  #
@@ -228,7 +283,7 @@ module ActiveRecord
228
283
  def autosave=(autosave)
229
284
  @automatic_inverse_of = false
230
285
  @options[:autosave] = autosave
231
- _, parent_reflection = self.parent_reflection
286
+ parent_reflection = self.parent_reflection
232
287
  if parent_reflection
233
288
  parent_reflection.autosave = autosave
234
289
  end
@@ -256,6 +311,10 @@ module ActiveRecord
256
311
  active_record == other_aggregation.active_record
257
312
  end
258
313
 
314
+ def scope_for(klass)
315
+ scope ? klass.unscoped.instance_exec(nil, &scope) : klass.unscoped
316
+ end
317
+
259
318
  private
260
319
  def derive_class_name
261
320
  name.to_s.camelize
@@ -296,7 +355,7 @@ module ActiveRecord
296
355
  end
297
356
 
298
357
  attr_reader :type, :foreign_type
299
- attr_accessor :parent_reflection # [:name, Reflection]
358
+ attr_accessor :parent_reflection # Reflection
300
359
 
301
360
  def initialize(name, scope, options, active_record)
302
361
  super
@@ -339,16 +398,12 @@ module ActiveRecord
339
398
  options[:primary_key] || primary_key(klass || self.klass)
340
399
  end
341
400
 
342
- def active_record_primary_key
343
- @active_record_primary_key ||= options[:primary_key] || primary_key(active_record)
401
+ def association_primary_key_type
402
+ klass.type_for_attribute(association_primary_key.to_s)
344
403
  end
345
404
 
346
- def counter_cache_column
347
- if options[:counter_cache] == true
348
- "#{active_record.name.demodulize.underscore.pluralize}_count"
349
- elsif options[:counter_cache]
350
- options[:counter_cache].to_s
351
- end
405
+ def active_record_primary_key
406
+ @active_record_primary_key ||= options[:primary_key] || primary_key(active_record)
352
407
  end
353
408
 
354
409
  def check_validity!
@@ -359,13 +414,10 @@ module ActiveRecord
359
414
  return unless scope
360
415
 
361
416
  if scope.arity > 0
362
- ActiveSupport::Deprecation.warn(<<-MSG.squish)
417
+ raise ArgumentError, <<-MSG.squish
363
418
  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.
419
+ block takes an argument). Preloading instance dependent scopes is
420
+ not supported.
369
421
  MSG
370
422
  end
371
423
  end
@@ -385,10 +437,16 @@ module ActiveRecord
385
437
 
386
438
  # A chain of reflections from this one back to the owner. For more see the explanation in
387
439
  # ThroughReflection.
388
- def chain
440
+ def collect_join_chain
389
441
  [self]
390
442
  end
391
443
 
444
+ # This is for clearing cache on the reflection. Useful for tests that need to compare
445
+ # SQL queries on associations.
446
+ def clear_association_scope_cache # :nodoc:
447
+ @association_scope_cache.clear
448
+ end
449
+
392
450
  def nested?
393
451
  false
394
452
  end
@@ -399,6 +457,10 @@ module ActiveRecord
399
457
  scope ? [[scope]] : [[]]
400
458
  end
401
459
 
460
+ def has_scope?
461
+ scope
462
+ end
463
+
402
464
  def has_inverse?
403
465
  inverse_name
404
466
  end
@@ -444,28 +506,7 @@ module ActiveRecord
444
506
  # Returns +true+ if +self+ is a +has_one+ reflection.
445
507
  def has_one?; false; end
446
508
 
447
- def association_class
448
- case macro
449
- when :belongs_to
450
- if polymorphic?
451
- Associations::BelongsToPolymorphicAssociation
452
- else
453
- Associations::BelongsToAssociation
454
- end
455
- when :has_many
456
- if options[:through]
457
- Associations::HasManyThroughAssociation
458
- else
459
- Associations::HasManyAssociation
460
- end
461
- when :has_one
462
- if options[:through]
463
- Associations::HasOneThroughAssociation
464
- else
465
- Associations::HasOneAssociation
466
- end
467
- end
468
- end
509
+ def association_class; raise NotImplementedError; end
469
510
 
470
511
  def polymorphic?
471
512
  options[:polymorphic]
@@ -474,6 +515,22 @@ module ActiveRecord
474
515
  VALID_AUTOMATIC_INVERSE_MACROS = [:has_many, :has_one, :belongs_to]
475
516
  INVALID_AUTOMATIC_INVERSE_OPTIONS = [:conditions, :through, :polymorphic, :foreign_key]
476
517
 
518
+ def add_as_source(seed)
519
+ seed
520
+ end
521
+
522
+ def add_as_polymorphic_through(reflection, seed)
523
+ seed + [PolymorphicReflection.new(self, reflection)]
524
+ end
525
+
526
+ def add_as_through(seed)
527
+ seed + [self]
528
+ end
529
+
530
+ def extensions
531
+ Array(options[:extend])
532
+ end
533
+
477
534
  protected
478
535
 
479
536
  def actual_source_reflection # FIXME: this is a horrible name
@@ -483,14 +540,7 @@ module ActiveRecord
483
540
  private
484
541
 
485
542
  def calculate_constructable(macro, options)
486
- case macro
487
- when :belongs_to
488
- !polymorphic?
489
- when :has_one
490
- !options[:through]
491
- else
492
- true
493
- end
543
+ true
494
544
  end
495
545
 
496
546
  # Attempts to find the inverse association name automatically.
@@ -506,7 +556,7 @@ module ActiveRecord
506
556
  end
507
557
  end
508
558
 
509
- # returns either nil or the inverse association name that it finds.
559
+ # returns either false or the inverse association name that it finds.
510
560
  def automatic_inverse_of
511
561
  if can_find_inverse_of_automatically?(self)
512
562
  inverse_name = ActiveSupport::Inflector.underscore(options[:as] || active_record.name.demodulize).to_sym
@@ -583,42 +633,70 @@ module ActiveRecord
583
633
  end
584
634
 
585
635
  class HasManyReflection < AssociationReflection # :nodoc:
586
- def initialize(name, scope, options, active_record)
587
- super(name, scope, options, active_record)
588
- end
589
-
590
636
  def macro; :has_many; end
591
637
 
592
638
  def collection?; true; end
593
- end
594
639
 
595
- class HasOneReflection < AssociationReflection # :nodoc:
596
- def initialize(name, scope, options, active_record)
597
- super(name, scope, options, active_record)
640
+ def association_class
641
+ if options[:through]
642
+ Associations::HasManyThroughAssociation
643
+ else
644
+ Associations::HasManyAssociation
645
+ end
598
646
  end
599
647
 
648
+ def association_primary_key(klass = nil)
649
+ primary_key(klass || self.klass)
650
+ end
651
+ end
652
+
653
+ class HasOneReflection < AssociationReflection # :nodoc:
600
654
  def macro; :has_one; end
601
655
 
602
656
  def has_one?; true; end
603
- end
604
657
 
605
- class BelongsToReflection < AssociationReflection # :nodoc:
606
- def initialize(name, scope, options, active_record)
607
- super(name, scope, options, active_record)
658
+ def association_class
659
+ if options[:through]
660
+ Associations::HasOneThroughAssociation
661
+ else
662
+ Associations::HasOneAssociation
663
+ end
608
664
  end
609
665
 
666
+ private
667
+
668
+ def calculate_constructable(macro, options)
669
+ !options[:through]
670
+ end
671
+ end
672
+
673
+ class BelongsToReflection < AssociationReflection # :nodoc:
610
674
  def macro; :belongs_to; end
611
675
 
612
676
  def belongs_to?; true; end
613
677
 
614
- def join_keys(assoc_klass)
615
- key = polymorphic? ? association_primary_key(assoc_klass) : association_primary_key
678
+ def association_class
679
+ if polymorphic?
680
+ Associations::BelongsToPolymorphicAssociation
681
+ else
682
+ Associations::BelongsToAssociation
683
+ end
684
+ end
685
+
686
+ def join_keys(association_klass)
687
+ key = polymorphic? ? association_primary_key(association_klass) : association_primary_key
616
688
  JoinKeys.new(key, foreign_key)
617
689
  end
618
690
 
619
691
  def join_id_for(owner) # :nodoc:
620
692
  owner[foreign_key]
621
693
  end
694
+
695
+ private
696
+
697
+ def calculate_constructable(macro, options)
698
+ !polymorphic?
699
+ end
622
700
  end
623
701
 
624
702
  class HasAndBelongsToManyReflection < AssociationReflection # :nodoc:
@@ -646,6 +724,10 @@ module ActiveRecord
646
724
  @source_reflection_name = delegate_reflection.options[:source]
647
725
  end
648
726
 
727
+ def through_reflection?
728
+ true
729
+ end
730
+
649
731
  def klass
650
732
  @klass ||= delegate_reflection.compute_class(class_name)
651
733
  end
@@ -704,14 +786,16 @@ module ActiveRecord
704
786
  # # => [<ActiveRecord::Reflection::ThroughReflection: @delegate_reflection=#<ActiveRecord::Reflection::HasManyReflection: @name=:tags...>,
705
787
  # <ActiveRecord::Reflection::HasManyReflection: @name=:taggings, @options={}, @active_record=Post>]
706
788
  #
707
- def chain
708
- @chain ||= begin
709
- a = source_reflection.chain
710
- b = through_reflection.chain
711
- chain = a + b
712
- chain[0] = self # Use self so we don't lose the information from :source_type
713
- chain
714
- end
789
+ def collect_join_chain
790
+ collect_join_reflections [self]
791
+ end
792
+
793
+ # This is for clearing cache on the reflection. Useful for tests that need to compare
794
+ # SQL queries on associations.
795
+ def clear_association_scope_cache # :nodoc:
796
+ delegate_reflection.clear_association_scope_cache
797
+ source_reflection.clear_association_scope_cache
798
+ through_reflection.clear_association_scope_cache
715
799
  end
716
800
 
717
801
  # Consider the following example:
@@ -755,23 +839,19 @@ module ActiveRecord
755
839
  end
756
840
  end
757
841
 
758
- def join_keys(assoc_klass)
759
- source_reflection.join_keys(assoc_klass)
842
+ def has_scope?
843
+ scope || options[:source_type] ||
844
+ source_reflection.has_scope? ||
845
+ through_reflection.has_scope?
760
846
  end
761
847
 
762
- # The macro used by the source association
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
-
769
- source_reflection.source_macro
848
+ def join_keys(association_klass)
849
+ source_reflection.join_keys(association_klass)
770
850
  end
771
851
 
772
852
  # A through association is nested if there would be more than one join table
773
853
  def nested?
774
- chain.length > 2
854
+ source_reflection.through_reflection? || through_reflection.through_reflection?
775
855
  end
776
856
 
777
857
  # We want to use the klass from this reflection, rather than just delegate straight to
@@ -783,6 +863,10 @@ module ActiveRecord
783
863
  actual_source_reflection.options[:primary_key] || primary_key(klass || self.klass)
784
864
  end
785
865
 
866
+ def association_primary_key_type
867
+ klass.type_for_attribute(association_primary_key.to_s)
868
+ end
869
+
786
870
  # Gets an array of possible <tt>:through</tt> source reflection names in both singular and plural form.
787
871
  #
788
872
  # class Post < ActiveRecord::Base
@@ -801,7 +885,7 @@ module ActiveRecord
801
885
  def source_reflection_name # :nodoc:
802
886
  return @source_reflection_name if @source_reflection_name
803
887
 
804
- names = [name.to_s.singularize, name].collect { |n| n.to_sym }.uniq
888
+ names = [name.to_s.singularize, name].collect(&:to_sym).uniq
805
889
  names = names.find_all { |n|
806
890
  through_reflection.klass._reflect_on_association(n)
807
891
  }
@@ -810,7 +894,7 @@ module ActiveRecord
810
894
  example_options = options.dup
811
895
  example_options[:source] = source_reflection_names.first
812
896
  ActiveSupport::Deprecation.warn \
813
- "Ambiguous source reflection for through association. Please " \
897
+ "Ambiguous source reflection for through association. Please " \
814
898
  "specify a :source directive on your declaration like:\n" \
815
899
  "\n" \
816
900
  " class #{active_record.name} < ActiveRecord::Base\n" \
@@ -865,6 +949,33 @@ module ActiveRecord
865
949
  check_validity_of_inverse!
866
950
  end
867
951
 
952
+ def constraints
953
+ scope_chain = source_reflection.constraints
954
+ scope_chain << scope if scope
955
+ scope_chain
956
+ end
957
+
958
+ def add_as_source(seed)
959
+ collect_join_reflections seed
960
+ end
961
+
962
+ def add_as_polymorphic_through(reflection, seed)
963
+ collect_join_reflections(seed + [PolymorphicReflection.new(self, reflection)])
964
+ end
965
+
966
+ def add_as_through(seed)
967
+ collect_join_reflections(seed + [self])
968
+ end
969
+
970
+ def collect_join_reflections(seed)
971
+ a = source_reflection.add_as_source seed
972
+ if options[:source_type]
973
+ through_reflection.add_as_polymorphic_through self, a
974
+ else
975
+ through_reflection.add_as_through a
976
+ end
977
+ end
978
+
868
979
  protected
869
980
 
870
981
  def actual_source_reflection # FIXME: this is a horrible name
@@ -889,5 +1000,81 @@ module ActiveRecord
889
1000
  delegate(*delegate_methods, to: :delegate_reflection)
890
1001
 
891
1002
  end
1003
+
1004
+ class PolymorphicReflection < ThroughReflection # :nodoc:
1005
+ def initialize(reflection, previous_reflection)
1006
+ @reflection = reflection
1007
+ @previous_reflection = previous_reflection
1008
+ end
1009
+
1010
+ def klass
1011
+ @reflection.klass
1012
+ end
1013
+
1014
+ def scope
1015
+ @reflection.scope
1016
+ end
1017
+
1018
+ def table_name
1019
+ @reflection.table_name
1020
+ end
1021
+
1022
+ def plural_name
1023
+ @reflection.plural_name
1024
+ end
1025
+
1026
+ def join_keys(association_klass)
1027
+ @reflection.join_keys(association_klass)
1028
+ end
1029
+
1030
+ def type
1031
+ @reflection.type
1032
+ end
1033
+
1034
+ def constraints
1035
+ @reflection.constraints + [source_type_info]
1036
+ end
1037
+
1038
+ def source_type_info
1039
+ type = @previous_reflection.foreign_type
1040
+ source_type = @previous_reflection.options[:source_type]
1041
+ lambda { |object| where(type => source_type) }
1042
+ end
1043
+ end
1044
+
1045
+ class RuntimeReflection < PolymorphicReflection # :nodoc:
1046
+ attr_accessor :next
1047
+
1048
+ def initialize(reflection, association)
1049
+ @reflection = reflection
1050
+ @association = association
1051
+ end
1052
+
1053
+ def klass
1054
+ @association.klass
1055
+ end
1056
+
1057
+ def table_name
1058
+ klass.table_name
1059
+ end
1060
+
1061
+ def constraints
1062
+ @reflection.constraints
1063
+ end
1064
+
1065
+ def source_type_info
1066
+ @reflection.source_type_info
1067
+ end
1068
+
1069
+ def alias_candidate(name)
1070
+ "#{plural_name}_#{name}_join"
1071
+ end
1072
+
1073
+ def alias_name
1074
+ Arel::Table.new(table_name)
1075
+ end
1076
+
1077
+ def all_includes; yield; end
1078
+ end
892
1079
  end
893
1080
  end