activerecord 5.1.7 → 5.2.0

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


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

Files changed (261) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +372 -765
  3. data/MIT-LICENSE +1 -1
  4. data/README.rdoc +5 -5
  5. data/examples/performance.rb +2 -0
  6. data/examples/simple.rb +2 -0
  7. data/lib/active_record/aggregations.rb +6 -5
  8. data/lib/active_record/association_relation.rb +4 -2
  9. data/lib/active_record/associations/alias_tracker.rb +19 -27
  10. data/lib/active_record/associations/association.rb +16 -27
  11. data/lib/active_record/associations/association_scope.rb +38 -50
  12. data/lib/active_record/associations/belongs_to_association.rb +20 -10
  13. data/lib/active_record/associations/belongs_to_polymorphic_association.rb +4 -7
  14. data/lib/active_record/associations/builder/association.rb +4 -7
  15. data/lib/active_record/associations/builder/belongs_to.rb +4 -5
  16. data/lib/active_record/associations/builder/collection_association.rb +1 -1
  17. data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +3 -1
  18. data/lib/active_record/associations/builder/has_many.rb +2 -0
  19. data/lib/active_record/associations/builder/has_one.rb +2 -0
  20. data/lib/active_record/associations/builder/singular_association.rb +2 -0
  21. data/lib/active_record/associations/collection_association.rb +43 -35
  22. data/lib/active_record/associations/collection_proxy.rb +12 -15
  23. data/lib/active_record/associations/foreign_association.rb +2 -0
  24. data/lib/active_record/associations/has_many_association.rb +3 -1
  25. data/lib/active_record/associations/has_many_through_association.rb +7 -18
  26. data/lib/active_record/associations/has_one_association.rb +4 -1
  27. data/lib/active_record/associations/has_one_through_association.rb +8 -7
  28. data/lib/active_record/associations/join_dependency/join_association.rb +17 -56
  29. data/lib/active_record/associations/join_dependency/join_base.rb +9 -8
  30. data/lib/active_record/associations/join_dependency/join_part.rb +2 -9
  31. data/lib/active_record/associations/join_dependency.rb +23 -43
  32. data/lib/active_record/associations/preloader/association.rb +45 -61
  33. data/lib/active_record/associations/preloader/through_association.rb +71 -79
  34. data/lib/active_record/associations/preloader.rb +17 -37
  35. data/lib/active_record/associations/singular_association.rb +14 -10
  36. data/lib/active_record/associations/through_association.rb +25 -10
  37. data/lib/active_record/associations.rb +31 -54
  38. data/lib/active_record/attribute_assignment.rb +2 -5
  39. data/lib/active_record/attribute_decorators.rb +3 -2
  40. data/lib/active_record/attribute_methods/before_type_cast.rb +2 -0
  41. data/lib/active_record/attribute_methods/dirty.rb +25 -214
  42. data/lib/active_record/attribute_methods/primary_key.rb +7 -6
  43. data/lib/active_record/attribute_methods/query.rb +2 -0
  44. data/lib/active_record/attribute_methods/read.rb +8 -2
  45. data/lib/active_record/attribute_methods/serialization.rb +23 -0
  46. data/lib/active_record/attribute_methods/time_zone_conversion.rb +6 -8
  47. data/lib/active_record/attribute_methods/write.rb +21 -9
  48. data/lib/active_record/attribute_methods.rb +65 -24
  49. data/lib/active_record/attributes.rb +6 -5
  50. data/lib/active_record/autosave_association.rb +8 -11
  51. data/lib/active_record/base.rb +2 -0
  52. data/lib/active_record/callbacks.rb +8 -10
  53. data/lib/active_record/coders/json.rb +2 -0
  54. data/lib/active_record/coders/yaml_column.rb +2 -0
  55. data/lib/active_record/collection_cache_key.rb +11 -7
  56. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +111 -38
  57. data/lib/active_record/connection_adapters/abstract/database_limits.rb +2 -0
  58. data/lib/active_record/connection_adapters/abstract/database_statements.rb +157 -29
  59. data/lib/active_record/connection_adapters/abstract/query_cache.rb +7 -2
  60. data/lib/active_record/connection_adapters/abstract/quoting.rb +13 -32
  61. data/lib/active_record/connection_adapters/abstract/savepoints.rb +2 -0
  62. data/lib/active_record/connection_adapters/abstract/schema_creation.rb +14 -5
  63. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +57 -2
  64. data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +31 -53
  65. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +158 -78
  66. data/lib/active_record/connection_adapters/abstract/transaction.rb +45 -9
  67. data/lib/active_record/connection_adapters/abstract_adapter.rb +81 -96
  68. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +111 -183
  69. data/lib/active_record/connection_adapters/column.rb +3 -1
  70. data/lib/active_record/connection_adapters/connection_specification.rb +17 -3
  71. data/lib/active_record/connection_adapters/determine_if_preparable_visitor.rb +2 -0
  72. data/lib/active_record/connection_adapters/mysql/column.rb +2 -0
  73. data/lib/active_record/connection_adapters/mysql/database_statements.rb +11 -2
  74. data/lib/active_record/connection_adapters/mysql/explain_pretty_printer.rb +2 -0
  75. data/lib/active_record/connection_adapters/mysql/quoting.rb +9 -10
  76. data/lib/active_record/connection_adapters/mysql/schema_creation.rb +5 -3
  77. data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +7 -10
  78. data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +30 -30
  79. data/lib/active_record/connection_adapters/mysql/schema_statements.rb +106 -1
  80. data/lib/active_record/connection_adapters/mysql/type_metadata.rb +2 -0
  81. data/lib/active_record/connection_adapters/mysql2_adapter.rb +8 -2
  82. data/lib/active_record/connection_adapters/postgresql/column.rb +2 -0
  83. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +6 -0
  84. data/lib/active_record/connection_adapters/postgresql/explain_pretty_printer.rb +2 -0
  85. data/lib/active_record/connection_adapters/postgresql/oid/array.rb +3 -11
  86. data/lib/active_record/connection_adapters/postgresql/oid/bit.rb +2 -0
  87. data/lib/active_record/connection_adapters/postgresql/oid/bit_varying.rb +2 -0
  88. data/lib/active_record/connection_adapters/postgresql/oid/bytea.rb +2 -0
  89. data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +2 -0
  90. data/lib/active_record/connection_adapters/postgresql/oid/date.rb +23 -0
  91. data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +2 -0
  92. data/lib/active_record/connection_adapters/postgresql/oid/decimal.rb +2 -0
  93. data/lib/active_record/connection_adapters/postgresql/oid/enum.rb +2 -0
  94. data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +2 -0
  95. data/lib/active_record/connection_adapters/postgresql/oid/inet.rb +2 -0
  96. data/lib/active_record/connection_adapters/postgresql/oid/jsonb.rb +3 -1
  97. data/lib/active_record/connection_adapters/postgresql/oid/legacy_point.rb +2 -0
  98. data/lib/active_record/connection_adapters/postgresql/oid/money.rb +3 -1
  99. data/lib/active_record/connection_adapters/postgresql/oid/oid.rb +2 -0
  100. data/lib/active_record/connection_adapters/postgresql/oid/point.rb +2 -0
  101. data/lib/active_record/connection_adapters/postgresql/oid/range.rb +4 -6
  102. data/lib/active_record/connection_adapters/postgresql/oid/specialized_string.rb +2 -0
  103. data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +4 -2
  104. data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +3 -1
  105. data/lib/active_record/connection_adapters/postgresql/oid/vector.rb +2 -0
  106. data/lib/active_record/connection_adapters/postgresql/oid/xml.rb +2 -0
  107. data/lib/active_record/connection_adapters/postgresql/oid.rb +3 -1
  108. data/lib/active_record/connection_adapters/postgresql/quoting.rb +18 -0
  109. data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +19 -25
  110. data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +14 -0
  111. data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +24 -11
  112. data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +20 -13
  113. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +246 -110
  114. data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +2 -0
  115. data/lib/active_record/connection_adapters/postgresql/utils.rb +2 -0
  116. data/lib/active_record/connection_adapters/postgresql_adapter.rb +58 -82
  117. data/lib/active_record/connection_adapters/schema_cache.rb +4 -2
  118. data/lib/active_record/connection_adapters/sql_type_metadata.rb +2 -0
  119. data/lib/active_record/connection_adapters/sqlite3/explain_pretty_printer.rb +2 -0
  120. data/lib/active_record/connection_adapters/sqlite3/quoting.rb +18 -1
  121. data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +2 -0
  122. data/lib/active_record/connection_adapters/sqlite3/schema_definitions.rb +6 -15
  123. data/lib/active_record/connection_adapters/sqlite3/schema_dumper.rb +3 -2
  124. data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +71 -1
  125. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +80 -90
  126. data/lib/active_record/connection_adapters/statement_pool.rb +2 -0
  127. data/lib/active_record/connection_handling.rb +4 -2
  128. data/lib/active_record/core.rb +39 -60
  129. data/lib/active_record/counter_cache.rb +15 -12
  130. data/lib/active_record/define_callbacks.rb +5 -3
  131. data/lib/active_record/dynamic_matchers.rb +9 -9
  132. data/lib/active_record/enum.rb +17 -13
  133. data/lib/active_record/errors.rb +54 -21
  134. data/lib/active_record/explain.rb +3 -1
  135. data/lib/active_record/explain_registry.rb +2 -0
  136. data/lib/active_record/explain_subscriber.rb +2 -0
  137. data/lib/active_record/fixture_set/file.rb +2 -0
  138. data/lib/active_record/fixtures.rb +67 -60
  139. data/lib/active_record/gem_version.rb +4 -2
  140. data/lib/active_record/inheritance.rb +49 -19
  141. data/lib/active_record/integration.rb +58 -19
  142. data/lib/active_record/internal_metadata.rb +2 -0
  143. data/lib/active_record/legacy_yaml_adapter.rb +3 -1
  144. data/lib/active_record/locking/optimistic.rb +14 -17
  145. data/lib/active_record/locking/pessimistic.rb +9 -6
  146. data/lib/active_record/log_subscriber.rb +43 -0
  147. data/lib/active_record/migration/command_recorder.rb +11 -9
  148. data/lib/active_record/migration/compatibility.rb +40 -2
  149. data/lib/active_record/migration/join_table.rb +2 -0
  150. data/lib/active_record/migration.rb +189 -139
  151. data/lib/active_record/model_schema.rb +16 -21
  152. data/lib/active_record/nested_attributes.rb +18 -6
  153. data/lib/active_record/no_touching.rb +3 -1
  154. data/lib/active_record/null_relation.rb +2 -0
  155. data/lib/active_record/persistence.rb +166 -16
  156. data/lib/active_record/query_cache.rb +11 -6
  157. data/lib/active_record/querying.rb +3 -1
  158. data/lib/active_record/railtie.rb +61 -3
  159. data/lib/active_record/railties/console_sandbox.rb +2 -0
  160. data/lib/active_record/railties/controller_runtime.rb +2 -0
  161. data/lib/active_record/railties/databases.rake +46 -36
  162. data/lib/active_record/readonly_attributes.rb +3 -2
  163. data/lib/active_record/reflection.rb +110 -192
  164. data/lib/active_record/relation/batches/batch_enumerator.rb +2 -0
  165. data/lib/active_record/relation/batches.rb +20 -5
  166. data/lib/active_record/relation/calculations.rb +30 -8
  167. data/lib/active_record/relation/delegation.rb +15 -27
  168. data/lib/active_record/relation/finder_methods.rb +75 -78
  169. data/lib/active_record/relation/from_clause.rb +2 -8
  170. data/lib/active_record/relation/merger.rb +51 -20
  171. data/lib/active_record/relation/predicate_builder/array_handler.rb +10 -7
  172. data/lib/active_record/relation/predicate_builder/association_query_value.rb +46 -0
  173. data/lib/active_record/relation/predicate_builder/base_handler.rb +2 -2
  174. data/lib/active_record/relation/predicate_builder/basic_object_handler.rb +12 -1
  175. data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +56 -0
  176. data/lib/active_record/relation/predicate_builder/range_handler.rb +26 -9
  177. data/lib/active_record/relation/predicate_builder/relation_handler.rb +6 -0
  178. data/lib/active_record/relation/predicate_builder.rb +53 -78
  179. data/lib/active_record/relation/query_attribute.rb +26 -2
  180. data/lib/active_record/relation/query_methods.rb +89 -88
  181. data/lib/active_record/relation/record_fetch_warning.rb +2 -0
  182. data/lib/active_record/relation/spawn_methods.rb +3 -1
  183. data/lib/active_record/relation/where_clause.rb +65 -68
  184. data/lib/active_record/relation/where_clause_factory.rb +5 -48
  185. data/lib/active_record/relation.rb +95 -208
  186. data/lib/active_record/result.rb +2 -0
  187. data/lib/active_record/runtime_registry.rb +2 -0
  188. data/lib/active_record/sanitization.rb +129 -121
  189. data/lib/active_record/schema.rb +4 -2
  190. data/lib/active_record/schema_dumper.rb +36 -26
  191. data/lib/active_record/schema_migration.rb +2 -0
  192. data/lib/active_record/scoping/default.rb +6 -7
  193. data/lib/active_record/scoping/named.rb +21 -7
  194. data/lib/active_record/scoping.rb +9 -8
  195. data/lib/active_record/secure_token.rb +2 -0
  196. data/lib/active_record/serialization.rb +2 -0
  197. data/lib/active_record/statement_cache.rb +22 -12
  198. data/lib/active_record/store.rb +3 -1
  199. data/lib/active_record/suppressor.rb +2 -0
  200. data/lib/active_record/table_metadata.rb +12 -3
  201. data/lib/active_record/tasks/database_tasks.rb +26 -15
  202. data/lib/active_record/tasks/mysql_database_tasks.rb +9 -48
  203. data/lib/active_record/tasks/postgresql_database_tasks.rb +10 -2
  204. data/lib/active_record/tasks/sqlite_database_tasks.rb +25 -3
  205. data/lib/active_record/timestamp.rb +5 -12
  206. data/lib/active_record/touch_later.rb +2 -0
  207. data/lib/active_record/transactions.rb +9 -7
  208. data/lib/active_record/translation.rb +2 -0
  209. data/lib/active_record/type/adapter_specific_registry.rb +2 -0
  210. data/lib/active_record/type/date.rb +2 -0
  211. data/lib/active_record/type/date_time.rb +2 -0
  212. data/lib/active_record/type/decimal_without_scale.rb +2 -0
  213. data/lib/active_record/type/hash_lookup_type_map.rb +2 -0
  214. data/lib/active_record/type/internal/timezone.rb +2 -0
  215. data/lib/active_record/type/json.rb +30 -0
  216. data/lib/active_record/type/serialized.rb +2 -4
  217. data/lib/active_record/type/text.rb +2 -0
  218. data/lib/active_record/type/time.rb +2 -0
  219. data/lib/active_record/type/type_map.rb +2 -0
  220. data/lib/active_record/type/unsigned_integer.rb +2 -0
  221. data/lib/active_record/type.rb +4 -1
  222. data/lib/active_record/type_caster/connection.rb +2 -0
  223. data/lib/active_record/type_caster/map.rb +3 -1
  224. data/lib/active_record/type_caster.rb +2 -0
  225. data/lib/active_record/validations/absence.rb +2 -0
  226. data/lib/active_record/validations/associated.rb +2 -0
  227. data/lib/active_record/validations/length.rb +2 -0
  228. data/lib/active_record/validations/presence.rb +2 -0
  229. data/lib/active_record/validations/uniqueness.rb +35 -5
  230. data/lib/active_record/validations.rb +2 -0
  231. data/lib/active_record/version.rb +2 -0
  232. data/lib/active_record.rb +11 -4
  233. data/lib/rails/generators/active_record/application_record/application_record_generator.rb +27 -0
  234. data/lib/rails/generators/active_record/{model/templates/application_record.rb → application_record/templates/application_record.rb.tt} +0 -0
  235. data/lib/rails/generators/active_record/migration/migration_generator.rb +3 -1
  236. data/lib/rails/generators/active_record/migration/templates/{create_table_migration.rb → create_table_migration.rb.tt} +0 -0
  237. data/lib/rails/generators/active_record/migration/templates/{migration.rb → migration.rb.tt} +0 -0
  238. data/lib/rails/generators/active_record/migration.rb +2 -0
  239. data/lib/rails/generators/active_record/model/model_generator.rb +2 -23
  240. data/lib/rails/generators/active_record/model/templates/{model.rb → model.rb.tt} +0 -0
  241. data/lib/rails/generators/active_record/model/templates/{module.rb → module.rb.tt} +0 -0
  242. data/lib/rails/generators/active_record.rb +3 -1
  243. metadata +24 -36
  244. data/lib/active_record/associations/preloader/belongs_to.rb +0 -15
  245. data/lib/active_record/associations/preloader/collection_association.rb +0 -17
  246. data/lib/active_record/associations/preloader/has_many.rb +0 -15
  247. data/lib/active_record/associations/preloader/has_many_through.rb +0 -19
  248. data/lib/active_record/associations/preloader/has_one.rb +0 -15
  249. data/lib/active_record/associations/preloader/has_one_through.rb +0 -9
  250. data/lib/active_record/associations/preloader/singular_association.rb +0 -18
  251. data/lib/active_record/attribute/user_provided_default.rb +0 -30
  252. data/lib/active_record/attribute.rb +0 -240
  253. data/lib/active_record/attribute_mutation_tracker.rb +0 -122
  254. data/lib/active_record/attribute_set/builder.rb +0 -126
  255. data/lib/active_record/attribute_set/yaml_encoder.rb +0 -41
  256. data/lib/active_record/attribute_set.rb +0 -113
  257. data/lib/active_record/connection_adapters/postgresql/oid/json.rb +0 -10
  258. data/lib/active_record/railties/jdbcmysql_error.rb +0 -16
  259. data/lib/active_record/relation/predicate_builder/association_query_handler.rb +0 -88
  260. data/lib/active_record/relation/predicate_builder/polymorphic_array_handler.rb +0 -59
  261. data/lib/active_record/type/internal/abstract_json.rb +0 -37
