activerecord 6.0.4.1 → 6.1.0.rc1

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 (242) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +767 -851
  3. data/MIT-LICENSE +1 -1
  4. data/README.rdoc +3 -3
  5. data/lib/active_record.rb +7 -14
  6. data/lib/active_record/aggregations.rb +1 -1
  7. data/lib/active_record/association_relation.rb +22 -14
  8. data/lib/active_record/associations.rb +114 -11
  9. data/lib/active_record/associations/alias_tracker.rb +19 -15
  10. data/lib/active_record/associations/association.rb +39 -27
  11. data/lib/active_record/associations/association_scope.rb +11 -15
  12. data/lib/active_record/associations/belongs_to_association.rb +15 -5
  13. data/lib/active_record/associations/belongs_to_polymorphic_association.rb +1 -1
  14. data/lib/active_record/associations/builder/association.rb +9 -3
  15. data/lib/active_record/associations/builder/belongs_to.rb +10 -7
  16. data/lib/active_record/associations/builder/collection_association.rb +5 -4
  17. data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +0 -1
  18. data/lib/active_record/associations/builder/has_many.rb +6 -2
  19. data/lib/active_record/associations/builder/has_one.rb +11 -14
  20. data/lib/active_record/associations/builder/singular_association.rb +1 -1
  21. data/lib/active_record/associations/collection_association.rb +19 -13
  22. data/lib/active_record/associations/collection_proxy.rb +12 -5
  23. data/lib/active_record/associations/foreign_association.rb +13 -0
  24. data/lib/active_record/associations/has_many_association.rb +24 -2
  25. data/lib/active_record/associations/has_many_through_association.rb +10 -4
  26. data/lib/active_record/associations/has_one_association.rb +15 -1
  27. data/lib/active_record/associations/join_dependency.rb +63 -49
  28. data/lib/active_record/associations/join_dependency/join_association.rb +29 -14
  29. data/lib/active_record/associations/join_dependency/join_part.rb +1 -1
  30. data/lib/active_record/associations/preloader.rb +5 -3
  31. data/lib/active_record/associations/preloader/association.rb +13 -5
  32. data/lib/active_record/associations/preloader/through_association.rb +1 -1
  33. data/lib/active_record/associations/singular_association.rb +1 -1
  34. data/lib/active_record/attribute_assignment.rb +10 -8
  35. data/lib/active_record/attribute_methods.rb +52 -48
  36. data/lib/active_record/attribute_methods/before_type_cast.rb +13 -9
  37. data/lib/active_record/attribute_methods/dirty.rb +1 -11
  38. data/lib/active_record/attribute_methods/primary_key.rb +6 -2
  39. data/lib/active_record/attribute_methods/query.rb +3 -6
  40. data/lib/active_record/attribute_methods/read.rb +8 -11
  41. data/lib/active_record/attribute_methods/serialization.rb +4 -4
  42. data/lib/active_record/attribute_methods/time_zone_conversion.rb +12 -13
  43. data/lib/active_record/attribute_methods/write.rb +12 -20
  44. data/lib/active_record/attributes.rb +27 -7
  45. data/lib/active_record/autosave_association.rb +47 -30
  46. data/lib/active_record/base.rb +2 -14
  47. data/lib/active_record/callbacks.rb +32 -22
  48. data/lib/active_record/coders/yaml_column.rb +1 -1
  49. data/lib/active_record/connection_adapters.rb +50 -0
  50. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +180 -134
  51. data/lib/active_record/connection_adapters/abstract/database_limits.rb +2 -44
  52. data/lib/active_record/connection_adapters/abstract/database_statements.rb +65 -22
  53. data/lib/active_record/connection_adapters/abstract/query_cache.rb +2 -7
  54. data/lib/active_record/connection_adapters/abstract/quoting.rb +34 -34
  55. data/lib/active_record/connection_adapters/abstract/savepoints.rb +3 -3
  56. data/lib/active_record/connection_adapters/abstract/schema_creation.rb +153 -116
  57. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +110 -30
  58. data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +3 -3
  59. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +224 -85
  60. data/lib/active_record/connection_adapters/abstract/transaction.rb +66 -24
  61. data/lib/active_record/connection_adapters/abstract_adapter.rb +31 -70
  62. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +123 -87
  63. data/lib/active_record/connection_adapters/column.rb +15 -1
  64. data/lib/active_record/connection_adapters/deduplicable.rb +29 -0
  65. data/lib/active_record/connection_adapters/legacy_pool_manager.rb +31 -0
  66. data/lib/active_record/connection_adapters/mysql/database_statements.rb +22 -24
  67. data/lib/active_record/connection_adapters/mysql/explain_pretty_printer.rb +1 -1
  68. data/lib/active_record/connection_adapters/mysql/quoting.rb +1 -1
  69. data/lib/active_record/connection_adapters/mysql/schema_creation.rb +33 -6
  70. data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +8 -0
  71. data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +1 -1
  72. data/lib/active_record/connection_adapters/mysql/schema_statements.rb +3 -3
  73. data/lib/active_record/connection_adapters/mysql/type_metadata.rb +10 -1
  74. data/lib/active_record/connection_adapters/mysql2_adapter.rb +31 -12
  75. data/lib/active_record/connection_adapters/pool_config.rb +63 -0
  76. data/lib/active_record/connection_adapters/pool_manager.rb +43 -0
  77. data/lib/active_record/connection_adapters/postgresql/column.rb +24 -1
  78. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +12 -53
  79. data/lib/active_record/connection_adapters/postgresql/oid.rb +2 -0
  80. data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +3 -5
  81. data/lib/active_record/connection_adapters/postgresql/oid/date.rb +2 -2
  82. data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +2 -10
  83. data/lib/active_record/connection_adapters/postgresql/oid/interval.rb +49 -0
  84. data/lib/active_record/connection_adapters/postgresql/oid/legacy_point.rb +2 -2
  85. data/lib/active_record/connection_adapters/postgresql/oid/macaddr.rb +25 -0
  86. data/lib/active_record/connection_adapters/postgresql/oid/money.rb +2 -2
  87. data/lib/active_record/connection_adapters/postgresql/oid/point.rb +2 -2
  88. data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +11 -1
  89. data/lib/active_record/connection_adapters/postgresql/quoting.rb +4 -4
  90. data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +1 -1
  91. data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +5 -1
  92. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +61 -29
  93. data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +8 -0
  94. data/lib/active_record/connection_adapters/postgresql_adapter.rb +72 -55
  95. data/lib/active_record/connection_adapters/schema_cache.rb +98 -15
  96. data/lib/active_record/connection_adapters/sql_type_metadata.rb +10 -0
  97. data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +30 -5
  98. data/lib/active_record/connection_adapters/sqlite3/quoting.rb +1 -1
  99. data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +5 -1
  100. data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +36 -3
  101. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +48 -50
  102. data/lib/active_record/connection_handling.rb +210 -71
  103. data/lib/active_record/core.rb +215 -49
  104. data/lib/active_record/database_configurations.rb +124 -85
  105. data/lib/active_record/database_configurations/connection_url_resolver.rb +98 -0
  106. data/lib/active_record/database_configurations/database_config.rb +52 -9
  107. data/lib/active_record/database_configurations/hash_config.rb +54 -8
  108. data/lib/active_record/database_configurations/url_config.rb +15 -40
  109. data/lib/active_record/delegated_type.rb +209 -0
  110. data/lib/active_record/destroy_association_async_job.rb +36 -0
  111. data/lib/active_record/enum.rb +33 -23
  112. data/lib/active_record/errors.rb +47 -12
  113. data/lib/active_record/explain.rb +9 -4
  114. data/lib/active_record/explain_subscriber.rb +1 -1
  115. data/lib/active_record/fixture_set/file.rb +10 -17
  116. data/lib/active_record/fixture_set/model_metadata.rb +1 -2
  117. data/lib/active_record/fixture_set/render_context.rb +1 -1
  118. data/lib/active_record/fixture_set/table_row.rb +2 -2
  119. data/lib/active_record/fixtures.rb +54 -8
  120. data/lib/active_record/gem_version.rb +3 -3
  121. data/lib/active_record/inheritance.rb +40 -18
  122. data/lib/active_record/insert_all.rb +32 -5
  123. data/lib/active_record/integration.rb +3 -5
  124. data/lib/active_record/internal_metadata.rb +15 -4
  125. data/lib/active_record/legacy_yaml_adapter.rb +7 -3
  126. data/lib/active_record/locking/optimistic.rb +13 -16
  127. data/lib/active_record/locking/pessimistic.rb +6 -2
  128. data/lib/active_record/log_subscriber.rb +26 -8
  129. data/lib/active_record/middleware/database_selector.rb +4 -1
  130. data/lib/active_record/middleware/database_selector/resolver.rb +5 -0
  131. data/lib/active_record/middleware/database_selector/resolver/session.rb +3 -0
  132. data/lib/active_record/migration.rb +113 -83
  133. data/lib/active_record/migration/command_recorder.rb +47 -27
  134. data/lib/active_record/migration/compatibility.rb +67 -17
  135. data/lib/active_record/model_schema.rb +88 -42
  136. data/lib/active_record/nested_attributes.rb +2 -3
  137. data/lib/active_record/no_touching.rb +1 -1
  138. data/lib/active_record/persistence.rb +50 -45
  139. data/lib/active_record/query_cache.rb +15 -5
  140. data/lib/active_record/querying.rb +11 -6
  141. data/lib/active_record/railtie.rb +64 -44
  142. data/lib/active_record/railties/databases.rake +253 -98
  143. data/lib/active_record/readonly_attributes.rb +4 -0
  144. data/lib/active_record/reflection.rb +59 -44
  145. data/lib/active_record/relation.rb +90 -64
  146. data/lib/active_record/relation/batches.rb +38 -31
  147. data/lib/active_record/relation/batches/batch_enumerator.rb +25 -9
  148. data/lib/active_record/relation/calculations.rb +100 -43
  149. data/lib/active_record/relation/finder_methods.rb +44 -14
  150. data/lib/active_record/relation/from_clause.rb +1 -1
  151. data/lib/active_record/relation/merger.rb +20 -23
  152. data/lib/active_record/relation/predicate_builder.rb +57 -33
  153. data/lib/active_record/relation/predicate_builder/array_handler.rb +8 -9
  154. data/lib/active_record/relation/predicate_builder/association_query_value.rb +2 -2
  155. data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +3 -3
  156. data/lib/active_record/relation/predicate_builder/relation_handler.rb +1 -1
  157. data/lib/active_record/relation/query_methods.rb +319 -196
  158. data/lib/active_record/relation/record_fetch_warning.rb +3 -3
  159. data/lib/active_record/relation/spawn_methods.rb +6 -5
  160. data/lib/active_record/relation/where_clause.rb +104 -57
  161. data/lib/active_record/result.rb +41 -33
  162. data/lib/active_record/runtime_registry.rb +2 -2
  163. data/lib/active_record/sanitization.rb +6 -17
  164. data/lib/active_record/schema_dumper.rb +34 -4
  165. data/lib/active_record/schema_migration.rb +0 -4
  166. data/lib/active_record/scoping/named.rb +1 -17
  167. data/lib/active_record/secure_token.rb +16 -8
  168. data/lib/active_record/serialization.rb +5 -3
  169. data/lib/active_record/signed_id.rb +116 -0
  170. data/lib/active_record/statement_cache.rb +20 -4
  171. data/lib/active_record/store.rb +2 -2
  172. data/lib/active_record/suppressor.rb +2 -2
  173. data/lib/active_record/table_metadata.rb +36 -52
  174. data/lib/active_record/tasks/database_tasks.rb +139 -113
  175. data/lib/active_record/tasks/mysql_database_tasks.rb +34 -35
  176. data/lib/active_record/tasks/postgresql_database_tasks.rb +24 -26
  177. data/lib/active_record/tasks/sqlite_database_tasks.rb +13 -9
  178. data/lib/active_record/test_databases.rb +5 -4
  179. data/lib/active_record/test_fixtures.rb +36 -33
  180. data/lib/active_record/timestamp.rb +4 -6
  181. data/lib/active_record/touch_later.rb +21 -21
  182. data/lib/active_record/transactions.rb +15 -64
  183. data/lib/active_record/type.rb +8 -1
  184. data/lib/active_record/type/serialized.rb +6 -2
  185. data/lib/active_record/type_caster/connection.rb +0 -1
  186. data/lib/active_record/type_caster/map.rb +8 -5
  187. data/lib/active_record/validations.rb +1 -0
  188. data/lib/active_record/validations/associated.rb +1 -1
  189. data/lib/active_record/validations/numericality.rb +35 -0
  190. data/lib/active_record/validations/uniqueness.rb +24 -4
  191. data/lib/arel.rb +5 -13
  192. data/lib/arel/attributes/attribute.rb +4 -0
  193. data/lib/arel/collectors/bind.rb +5 -0
  194. data/lib/arel/collectors/composite.rb +8 -0
  195. data/lib/arel/collectors/sql_string.rb +7 -0
  196. data/lib/arel/collectors/substitute_binds.rb +7 -0
  197. data/lib/arel/nodes.rb +3 -1
  198. data/lib/arel/nodes/binary.rb +82 -8
  199. data/lib/arel/nodes/bind_param.rb +8 -0
  200. data/lib/arel/nodes/casted.rb +21 -9
  201. data/lib/arel/nodes/equality.rb +6 -9
  202. data/lib/arel/nodes/grouping.rb +3 -0
  203. data/lib/arel/nodes/homogeneous_in.rb +72 -0
  204. data/lib/arel/nodes/in.rb +8 -1
  205. data/lib/arel/nodes/infix_operation.rb +13 -1
  206. data/lib/arel/nodes/join_source.rb +1 -1
  207. data/lib/arel/nodes/node.rb +7 -6
  208. data/lib/arel/nodes/ordering.rb +27 -0
  209. data/lib/arel/nodes/sql_literal.rb +3 -0
  210. data/lib/arel/nodes/table_alias.rb +7 -3
  211. data/lib/arel/nodes/unary.rb +0 -1
  212. data/lib/arel/predications.rb +12 -18
  213. data/lib/arel/select_manager.rb +1 -2
  214. data/lib/arel/table.rb +13 -5
  215. data/lib/arel/visitors.rb +0 -7
  216. data/lib/arel/visitors/dot.rb +14 -2
  217. data/lib/arel/visitors/mysql.rb +11 -1
  218. data/lib/arel/visitors/postgresql.rb +15 -4
  219. data/lib/arel/visitors/to_sql.rb +89 -78
  220. data/lib/rails/generators/active_record/migration.rb +6 -1
  221. data/lib/rails/generators/active_record/migration/migration_generator.rb +1 -0
  222. data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb.tt +2 -0
  223. data/lib/rails/generators/active_record/migration/templates/migration.rb.tt +3 -3
  224. data/lib/rails/generators/active_record/model/model_generator.rb +39 -2
  225. data/lib/rails/generators/active_record/model/templates/abstract_base_class.rb.tt +7 -0
  226. metadata +30 -31
  227. data/lib/active_record/advisory_lock_base.rb +0 -18
  228. data/lib/active_record/attribute_decorators.rb +0 -88
  229. data/lib/active_record/connection_adapters/connection_specification.rb +0 -296
  230. data/lib/active_record/connection_adapters/determine_if_preparable_visitor.rb +0 -29
  231. data/lib/active_record/define_callbacks.rb +0 -22
  232. data/lib/active_record/railties/collection_cache_association_loading.rb +0 -34
  233. data/lib/active_record/relation/predicate_builder/base_handler.rb +0 -18
  234. data/lib/active_record/relation/where_clause_factory.rb +0 -33
  235. data/lib/arel/attributes.rb +0 -22
  236. data/lib/arel/visitors/depth_first.rb +0 -203
  237. data/lib/arel/visitors/ibm_db.rb +0 -34
  238. data/lib/arel/visitors/informix.rb +0 -62
  239. data/lib/arel/visitors/mssql.rb +0 -156
  240. data/lib/arel/visitors/oracle.rb +0 -158
  241. data/lib/arel/visitors/oracle12.rb +0 -65
  242. data/lib/arel/visitors/where_sql.rb +0 -22