@@ -1,10 +1,11 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ActiveRecord
2
4
  module ReadonlyAttributes
3
5
  extend ActiveSupport::Concern
4
6
 
5
7
  included do
6
- class_attribute :_attr_readonly, instance_accessor: false
7
- self._attr_readonly = []
8
+ class_attribute :_attr_readonly, instance_accessor: false, default: []
8
9
  end
9
10
 
10
11
  module ClassMethods
@@ -1,6 +1,7 @@
1
- require "thread"
1
+ # frozen_string_literal: true
2
+
2
3
  require "active_support/core_ext/string/filters"
3
- require "active_support/deprecation"
4
+ require "concurrent/map"
4
5
 
5
6
  module ActiveRecord
6
7
  # = Active Record Reflection
@@ -8,10 +9,8 @@ module ActiveRecord
8
9
  extend ActiveSupport::Concern
9
10
 
10
11
  included do
11
- class_attribute :_reflections, instance_writer: false
12
- class_attribute :aggregate_reflections, instance_writer: false
13
- self._reflections = {}
14
- self.aggregate_reflections = {}
12
+ class_attribute :_reflections, instance_writer: false, default: {}
13
+ class_attribute :aggregate_reflections, instance_writer: false, default: {}
15
14
  end
16
15
 
17
16
  def self.create(macro, name, scope, options, ar)