@@ -19,6 +19,10 @@ module ActiveRecord
19
19
  def readonly_attributes
20
20
  _attr_readonly
21
21
  end
22
+
23
+ def readonly_attribute?(name) # :nodoc:
24
+ _attr_readonly.include?(name)
25
+ end
22
26
  end
23
27
  end
24
28
  end
@@ -162,13 +162,7 @@ module ActiveRecord
162
162
  # <tt>composed_of :balance, class_name: 'Money'</tt> returns <tt>'Money'</tt>
163
163
  # <tt>has_many :clients</tt> returns <tt>'Client'</tt>
164
164
  def class_name
165
- @class_name ||= (options[:class_name] || derive_class_name).to_s
166
- end
167
-
168
- JoinKeys = Struct.new(:key, :foreign_key) # :nodoc:
169
-
170
- def join_keys
171
- @join_keys ||= get_join_keys(klass)
165
+ @class_name ||= -(options[:class_name]&.to_s || derive_class_name)
172
166
  end
173
167
 
174
168
  # Returns a list of scopes that should be applied for this Reflection
@@ -188,10 +182,10 @@ module ActiveRecord
188
182
 
189
183
  scope_chain_items.inject(klass_scope, &:merge!)
190
184
 
191
- key = join_keys.key
192
- foreign_key = join_keys.foreign_key
185
+ primary_key = join_primary_key
186
+ foreign_key = join_foreign_key
193
187
 