@@ -139,7 +138,7 @@ module ActiveRecord
139
138
  # HasAndBelongsToManyReflection
140
139
  # ThroughReflection
141
140
  # PolymorphicReflection
142
- # RuntimeReflection
141
+ # RuntimeReflection
143
142
  class AbstractReflection # :nodoc:
144
143
  def through_reflection?
145
144
  false
@@ -155,14 +154,6 @@ module ActiveRecord
155
154
  klass.new(attributes, &block)
156
155
  end
157
156
 
158
- def quoted_table_name
159
- klass.quoted_table_name
160
- end
161
-
162
- def primary_key_type
163
- klass.type_for_attribute(klass.primary_key)
164
- end
165
-
166
157
  # Returns the class name for the macro.
167
158
  #
168
159
  # <tt>composed_of :balance, class_name: 'Money'</tt> returns <tt>'Money'</tt>
@@ -174,7 +165,7 @@ module ActiveRecord
174
165
  JoinKeys = Struct.new(:key, :foreign_key) # :nodoc:
175
166
 
176
167
  def join_keys
177
- get_join_keys klass
168
+ @join_keys ||= get_join_keys(klass)
178
169
  end
179
170
 
180
171
  # Returns a list of scopes that should be applied for this Reflection
@@ -183,22 +174,34 @@ module ActiveRecord
183
174
  scope ? [scope] : []
184
175
  end
185
176
 
186
- def scope_chain
187
- chain.map(&:scopes)
177
+ def build_join_constraint(table, foreign_table)
178
+ key = join_keys.key
179
+ foreign_key = join_keys.foreign_key
180
+
181
+ constraint = table[key].eq(foreign_table[foreign_key])
182
+
183
+ if klass.finder_needs_type_condition?
184
+ table.create_and([constraint, klass.send(:type_condition, table)])
185
+ else
186
+ constraint
187
+ end
188
188
  end
189
- deprecate :scope_chain
190
189
 
191
- def join_scope(table)
190
+ def join_scope(table, foreign_klass)
192
191
  predicate_builder = predicate_builder(table)
193
192
  scope_chain_items = join_scopes(table, predicate_builder)
194
193
  klass_scope = klass_join_scope(table, predicate_builder)
195
194
 
196
- scope_chain_items.inject(klass_scope || scope_chain_items.shift, &:merge!)
195
+ if type
196
+ klass_scope.where!(type => foreign_klass.polymorphic_name)
197
+ end
198
+
199
+ scope_chain_items.inject(klass_scope, &:merge!)
197
200
  end
198
201
 
199
202
  def join_scopes(table, predicate_builder) # :nodoc:
200
203
  if scope
201
- [build_scope(table, predicate_builder).instance_exec(&scope)]
204
+ [scope_for(build_scope(table, predicate_builder))]
202
205
  else