194
- klass_scope.where!(table[key].eq(foreign_table[foreign_key]))
188
+ klass_scope.where!(table[primary_key].eq(foreign_table[foreign_key]))
195
189
 
196
190
  if klass.finder_needs_type_condition?
197
191
  klass_scope.where!(klass.send(:type_condition, table))
@@ -218,14 +212,14 @@ module ActiveRecord
218
212
  end
219
213
 
220
214
  def counter_cache_column
221
- if belongs_to?
215
+ @counter_cache_column ||= if belongs_to?
222
216
  if options[:counter_cache] == true
223
- "#{active_record.name.demodulize.underscore.pluralize}_count"
217
+ -"#{active_record.name.demodulize.underscore.pluralize}_count"
224
218
  elsif options[:counter_cache]
225
- options[:counter_cache].to_s
219
+ -options[:counter_cache].to_s
226
220
  end
227
221
  else
228
- options[:counter_cache] ? options[:counter_cache].to_s : "#{name}_count"
222
+ -(options[:counter_cache]&.to_s || "#{name}_count")
229
223
  end
230
224
  end
231
225
 
@@ -272,7 +266,7 @@ module ActiveRecord
272
266
  def has_cached_counter?
273
267
  options[:counter_cache] ||
274
268
  inverse_which_updates_counter_cache && inverse_which_updates_counter_cache.options[:counter_cache] &&