203
206
  []
204
207
  end
@@ -210,7 +213,7 @@ module ActiveRecord
210
213
  end
211
214
 
212
215
  def constraints
213
- chain.map(&:scopes).flatten
216
+ chain.flat_map(&:scopes)
214
217
  end
215
218
 
216
219
  def counter_cache_column
@@ -284,24 +287,37 @@ module ActiveRecord
284
287
  end
285
288
 
286
289
  def get_join_keys(association_klass)
287
- JoinKeys.new(join_pk(association_klass), join_fk)
290
+ JoinKeys.new(join_primary_key(association_klass), join_foreign_key)
288
291
  end
289
292
 
290
293
  def build_scope(table, predicate_builder = predicate_builder(table))
291
- Relation.create(klass, table, predicate_builder)
294
+ Relation.create(
295
+ klass,
296
+ table: table,
297
+ predicate_builder: predicate_builder
298
+ )
299
+ end
300
+
301
+ def join_primary_key(*)
302
+ foreign_key
303
+ end
304
+
305
+ def join_foreign_key
306
+ active_record_primary_key
292
307
  end
293
308
 
309
+ protected
310
+ def actual_source_reflection # FIXME: this is a horrible name
311
+ self
312
+ end
313
+
294
314
  private
295
315
  def predicate_builder(table)
296
316
  PredicateBuilder.new(TableMetadata.new(klass, table))
297
317
  end
298
318
 
299
- def join_pk(_)
300
- foreign_key
301
- end
302
-
303
- def join_fk
304
- active_record_primary_key
319
+ def primary_key(klass)
320
+ klass.primary_key || raise(UnknownPrimaryKey.new(klass))
305
321
  end
306
322
  end
307
323
 
@@ -348,6 +364,17 @@ module ActiveRecord
348
364
  #
349
365
  # <tt>composed_of :balance, class_name: 'Money'</tt> returns the Money class
350
366
  # <tt>has_many :clients</tt> returns the Client class
367
+ #
368
+ # class Company < ActiveRecord::Base
369
+ # has_many :clients
370
+ # end
371
+ #
372
+ # Company.reflect_on_association(:clients).klass
373
+ # # => Client
374
+ #
375
+ # <b>Note:</b> Do not call +klass.new+ or +klass.create+ to instantiate
376
+ # a new association object. Use +build_association+ or +create_association+
377
+ # instead. This allows plugins to hook into association object creation.
351
378
  def klass
352
379
  @klass ||= compute_class(class_name)
353
380
  end
@@ -366,8 +393,8 @@ module ActiveRecord
366
393
  active_record == other_aggregation.active_record
367
394
  end
368
395
 
369
- def scope_for(klass)
370
- scope ? klass.unscoped.instance_exec(nil, &scope) : klass.unscoped
396
+ def scope_for(relation, owner = nil)
397
+ relation.instance_exec(owner, &scope) || relation
371
398
  end
372
399
 
373
400
  private
@@ -388,23 +415,10 @@ module ActiveRecord
388
415
  # Holds all the metadata about an association as it was specified in the
389
416
  # Active Record class.
390
417
  class AssociationReflection < MacroReflection #:nodoc:
391
- # Returns the target association's class.
392
- #
393
- # class Author < ActiveRecord::Base
394
- # has_many :books
395
- # end
396
- #
397
- # Author.reflect_on_association(:books).klass
398
- # # => Book
399
- #
400
- # <b>Note:</b> Do not call +klass.new+ or +klass.create+ to instantiate
401
- # a new association object. Use +build_association+ or +create_association+
402
- # instead. This allows plugins to hook into association object creation.
403
- def klass
404
- @klass ||= compute_class(class_name)
405
- end
406
-
407
418
  def compute_class(name)
419
+ if polymorphic?
420
+ raise ArgumentError, "Polymorphic association does not support to compute class."
421
+ end
408
422
  active_record.send(:compute_type, name)
409
423
  end
410
424
 
@@ -414,31 +428,21 @@ module ActiveRecord
414
428
  def initialize(name, scope, options, active_record)
415
429
  super
416
430
  @type = options[:as] && (options[:foreign_type] || "#{options[:as]}_type")
417
- @foreign_type = options[:foreign_type] || "#{name}_type"
431
+ @foreign_type = options[:polymorphic] && (options[:foreign_type] || "#{name}_type")
418
432
  @constructable = calculate_constructable(macro, options)
419
- @association_scope_cache = {}
420
- @scope_lock = Mutex.new
433
+ @association_scope_cache = Concurrent::Map.new
421
434
 
422
435
  if options[:class_name] && options[:class_name].class == Class
423
- ActiveSupport::Deprecation.warn(<<-MSG.squish)
424
- Passing a class to the `class_name` is deprecated and will raise
425
- an ArgumentError in Rails 5.2. It eagerloads more classes than
426
- necessary and potentially creates circular dependencies.
427
-
428
- Please pass the class name as a string:
429
- `#{macro} :#{name}, class_name: '#{options[:class_name]}'`
430
- MSG
436
+ raise ArgumentError, "A class was passed to `:class_name` but we are expecting a string."
431
437
  end
432
438
  end
433
439
 
434
- def association_scope_cache(conn, owner)
440
+ def association_scope_cache(conn, owner, &block)
435
441
  key = conn.prepared_statements
436
442
  if polymorphic?
437
443
  key = [key, owner._read_attribute(@foreign_type)]
438
444
  end
439
- @association_scope_cache[key] ||= @scope_lock.synchronize {
440
- @association_scope_cache[key] ||= yield
441
- }
445
+ @association_scope_cache.compute_if_absent(key) { StatementCache.create(conn, &block) }
442
446
  end
443
447
 
444
448
  def constructable? # :nodoc:
@@ -462,10 +466,6 @@ module ActiveRecord
462
466
  options[:primary_key] || primary_key(klass || self.klass)
463
467
  end
464
468
 
465
- def association_primary_key_type
466
- klass.type_for_attribute(association_primary_key.to_s)
467
- end
468
-
469
469
  def active_record_primary_key
470
470
  @active_record_primary_key ||= options[:primary_key] || primary_key(active_record)
471
471
  end
@@ -488,7 +488,7 @@ module ActiveRecord
488
488
  alias :check_eager_loadable! :check_preloadable!
489
489
 
490
490
  def join_id_for(owner) # :nodoc:
491
- owner[active_record_primary_key]
491
+ owner[join_foreign_key]
492
492
  end
493
493
 
494
494
  def through_reflection
@@ -571,7 +571,7 @@ module ActiveRecord
571
571
  end
572
572
 
573
573
  VALID_AUTOMATIC_INVERSE_MACROS = [:has_many, :has_one, :belongs_to]
574
- INVALID_AUTOMATIC_INVERSE_OPTIONS = [:conditions, :through, :polymorphic, :foreign_key]
574
+ INVALID_AUTOMATIC_INVERSE_OPTIONS = [:through, :foreign_key]
575
575
 
576
576
  def add_as_source(seed)
577
577
  seed
@@ -589,12 +589,6 @@ module ActiveRecord
589
589
  Array(options[:extend])
590
590
  end
591
591
 
592
- protected
593
-
594
- def actual_source_reflection # FIXME: this is a horrible name
595
- self
596
- end
597
-
598
592
  private
599
593
 
600
594
  def calculate_constructable(macro, options)
@@ -635,12 +629,9 @@ module ActiveRecord
635
629
  # +automatic_inverse_of+ method is a valid reflection. We must
636
630
  # make sure that the reflection's active_record name matches up
637
631
  # with the current reflection's klass name.
638
- #
639
- # Note: klass will always be valid because when there's a NameError
640
- # from calling +klass+, +reflection+ will already be set to false.
641
632
  def valid_inverse_reflection?(reflection)
642
633
  reflection &&
643
- klass.name == reflection.active_record.name &&
634
+ klass <= reflection.active_record &&
644
635
  can_find_inverse_of_automatically?(reflection)
645
636
  end
646
637
 
@@ -648,9 +639,8 @@ module ActiveRecord
648
639
  # us from being able to guess the inverse automatically. First, the
649
640
  # <tt>inverse_of</tt> option cannot be set to false. Second, we must
650
641
  # have <tt>has_many</tt>, <tt>has_one</tt>, <tt>belongs_to</tt> associations.
651
- # Third, we must not have options such as <tt>:polymorphic</tt> or
652
- # <tt>:foreign_key</tt> which prevent us from correctly guessing the
653
- # inverse association.
642
+ # Third, we must not have options such as <tt>:foreign_key</tt>
643
+ # which prevent us from correctly guessing the inverse association.
654
644
  #
655
645
  # Anything with a scope can additionally ruin our attempt at finding an
656
646
  # inverse, so we exclude reflections with scopes.
@@ -680,10 +670,6 @@ module ActiveRecord
680
670
  def derive_join_table
681
671
  ModelSchema.derive_join_table_name active_record.table_name, klass.table_name
682
672
  end
683
-
684
- def primary_key(klass)
685
- klass.primary_key || raise(UnknownPrimaryKey.new(klass))
686
- end
687
673
  end
688
674
 
689
675
  class HasManyReflection < AssociationReflection # :nodoc:
@@ -737,30 +723,25 @@ module ActiveRecord
737
723
  end
738
724
  end
739
725
 