275
- !!active_record.columns_hash[counter_cache_column]
269
+ active_record.has_attribute?(counter_cache_column)
276
270
  end
277
271
 
278
272
  def counter_must_be_updated_by_has_many?
@@ -287,10 +281,6 @@ module ActiveRecord
287
281
  collect_join_chain
288
282
  end
289
283
 
290
- def get_join_keys(association_klass)
291
- JoinKeys.new(join_primary_key(association_klass), join_foreign_key)
292
- end
293
-
294
284
  def build_scope(table, predicate_builder = predicate_builder(table), klass = self.klass)
295
285
  Relation.create(
296
286
  klass,
@@ -299,12 +289,8 @@ module ActiveRecord
299
289
  )
300
290
  end
301
291
 
302
- def join_primary_key(*)
303
- foreign_key
304
- end
305
-
306
- def join_foreign_key
307
- active_record_primary_key
292
+ def strict_loading?
293
+ options[:strict_loading]
308
294
  end
309
295
 
310
296
  protected
@@ -428,8 +414,8 @@ module ActiveRecord
428
414
 
429
415
  def initialize(name, scope, options, active_record)
430
416
  super
431
- @type = options[:as] && (options[:foreign_type] || "#{options[:as]}_type")
432
- @foreign_type = options[:polymorphic] && (options[:foreign_type] || "#{name}_type")
417
+ @type = -(options[:foreign_type]&.to_s || "#{options[:as]}_type") if options[:as]
418
+ @foreign_type = -(options[:foreign_type]&.to_s || "#{name}_type") if options[:polymorphic]
433
419
  @constructable = calculate_constructable(macro, options)
434
420
 
435
421
  if options[:class_name] && options[:class_name].class == Class
@@ -450,24 +436,31 @@ module ActiveRecord
450
436
  end
451
437
 
452
438
  def join_table
453
- @join_table ||= options[:join_table] || derive_join_table
439
+ @join_table ||= -(options[:join_table]&.to_s || derive_join_table)
454
440
  end
455
441
 
456
442
  def foreign_key
457
- @foreign_key ||= options[:foreign_key] || derive_foreign_key.freeze
443
+ @foreign_key ||= -(options[:foreign_key]&.to_s || derive_foreign_key)
458
444
  end
459
445
 
460
446
  def association_foreign_key
461
- @association_foreign_key ||= options[:association_foreign_key] || class_name.foreign_key
447
+ @association_foreign_key ||= -(options[:association_foreign_key]&.to_s || class_name.foreign_key)
462
448
  end
463
449
 
464
- # klass option is necessary to support loading polymorphic associations
465
450
  def association_primary_key(klass = nil)