740
- def join_id_for(owner) # :nodoc:
741
- owner[foreign_key]
726
+ def join_primary_key(klass = nil)
727
+ polymorphic? ? association_primary_key(klass) : association_primary_key
728
+ end
729
+
730
+ def join_foreign_key
731
+ foreign_key
742
732
  end
743
733
 
744
734
  private
735
+ def can_find_inverse_of_automatically?(_)
736
+ !polymorphic? && super
737
+ end
745
738
 
746
739
  def calculate_constructable(macro, options)
747
740
  !polymorphic?
748
741
  end
749
-
750
- def join_fk
751
- foreign_key
752
- end
753
-
754
- def join_pk(klass)
755
- polymorphic? ? association_primary_key(klass) : association_primary_key
756
- end
757
742
  end
758
743
 
759
744
  class HasAndBelongsToManyReflection < AssociationReflection # :nodoc:
760
- def initialize(name, scope, options, active_record)
761
- super
762
- end
763
-
764
745
  def macro; :has_and_belongs_to_many; end
765
746
 
766
747
  def collection?
@@ -771,8 +752,7 @@ module ActiveRecord
771
752
  # Holds all the metadata about a :through association as it was specified
772
753
  # in the Active Record class.
773
754
  class ThroughReflection < AbstractReflection #:nodoc:
774
- attr_reader :delegate_reflection
775
- delegate :foreign_key, :foreign_type, :association_foreign_key,
755
+ delegate :foreign_key, :foreign_type, :association_foreign_key, :join_id_for,
776
756
  :active_record_primary_key, :type, :get_join_keys, to: :source_reflection
777
757
 
778
758
  def initialize(delegate_reflection)
@@ -863,10 +843,6 @@ module ActiveRecord
863
843
  source_reflection.join_scopes(table, predicate_builder) + super
864
844
  end
865
845
 
866
- def source_type_scope
867
- through_reflection.klass.where(foreign_type => options[:source_type])
868
- end
869
-
870
846
  def has_scope?
871
847
  scope || options[:source_type] ||
872
848
  source_reflection.has_scope? ||
@@ -887,10 +863,6 @@ module ActiveRecord
887
863
  actual_source_reflection.options[:primary_key] || primary_key(klass || self.klass)
888
864
  end
889
865
 
890
- def association_primary_key_type
891
- klass.type_for_attribute(association_primary_key.to_s)
892
- end
893
-
894
866
  # Gets an array of possible <tt>:through</tt> source reflection names in both singular and plural form.
895
867
  #
896
868
  # class Post < ActiveRecord::Base
@@ -935,10 +907,6 @@ module ActiveRecord
935
907
  through_reflection.options
936
908
  end
937
909
 
938
- def join_id_for(owner) # :nodoc:
939
- source_reflection.join_id_for(owner)
940
- end
941
-
942
910
  def check_validity!
943
911
  if through_reflection.nil?
944
912
  raise HasManyThroughAssociationNotFoundError.new(active_record.name, self)
@@ -997,23 +965,23 @@ module ActiveRecord
997
965
  collect_join_reflections(seed + [self])
998
966
  end
999
967
 
1000
- def collect_join_reflections(seed)
1001
- a = source_reflection.add_as_source seed
1002
- if options[:source_type]
1003
- through_reflection.add_as_polymorphic_through self, a
1004
- else
1005
- through_reflection.add_as_through a
1006
- end
1007
- end
1008
-
1009
- private
968
+ # TODO Change this to private once we've dropped Ruby 2.2 support.
969
+ # Workaround for Ruby 2.2 "private attribute?" warning.
970
+ protected
971
+ attr_reader :delegate_reflection
1010
972
 
1011
973
  def actual_source_reflection # FIXME: this is a horrible name
1012
- source_reflection.send(:actual_source_reflection)
974
+ source_reflection.actual_source_reflection
1013
975
  end
1014
976
 
1015
- def primary_key(klass)
1016
- klass.primary_key || raise(UnknownPrimaryKey.new(klass))
977
+ private
978
+ def collect_join_reflections(seed)
979
+ a = source_reflection.add_as_source seed
980
+ if options[:source_type]
981
+ through_reflection.add_as_polymorphic_through self, a
982
+ else
983
+ through_reflection.add_as_through a
984
+ end
1017
985
  end
1018
986
 
1019
987
  def inverse_name; delegate_reflection.send(:inverse_name); end
@@ -1030,66 +998,32 @@ module ActiveRecord
1030
998
  end
1031
999
 
1032
1000
  class PolymorphicReflection < AbstractReflection # :nodoc:
1001
+ delegate :klass, :scope, :plural_name, :type, :get_join_keys, :scope_for, to: :@reflection
1002
+
1033
1003
  def initialize(reflection, previous_reflection)
1034
1004
  @reflection = reflection
1035
1005
  @previous_reflection = previous_reflection
1036
1006
  end
1037
1007
 
1038
- def scopes
1039
- scopes = @previous_reflection.scopes
1040
- if @previous_reflection.options[:source_type]
1041
- scopes + [@previous_reflection.source_type_scope]
1042
- else
1043
- scopes
1044
- end
1045
- end
1046
-
1047
1008
  def join_scopes(table, predicate_builder) # :nodoc:
1048
1009
  scopes = @previous_reflection.join_scopes(table, predicate_builder) + super