466
- options[:primary_key] || primary_key(klass || self.klass)
451
+ primary_key(klass || self.klass)
467
452
  end
468
453
 
469
454
  def active_record_primary_key
470
- @active_record_primary_key ||= options[:primary_key] || primary_key(active_record)
455
+ @active_record_primary_key ||= -(options[:primary_key]&.to_s || primary_key(active_record))
456
+ end
457
+
458
+ def join_primary_key(klass = nil)
459
+ foreign_key
460
+ end
461
+
462
+ def join_foreign_key
463
+ active_record_primary_key
471
464
  end
472
465
 
473
466
  def check_validity!
@@ -683,10 +676,6 @@ module ActiveRecord
683
676
  Associations::HasManyAssociation
684
677
  end
685
678
  end
686
-
687
- def association_primary_key(klass = nil)
688
- primary_key(klass || self.klass)
689
- end
690
679
  end
691
680
 
692
681
  class HasOneReflection < AssociationReflection # :nodoc:
@@ -721,6 +710,15 @@ module ActiveRecord
721
710
  end
722
711
  end
723
712
 
713
+ # klass option is necessary to support loading polymorphic associations
714
+ def association_primary_key(klass = nil)
715
+ if primary_key = options[:primary_key]
716
+ @association_primary_key ||= -primary_key.to_s
717
+ else
718
+ primary_key(klass || self.klass)
719
+ end
720
+ end
721
+
724
722
  def join_primary_key(klass = nil)
725
723
  polymorphic? ? association_primary_key(klass) : association_primary_key
726
724
  end
@@ -729,6 +727,10 @@ module ActiveRecord
729
727
  foreign_key
730
728
  end
731
729
 
730
+ def join_foreign_type
731
+ foreign_type
732
+ end
733
+
732
734
  private
733
735
  def can_find_inverse_of_automatically?(_)
734
736
  !polymorphic? && super
@@ -750,8 +752,8 @@ module ActiveRecord
750
752
  # Holds all the metadata about a :through association as it was specified
751
753
  # in the Active Record class.
752
754
  class ThroughReflection < AbstractReflection #:nodoc:
753
- delegate :foreign_key, :foreign_type, :association_foreign_key, :join_id_for,
754
- :active_record_primary_key, :type, :get_join_keys, to: :source_reflection
755
+ delegate :foreign_key, :foreign_type, :association_foreign_key, :join_id_for, :type,
756
+ :active_record_primary_key, :join_foreign_key, to: :source_reflection
755
757
 
756
758
  def initialize(delegate_reflection)
757
759
  @delegate_reflection = delegate_reflection
@@ -858,7 +860,15 @@ module ActiveRecord
858
860
  def association_primary_key(klass = nil)
859
861
  # Get the "actual" source reflection if the immediate source reflection has a
860
862
  # source reflection itself
861
- actual_source_reflection.options[:primary_key] || primary_key(klass || self.klass)
863
+ if primary_key = actual_source_reflection.options[:primary_key]
864
+ @association_primary_key ||= -primary_key.to_s
865
+ else
866
+ primary_key(klass || self.klass)
867
+ end
868
+ end
869
+
870
+ def join_primary_key(klass = self.klass)
871
+ source_reflection.join_primary_key(klass)
862
872
  end
863
873
 
864
874
  # Gets an array of possible <tt>:through</tt> source reflection names in both singular and plural form.
@@ -907,7 +917,7 @@ module ActiveRecord
907
917
 
908
918
  def check_validity!
909
919
  if through_reflection.nil?
910
- raise HasManyThroughAssociationNotFoundError.new(active_record.name, self)
920
+ raise HasManyThroughAssociationNotFoundError.new(active_record, self)
911
921
  end
912
922
 
913
923
  if through_reflection.polymorphic?
@@ -994,7 +1004,8 @@ module ActiveRecord
994
1004
  end
995
1005
 
996
1006
  class PolymorphicReflection < AbstractReflection # :nodoc:
997
- delegate :klass, :scope, :plural_name, :type, :get_join_keys, :scope_for, to: :@reflection
1007
+ delegate :klass, :scope, :plural_name, :type, :join_primary_key, :join_foreign_key,
1008
+ :name, :scope_for, to: :@reflection
998
1009
 
999
1010
  def initialize(reflection, previous_reflection)
1000
1011
  @reflection = reflection
@@ -1019,7 +1030,7 @@ module ActiveRecord
1019
1030
  end
1020
1031
 
1021
1032
  class RuntimeReflection < AbstractReflection # :nodoc:
1022
- delegate :scope, :type, :constraints, :get_join_keys, to: :@reflection
1033
+ delegate :scope, :type, :constraints, :join_foreign_key, to: :@reflection
1023
1034
 
1024
1035
  def initialize(reflection, association)
1025
1036
  @reflection = reflection
@@ -1031,7 +1042,11 @@ module ActiveRecord
1031
1042
  end
1032
1043
 
1033
1044
  def aliased_table
1034
- @aliased_table ||= Arel::Table.new(table_name, type_caster: klass.type_caster)
1045
+ klass.arel_table
1046
+ end
1047
+
1048
+ def join_primary_key(klass = self.klass)
1049
+ @reflection.join_primary_key(klass)
1035
1050
  end
1036
1051
 
1037
1052
  def all_includes; yield; end
@@ -7,7 +7,7 @@ module ActiveRecord
7
7
  :order, :joins, :left_outer_joins, :references,
8
8
  :extending, :unscope, :optimizer_hints, :annotate]
9
9
 
10
- SINGLE_VALUE_METHODS = [:limit, :offset, :lock, :readonly, :reordering,
10
+ SINGLE_VALUE_METHODS = [:limit, :offset, :lock, :readonly, :reordering, :strict_loading,
11
11
  :reverse_order, :distinct, :create_with, :skip_query_cache]
12
12
 
13
13
  CLAUSE_METHODS = [:where, :having, :from]
@@ -28,7 +28,6 @@ module ActiveRecord
28
28
  @klass = klass
29
29
  @table = table
30
30
  @values = values
31
- @offsets = {}
32
31
  @loaded = false
33
32
  @predicate_builder = predicate_builder
34
33
  @delegate_to_klass = false
@@ -40,8 +39,9 @@ module ActiveRecord
40
39
  end
41
40
 
42
41
  def arel_attribute(name) # :nodoc:
43
- klass.arel_attribute(name, table)
42
+ table[name]
44
43
  end
44
+ deprecate :arel_attribute
45
45
 
46
46
  def bind_attribute(name, value) # :nodoc:
47
47
  if reflection = klass._reflect_on_association(name)
@@ -49,7 +49,7 @@ module ActiveRecord
49
49
  value = value.read_attribute(reflection.klass.primary_key) unless value.nil?
50
50
  end
51
51
 
52
- attr = arel_attribute(name)
52
+ attr = table[name]
53
53
  bind = predicate_builder.build_bind_attribute(attr.name, value)
54
54
  yield attr, bind
55
55
  end
@@ -67,10 +67,9 @@ module ActiveRecord
67
67
  # user = users.new { |user| user.name = 'Oscar' }
68
68
  # user.name # => Oscar
69
69
  def new(attributes = nil, &block)
70
- block = _deprecated_scope_block("new", &block)
71
- scoping { klass.new(attributes, &block) }
70
+ block = current_scope_restoring_block(&block)
71
+ scoping { _new(attributes, &block) }
72
72
  end
73
-
74
73
  alias build new
75
74
 
76
75
  # Tries to create a new record with the same scoped attributes
@@ -96,8 +95,8 @@ module ActiveRecord
96
95
  if attributes.is_a?(Array)
97
96
  attributes.collect { |attr| create(attr, &block) }
98
97
  else
99
- block = _deprecated_scope_block("create", &block)
100
- scoping { klass.create(attributes, &block) }
98
+ block = current_scope_restoring_block(&block)
99
+ scoping { _create(attributes, &block) }
101
100
  end
102
101
  end
103
102
 
@@ -111,8 +110,8 @@ module ActiveRecord
111
110
  if attributes.is_a?(Array)
112
111
  attributes.collect { |attr| create!(attr, &block) }
113
112
  else
114
- block = _deprecated_scope_block("create!", &block)
115
- scoping { klass.create!(attributes, &block) }
113
+ block = current_scope_restoring_block(&block)
114
+ scoping { _create!(attributes, &block) }
116
115
  end
117
116
  end
118
117
 
@@ -308,7 +307,7 @@ module ActiveRecord
308
307
  # last updated record.
309
308
  #
310
309
  # Product.where("name like ?", "%Game%").cache_key(:last_reviewed_at)
311
- def cache_key(timestamp_column = :updated_at)
310
+ def cache_key(timestamp_column = "updated_at")
312
311
  @cache_keys ||= {}
313
312
  @cache_keys[timestamp_column] ||= klass.collection_cache_key(self, timestamp_column)
314
313
  end
@@ -317,7 +316,7 @@ module ActiveRecord
317
316
  query_signature = ActiveSupport::Digest.hexdigest(to_sql)
318
317
  key = "#{klass.model_name.cache_key}/query-#{query_signature}"
319
318
 
320
- if cache_version(timestamp_column)
319
+ if collection_cache_versioning
321
320
  key
322
321
  else
323
322
  "#{key}-#{compute_cache_version(timestamp_column)}"
@@ -343,15 +342,17 @@ module ActiveRecord
343
342
  end
344
343
 
345
344
  def compute_cache_version(timestamp_column) # :nodoc:
345
+ timestamp_column = timestamp_column.to_s
346
+
346
347
  if loaded? || distinct_value
347
348
  size = records.size
348
349
  if size > 0
349
- timestamp = max_by(&timestamp_column)._read_attribute(timestamp_column)
350
+ timestamp = records.map { |record| record.read_attribute(timestamp_column) }.max
350
351
  end
351
352
  else
352
353
  collection = eager_loading? ? apply_join_dependency : self
353
354
 
354
- column = connection.visitor.compile(arel_attribute(timestamp_column))
355
+ column = connection.visitor.compile(table[timestamp_column])
355
356
  select_values = "COUNT(*) AS #{connection.quote_column_name("size")}, MAX(%s) AS timestamp"
356
357
 
357
358
  if collection.has_limit_or_offset?
@@ -365,14 +366,12 @@ module ActiveRecord
365
366
  arel = query.arel
366
367
  end
367
368
 
368
- result = connection.select_one(arel, nil)
369
+ size, timestamp = connection.select_rows(arel, nil).first
369
370
 
370
- if result
371
+ if size
371
372
  column_type = klass.type_for_attribute(timestamp_column)
372
- timestamp = column_type.deserialize(result["timestamp"])
373
- size = result["size"]
373
+ timestamp = column_type.deserialize(timestamp)
374
374
  else
375
- timestamp = nil
376
375
  size = 0
377
376
  end
378
377
  end
@@ -407,9 +406,9 @@ module ActiveRecord
407
406
  already_in_scope? ? yield : _scoping(self) { yield }
408
407
  end
409
408
 
410
- def _exec_scope(name, *args, &block) # :nodoc:
409
+ def _exec_scope(*args, &block) # :nodoc:
411
410
  @delegate_to_klass = true
412
- _scoping(_deprecated_spawn(name)) { instance_exec(*args, &block) || self }
411
+ _scoping(nil) { instance_exec(*args, &block) || self }
413
412
  ensure
414
413
  @delegate_to_klass = false
415
414
  end
@@ -417,7 +416,7 @@ module ActiveRecord
417
416
  # Updates all records in the current relation with details given. This method constructs a single SQL UPDATE
418
417
  # statement and sends it straight to the database. It does not instantiate the involved models and it does not
419
418
  # trigger Active Record callbacks or validations. However, values passed to #update_all will still go through
420
- # Active Record's normal type casting and serialization.
419
+ # Active Record's normal type casting and serialization. Returns the number of rows affected.
421
420
  #
422
421
  # Note: As Active Record callbacks are not triggered, this method will not automatically update +updated_at+/+updated_on+ columns.
423
422
  #
@@ -448,7 +447,7 @@ module ActiveRecord
448
447
 
449
448
  stmt = Arel::UpdateManager.new
450
449
  stmt.table(arel.join_sources.empty? ? table : arel.source)
451
- stmt.key = arel_attribute(primary_key)
450
+ stmt.key = table[primary_key]
452
451
  stmt.take(arel.limit)
453
452
  stmt.offset(arel.offset)
454
453
  stmt.order(*arel.orders)
@@ -458,7 +457,7 @@ module ActiveRecord
458
457
  if klass.locking_enabled? &&
459
458
  !updates.key?(klass.locking_column) &&
460
459
  !updates.key?(klass.locking_column.to_sym)
461
- attr = arel_attribute(klass.locking_column)
460
+ attr = table[klass.locking_column]
462
461
  updates[attr.name] = _increment_attribute(attr)
463
462
  end
464
463
  stmt.set _substitute_values(updates)
@@ -477,12 +476,24 @@ module ActiveRecord
477
476
  end
478
477
  end
479
478
 
480
- def update_counters(counters) # :nodoc:
479
+ # Updates the counters of the records in the current relation.
480
+ #
481
+ # ==== Parameters
482
+ #
483
+ # * +counter+ - A Hash containing the names of the fields to update as keys and the amount to update as values.
484
+ # * <tt>:touch</tt> option - Touch the timestamp columns when updating.
485
+ # * If attributes names are passed, they are updated along with update_at/on attributes.
486
+ #
487
+ # ==== Examples
488
+ #
489
+ # # For Posts by a given author increment the comment_count by 1.
490
+ # Post.where(author_id: author.id).update_counters(comment_count: 1)
491
+ def update_counters(counters)
481
492
  touch = counters.delete(:touch)
482
493
 
483
494
  updates = {}
484
495
  counters.each do |counter_name, value|
485
- attr = arel_attribute(counter_name)
496
+ attr = table[counter_name]
486
497
  updates[attr.name] = _increment_attribute(attr, value)
487
498
  end
488
499
 
@@ -578,7 +589,7 @@ module ActiveRecord
578
589
 
579
590
  stmt = Arel::DeleteManager.new
580
591
  stmt.from(arel.join_sources.empty? ? table : arel.source)
581
- stmt.key = arel_attribute(primary_key)
592
+ stmt.key = table[primary_key]
582
593
  stmt.take(arel.limit)
583
594
  stmt.offset(arel.offset)
584
595
  stmt.order(*arel.orders)
@@ -623,7 +634,10 @@ module ActiveRecord
623
634
  #
624
635
  # Post.where(published: true).load # => #<ActiveRecord::Relation>
625
636
  def load(&block)
626
- exec_queries(&block) unless loaded?
637
+ unless loaded?
638
+ @records = exec_queries(&block)
639
+ @loaded = true
640
+ end
627
641
 
628
642
  self
629
643
  end
@@ -636,11 +650,9 @@ module ActiveRecord
636
650
 
637
651
  def reset
638
652
  @delegate_to_klass = false
639
- @_deprecated_scope_source = nil
640
653
  @to_sql = @arel = @loaded = @should_eager_load = nil
654
+ @offsets = @take = nil
641
655
  @records = [].freeze
642
- @offsets = {}
643
- @take = nil
644
656
  self
645
657
  end
646
658
 
@@ -718,7 +730,7 @@ module ActiveRecord
718
730
  end
719
731
 
720
732
  def inspect
721
- subject = loaded? ? records : self
733
+ subject = loaded? ? records : annotate("loading for inspect")
722
734
  entries = subject.take([limit_value, 11].compact.min).map!(&:inspect)
723
735
 
724
736
  entries[10] = "..." if entries.size == 11
@@ -735,25 +747,31 @@ module ActiveRecord
735
747
  end
736
748
 
737
749
  def alias_tracker(joins = [], aliases = nil) # :nodoc:
738
- joins += [aliases] if aliases
739
- ActiveRecord::Associations::AliasTracker.create(connection, table.name, joins)
750
+ ActiveRecord::Associations::AliasTracker.create(connection, table.name, joins, aliases)
751
+ end
752
+
753
+ class StrictLoadingScope # :nodoc:
754
+ def self.empty_scope?
755
+ true
756
+ end
757
+
758
+ def self.strict_loading_value
759
+ true
760
+ end
740
761
  end
741
762
 
742
763
  def preload_associations(records) # :nodoc:
743
764
  preload = preload_values
744
765
  preload += includes_values unless eager_loading?
745
766
  preloader = nil
767
+ scope = strict_loading_value ? StrictLoadingScope : nil
746
768
  preload.each do |associations|
747
769
  preloader ||= build_preloader
748
- preloader.preload records, associations
770
+ preloader.preload records, associations, scope
749
771
  end
750
772
  end
751
773
 
752
- attr_reader :_deprecated_scope_source # :nodoc:
753
-
754
774
  protected
755
- attr_writer :_deprecated_scope_source # :nodoc:
756
-
757
775
  def load_records(records)
758
776
  @records = records.freeze
759
777
  @loaded = true
@@ -765,23 +783,29 @@ module ActiveRecord
765
783
 
766
784
  private
767
785
  def already_in_scope?
768
- @delegate_to_klass && begin
769
- scope = klass.current_scope(true)
770
- scope && !scope._deprecated_scope_source
771
- end
772
- end
773
-
774
- def _deprecated_spawn(name)
775
- spawn.tap { |scope| scope._deprecated_scope_source = name }
786
+ @delegate_to_klass && klass.current_scope(true)
776
787
  end
777
788
 
778
- def _deprecated_scope_block(name, &block)
789
+ def current_scope_restoring_block(&block)
790
+ current_scope = klass.current_scope(true)
779
791
  -> record do
780
- klass.current_scope = _deprecated_spawn(name)
792
+ klass.current_scope = current_scope
781
793
  yield record if block_given?
782
794
  end
783
795
  end
784
796
 
797
+ def _new(attributes, &block)
798
+ klass.new(attributes, &block)
799
+ end
800
+
801
+ def _create(attributes, &block)
802
+ klass.create(attributes, &block)
803
+ end
804
+
805
+ def _create!(attributes, &block)
806
+ klass.create!(attributes, &block)
807
+ end
808
+
785
809
  def _scoping(scope)
786
810
  previous, klass.current_scope = klass.current_scope(true), scope
787
811
  yield
@@ -791,7 +815,7 @@ module ActiveRecord
791
815
 
792
816
  def _substitute_values(values)
793
817
  values.map do |name, value|
794
- attr = arel_attribute(name)
818
+ attr = table[name]
795
819
  unless Arel.arel_node?(value)
796
820
  type = klass.type_for_attribute(attr.name)
797
821
  value = predicate_builder.build_bind_attribute(attr.name, type.cast(value))
@@ -809,27 +833,29 @@ module ActiveRecord
809
833
 
810
834
  def exec_queries(&block)
811
835
  skip_query_cache_if_necessary do
812
- @records =
813
- if eager_loading?
836
+ records =
837
+ if where_clause.contradiction?
838
+ []
839
+ elsif eager_loading?
814
840
  apply_join_dependency do |relation, join_dependency|
815
841
  if relation.null_relation?
816
842
  []
817
843
  else
818
844
  relation = join_dependency.apply_column_aliases(relation)
819
845
  rows = connection.select_all(relation.arel, "SQL")
820
- join_dependency.instantiate(rows, &block)
846
+ join_dependency.instantiate(rows, strict_loading_value, &block)
821
847
  end.freeze
822
848
  end
823
849
  else
824
850
  klass.find_by_sql(arel, &block).freeze
825
851
  end
826
852
 
827
- preload_associations(@records) unless skip_preloading_value
853
+ preload_associations(records) unless skip_preloading_value
828
854
 
829
- @records.each(&:readonly!) if readonly_value
855
+ records.each(&:readonly!) if readonly_value
856
+ records.each(&:strict_loading!) if strict_loading_value
830
857
 
831
- @loaded = true
832
- @records
858
+ records
833
859
  end
834
860
  end
835
861
 
@@ -848,27 +874,27 @@ module ActiveRecord
848
874
  end
849
875
 
850
876
  def references_eager_loaded_tables?
851
- joined_tables = arel.join_sources.map do |join|
877
+ joined_tables = build_joins([]).flat_map do |join|
852
878
  if join.is_a?(Arel::Nodes::StringJoin)
853
879
  tables_in_string(join.left)
854
880
  else
855
- [join.left.table_name, join.left.table_alias]
881
+ join.left.name
856
882
  end
857
883
  end
858
884
 
859
- joined_tables += [table.name, table.table_alias]
885
+ joined_tables << table.name
860
886
 
861
887
  # always convert table names to downcase as in Oracle quoted table names are in uppercase
862
- joined_tables = joined_tables.flatten.compact.map(&:downcase).uniq
888
+ joined_tables.map!(&:downcase)
863
889
 
864
- (references_values - joined_tables).any?
890
+ !(references_values.map(&:to_s) - joined_tables).empty?
865
891
  end
866
892
 
867
893
  def tables_in_string(string)
868
894
  return [] if string.blank?
869
895
  # always convert table names to downcase as in Oracle quoted table names are in uppercase
870
896
  # ignore raw_sql_ that is used by Oracle adapter as alias for limit/offset subqueries
871
- string.scan(/([a-zA-Z_][.\w]+).?\./).flatten.map(&:downcase).uniq - ["raw_sql_"]
897
+ string.scan(/[a-zA-Z_][.\w]+(?=.?\.)/).map!(&:downcase) - ["raw_sql_"]
872
898
  end
873
899
  end
874
900
  end