1049
- if @previous_reflection.options[:source_type]
1050
- scopes + [@previous_reflection.source_type_scope]
1051
- else
1052
- scopes
1053
- end
1054
- end
1055
-
1056
- def klass
1057
- @reflection.klass
1058
- end
1059
-
1060
- def scope
1061
- @reflection.scope
1062
- end
1063
-
1064
- def table_name
1065
- @reflection.table_name
1066
- end
1067
-
1068
- def plural_name
1069
- @reflection.plural_name
1070
- end
1071
-
1072
- def type
1073
- @reflection.type
1010
+ scopes << build_scope(table, predicate_builder).instance_exec(nil, &source_type_scope)
1074
1011
  end
1075
1012
 
1076
1013
  def constraints
1077
- @reflection.constraints + [source_type_info]
1078
- end
1079
-
1080
- def source_type_info
1081
- type = @previous_reflection.foreign_type
1082
- source_type = @previous_reflection.options[:source_type]
1083
- lambda { |object| where(type => source_type) }
1014
+ @reflection.constraints + [source_type_scope]
1084
1015
  end
1085
1016
 
1086
- def get_join_keys(association_klass)
1087
- @reflection.get_join_keys(association_klass)
1088
- end
1017
+ private
1018
+ def source_type_scope
1019
+ type = @previous_reflection.foreign_type
1020
+ source_type = @previous_reflection.options[:source_type]
1021
+ lambda { |object| where(type => source_type) }
1022
+ end
1089
1023
  end
1090
1024
 
1091
- class RuntimeReflection < PolymorphicReflection # :nodoc:
1092
- attr_accessor :next
1025
+ class RuntimeReflection < AbstractReflection # :nodoc:
1026
+ delegate :scope, :type, :constraints, :get_join_keys, to: :@reflection
1093
1027
 
1094
1028
  def initialize(reflection, association)
1095
1029
  @reflection = reflection
@@ -1100,24 +1034,8 @@ module ActiveRecord
1100
1034
  @association.klass
1101
1035
  end
1102
1036
 
1103
- def table_name
1104
- klass.table_name
1105
- end
1106
-
1107
- def constraints
1108
- @reflection.constraints
1109
- end
1110
-
1111
- def source_type_info
1112
- @reflection.source_type_info
1113
- end
1114
-
1115
- def alias_candidate(name)
1116
- "#{plural_name}_#{name}_join"
1117
- end
1118
-
1119
- def alias_name
1120
- Arel::Table.new(table_name, type_caster: klass.type_caster)
1037
+ def aliased_table
1038
+ @aliased_table ||= Arel::Table.new(table_name, type_caster: klass.type_caster)
1121
1039
  end
1122
1040
 
1123
1041
  def all_includes; yield; end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ActiveRecord
2
4
  module Batches
3
5
  class BatchEnumerator
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "active_record/relation/batches/batch_enumerator"
2
4
 
3
5
  module ActiveRecord
@@ -45,7 +47,12 @@ module ActiveRecord
45
47
  # handle from 10000 and beyond by setting the +:start+ and +:finish+
46
48
  # option on each worker.
47
49
  #
48
- # # Let's process from record 10_000 on.
50
+ # # In worker 1, let's process until 9999 records.
51
+ # Person.find_each(finish: 9_999) do |person|
52
+ # person.party_all_night!
53
+ # end
54
+ #
55
+ # # In worker 2, let's process from record 10_000 and onwards.
49
56
  # Person.find_each(start: 10_000) do |person|
50
57
  # person.party_all_night!
51
58
  # end
@@ -209,6 +216,7 @@ module ActiveRecord
209
216
 
210
217
  relation = relation.reorder(batch_order).limit(batch_limit)
211
218
  relation = apply_limits(relation, start, finish)
219
+ relation.skip_query_cache! # Retaining the results in the query cache would undermine the point of batching
212
220
  batch_relation = relation
213
221
 
214
222
  loop do
@@ -243,20 +251,27 @@ module ActiveRecord
243
251
  end
244
252
  end
245
253
 
246
- batch_relation = relation.where(arel_attribute(primary_key).gt(primary_key_offset))
254
+ attr = Relation::QueryAttribute.new(primary_key, primary_key_offset, klass.type_for_attribute(primary_key))
255
+ batch_relation = relation.where(arel_attribute(primary_key).gt(Arel::Nodes::BindParam.new(attr)))
247
256
  end
248
257
  end
249
258
 
250
259
  private
251
260
 
252
261
  def apply_limits(relation, start, finish)
253
- relation = relation.where(arel_attribute(primary_key).gteq(start)) if start
254
- relation = relation.where(arel_attribute(primary_key).lteq(finish)) if finish
262
+ if start
263
+ attr = Relation::QueryAttribute.new(primary_key, start, klass.type_for_attribute(primary_key))
264
+ relation = relation.where(arel_attribute(primary_key).gteq(Arel::Nodes::BindParam.new(attr)))
265
+ end
266
+ if finish
267
+ attr = Relation::QueryAttribute.new(primary_key, finish, klass.type_for_attribute(primary_key))
268
+ relation = relation.where(arel_attribute(primary_key).lteq(Arel::Nodes::BindParam.new(attr)))
269
+ end
255
270
  relation
256
271
  end
257
272
 
258
273
  def batch_order
259
- "#{quoted_table_name}.#{quoted_primary_key} ASC"
274
+ arel_attribute(primary_key).asc
260
275
  end
261
276
 
262
277
  def act_on_ignored_order(error_on_ignore)