activerecord 5.1.0 → 5.2.3

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 +5 -5
  2. data/CHANGELOG.md +596 -450
  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.rb +11 -4
  8. data/lib/active_record/aggregations.rb +6 -5
  9. data/lib/active_record/association_relation.rb +7 -5
  10. data/lib/active_record/associations.rb +77 -85
  11. data/lib/active_record/associations/alias_tracker.rb +23 -32
  12. data/lib/active_record/associations/association.rb +49 -35
  13. data/lib/active_record/associations/association_scope.rb +55 -55
  14. data/lib/active_record/associations/belongs_to_association.rb +30 -11
  15. data/lib/active_record/associations/belongs_to_polymorphic_association.rb +8 -8
  16. data/lib/active_record/associations/builder/association.rb +4 -7
  17. data/lib/active_record/associations/builder/belongs_to.rb +21 -8
  18. data/lib/active_record/associations/builder/collection_association.rb +1 -1
  19. data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +3 -1
  20. data/lib/active_record/associations/builder/has_many.rb +2 -0
  21. data/lib/active_record/associations/builder/has_one.rb +2 -0
  22. data/lib/active_record/associations/builder/singular_association.rb +2 -0
  23. data/lib/active_record/associations/collection_association.rb +66 -53
  24. data/lib/active_record/associations/collection_proxy.rb +30 -73
  25. data/lib/active_record/associations/foreign_association.rb +2 -0
  26. data/lib/active_record/associations/has_many_association.rb +13 -2
  27. data/lib/active_record/associations/has_many_through_association.rb +37 -19
  28. data/lib/active_record/associations/has_one_association.rb +14 -1
  29. data/lib/active_record/associations/has_one_through_association.rb +13 -8
  30. data/lib/active_record/associations/join_dependency.rb +52 -96
  31. data/lib/active_record/associations/join_dependency/join_association.rb +22 -75
  32. data/lib/active_record/associations/join_dependency/join_base.rb +9 -8
  33. data/lib/active_record/associations/join_dependency/join_part.rb +9 -9
  34. data/lib/active_record/associations/preloader.rb +17 -37
  35. data/lib/active_record/associations/preloader/association.rb +53 -92
  36. data/lib/active_record/associations/preloader/through_association.rb +72 -73
  37. data/lib/active_record/associations/singular_association.rb +14 -16
  38. data/lib/active_record/associations/through_association.rb +27 -12
  39. data/lib/active_record/attribute_assignment.rb +2 -5
  40. data/lib/active_record/attribute_decorators.rb +3 -2
  41. data/lib/active_record/attribute_methods.rb +65 -24
  42. data/lib/active_record/attribute_methods/before_type_cast.rb +2 -0
  43. data/lib/active_record/attribute_methods/dirty.rb +33 -216
  44. data/lib/active_record/attribute_methods/primary_key.rb +10 -13
  45. data/lib/active_record/attribute_methods/query.rb +2 -0
  46. data/lib/active_record/attribute_methods/read.rb +9 -3
  47. data/lib/active_record/attribute_methods/serialization.rb +23 -0
  48. data/lib/active_record/attribute_methods/time_zone_conversion.rb +6 -8
  49. data/lib/active_record/attribute_methods/write.rb +22 -19
  50. data/lib/active_record/attributes.rb +7 -6
  51. data/lib/active_record/autosave_association.rb +15 -13
  52. data/lib/active_record/base.rb +2 -0
  53. data/lib/active_record/callbacks.rb +12 -6
  54. data/lib/active_record/coders/json.rb +2 -0
  55. data/lib/active_record/coders/yaml_column.rb +2 -0
  56. data/lib/active_record/collection_cache_key.rb +15 -11
  57. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +120 -39
  58. data/lib/active_record/connection_adapters/abstract/database_limits.rb +7 -0
  59. data/lib/active_record/connection_adapters/abstract/database_statements.rb +192 -37
  60. data/lib/active_record/connection_adapters/abstract/query_cache.rb +13 -2
  61. data/lib/active_record/connection_adapters/abstract/quoting.rb +15 -25
  62. data/lib/active_record/connection_adapters/abstract/savepoints.rb +2 -0
  63. data/lib/active_record/connection_adapters/abstract/schema_creation.rb +15 -6
  64. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +65 -7
  65. data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +31 -53
  66. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +158 -87
  67. data/lib/active_record/connection_adapters/abstract/transaction.rb +66 -21
  68. data/lib/active_record/connection_adapters/abstract_adapter.rb +86 -98
  69. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +126 -189
  70. data/lib/active_record/connection_adapters/column.rb +4 -2
  71. data/lib/active_record/connection_adapters/connection_specification.rb +17 -3
  72. data/lib/active_record/connection_adapters/determine_if_preparable_visitor.rb +13 -2
  73. data/lib/active_record/connection_adapters/mysql/column.rb +2 -0
  74. data/lib/active_record/connection_adapters/mysql/database_statements.rb +45 -15
  75. data/lib/active_record/connection_adapters/mysql/explain_pretty_printer.rb +2 -0
  76. data/lib/active_record/connection_adapters/mysql/quoting.rb +9 -10
  77. data/lib/active_record/connection_adapters/mysql/schema_creation.rb +5 -3
  78. data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +7 -10
  79. data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +30 -23
  80. data/lib/active_record/connection_adapters/mysql/schema_statements.rb +106 -1
  81. data/lib/active_record/connection_adapters/mysql/type_metadata.rb +2 -0
  82. data/lib/active_record/connection_adapters/mysql2_adapter.rb +8 -2
  83. data/lib/active_record/connection_adapters/postgresql/column.rb +30 -1
  84. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +6 -32
  85. data/lib/active_record/connection_adapters/postgresql/explain_pretty_printer.rb +2 -0
  86. data/lib/active_record/connection_adapters/postgresql/oid.rb +3 -1
  87. data/lib/active_record/connection_adapters/postgresql/oid/array.rb +13 -1
  88. data/lib/active_record/connection_adapters/postgresql/oid/bit.rb +2 -0
  89. data/lib/active_record/connection_adapters/postgresql/oid/bit_varying.rb +2 -0
  90. data/lib/active_record/connection_adapters/postgresql/oid/bytea.rb +2 -0
  91. data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +2 -0
  92. data/lib/active_record/connection_adapters/postgresql/oid/date.rb +23 -0
  93. data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +2 -0
  94. data/lib/active_record/connection_adapters/postgresql/oid/decimal.rb +3 -1
  95. data/lib/active_record/connection_adapters/postgresql/oid/enum.rb +2 -0
  96. data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +2 -0
  97. data/lib/active_record/connection_adapters/postgresql/oid/inet.rb +2 -0
  98. data/lib/active_record/connection_adapters/postgresql/oid/jsonb.rb +3 -11
  99. data/lib/active_record/connection_adapters/postgresql/oid/legacy_point.rb +2 -0
  100. data/lib/active_record/connection_adapters/postgresql/oid/money.rb +3 -1
  101. data/lib/active_record/connection_adapters/postgresql/oid/oid.rb +2 -0
  102. data/lib/active_record/connection_adapters/postgresql/oid/point.rb +2 -0
  103. data/lib/active_record/connection_adapters/postgresql/oid/range.rb +8 -2
  104. data/lib/active_record/connection_adapters/postgresql/oid/specialized_string.rb +2 -0
  105. data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +4 -2
  106. data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +3 -1
  107. data/lib/active_record/connection_adapters/postgresql/oid/vector.rb +2 -0
  108. data/lib/active_record/connection_adapters/postgresql/oid/xml.rb +2 -0
  109. data/lib/active_record/connection_adapters/postgresql/quoting.rb +22 -1
  110. data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +19 -25
  111. data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +50 -0
  112. data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +24 -11
  113. data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +20 -13
  114. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +258 -129
  115. data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +2 -0
  116. data/lib/active_record/connection_adapters/postgresql/utils.rb +3 -1
  117. data/lib/active_record/connection_adapters/postgresql_adapter.rb +75 -87
  118. data/lib/active_record/connection_adapters/schema_cache.rb +4 -2
  119. data/lib/active_record/connection_adapters/sql_type_metadata.rb +2 -0
  120. data/lib/active_record/connection_adapters/sqlite3/explain_pretty_printer.rb +2 -0
  121. data/lib/active_record/connection_adapters/sqlite3/quoting.rb +24 -1
  122. data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +2 -0
  123. data/lib/active_record/connection_adapters/sqlite3/schema_definitions.rb +6 -15
  124. data/lib/active_record/connection_adapters/sqlite3/schema_dumper.rb +3 -2
  125. data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +75 -1
  126. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +90 -96
  127. data/lib/active_record/connection_adapters/statement_pool.rb +2 -0
  128. data/lib/active_record/connection_handling.rb +4 -2
  129. data/lib/active_record/core.rb +41 -61
  130. data/lib/active_record/counter_cache.rb +20 -15
  131. data/lib/active_record/define_callbacks.rb +5 -3
  132. data/lib/active_record/dynamic_matchers.rb +9 -9
  133. data/lib/active_record/enum.rb +18 -13
  134. data/lib/active_record/errors.rb +60 -15
  135. data/lib/active_record/explain.rb +3 -1
  136. data/lib/active_record/explain_registry.rb +2 -0
  137. data/lib/active_record/explain_subscriber.rb +2 -0
  138. data/lib/active_record/fixture_set/file.rb +2 -0
  139. data/lib/active_record/fixtures.rb +67 -60
  140. data/lib/active_record/gem_version.rb +4 -2
  141. data/lib/active_record/inheritance.rb +49 -19
  142. data/lib/active_record/integration.rb +58 -19
  143. data/lib/active_record/internal_metadata.rb +2 -0
  144. data/lib/active_record/legacy_yaml_adapter.rb +3 -1
  145. data/lib/active_record/locking/optimistic.rb +30 -42
  146. data/lib/active_record/locking/pessimistic.rb +10 -7
  147. data/lib/active_record/log_subscriber.rb +46 -4
  148. data/lib/active_record/migration.rb +189 -139
  149. data/lib/active_record/migration/command_recorder.rb +11 -9
  150. data/lib/active_record/migration/compatibility.rb +81 -29
  151. data/lib/active_record/migration/join_table.rb +2 -0
  152. data/lib/active_record/model_schema.rb +74 -58
  153. data/lib/active_record/nested_attributes.rb +18 -6
  154. data/lib/active_record/no_touching.rb +3 -1
  155. data/lib/active_record/null_relation.rb +2 -0
  156. data/lib/active_record/persistence.rb +199 -54
  157. data/lib/active_record/query_cache.rb +8 -10
  158. data/lib/active_record/querying.rb +5 -3
  159. data/lib/active_record/railtie.rb +62 -6
  160. data/lib/active_record/railties/console_sandbox.rb +2 -0
  161. data/lib/active_record/railties/controller_runtime.rb +2 -0
  162. data/lib/active_record/railties/databases.rake +48 -38
  163. data/lib/active_record/readonly_attributes.rb +3 -2
  164. data/lib/active_record/reflection.rb +137 -207
  165. data/lib/active_record/relation.rb +132 -207
  166. data/lib/active_record/relation/batches.rb +32 -17
  167. data/lib/active_record/relation/batches/batch_enumerator.rb +2 -0
  168. data/lib/active_record/relation/calculations.rb +66 -25
  169. data/lib/active_record/relation/delegation.rb +45 -29
  170. data/lib/active_record/relation/finder_methods.rb +76 -85
  171. data/lib/active_record/relation/from_clause.rb +2 -8
  172. data/lib/active_record/relation/merger.rb +53 -23
  173. data/lib/active_record/relation/predicate_builder.rb +60 -79
  174. data/lib/active_record/relation/predicate_builder/array_handler.rb +10 -7
  175. data/lib/active_record/relation/predicate_builder/association_query_value.rb +46 -0
  176. data/lib/active_record/relation/predicate_builder/base_handler.rb +2 -2
  177. data/lib/active_record/relation/predicate_builder/basic_object_handler.rb +12 -1
  178. data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +56 -0
  179. data/lib/active_record/relation/predicate_builder/range_handler.rb +26 -9
  180. data/lib/active_record/relation/predicate_builder/relation_handler.rb +6 -0
  181. data/lib/active_record/relation/query_attribute.rb +28 -2
  182. data/lib/active_record/relation/query_methods.rb +135 -103
  183. data/lib/active_record/relation/record_fetch_warning.rb +2 -0
  184. data/lib/active_record/relation/spawn_methods.rb +4 -2
  185. data/lib/active_record/relation/where_clause.rb +65 -67
  186. data/lib/active_record/relation/where_clause_factory.rb +5 -48
  187. data/lib/active_record/result.rb +2 -0
  188. data/lib/active_record/runtime_registry.rb +2 -0
  189. data/lib/active_record/sanitization.rb +129 -121
  190. data/lib/active_record/schema.rb +4 -2
  191. data/lib/active_record/schema_dumper.rb +36 -26
  192. data/lib/active_record/schema_migration.rb +2 -0
  193. data/lib/active_record/scoping.rb +12 -10
  194. data/lib/active_record/scoping/default.rb +10 -7
  195. data/lib/active_record/scoping/named.rb +40 -12
  196. data/lib/active_record/secure_token.rb +2 -0
  197. data/lib/active_record/serialization.rb +2 -0
  198. data/lib/active_record/statement_cache.rb +22 -12
  199. data/lib/active_record/store.rb +3 -1
  200. data/lib/active_record/suppressor.rb +2 -0
  201. data/lib/active_record/table_metadata.rb +12 -3
  202. data/lib/active_record/tasks/database_tasks.rb +38 -26
  203. data/lib/active_record/tasks/mysql_database_tasks.rb +11 -50
  204. data/lib/active_record/tasks/postgresql_database_tasks.rb +11 -3
  205. data/lib/active_record/tasks/sqlite_database_tasks.rb +25 -3
  206. data/lib/active_record/timestamp.rb +13 -6
  207. data/lib/active_record/touch_later.rb +2 -0
  208. data/lib/active_record/transactions.rb +32 -27
  209. data/lib/active_record/translation.rb +2 -0
  210. data/lib/active_record/type.rb +4 -1
  211. data/lib/active_record/type/adapter_specific_registry.rb +2 -0
  212. data/lib/active_record/type/date.rb +2 -0
  213. data/lib/active_record/type/date_time.rb +2 -0
  214. data/lib/active_record/type/decimal_without_scale.rb +2 -0
  215. data/lib/active_record/type/hash_lookup_type_map.rb +2 -0
  216. data/lib/active_record/type/internal/timezone.rb +2 -0
  217. data/lib/active_record/type/json.rb +30 -0
  218. data/lib/active_record/type/serialized.rb +6 -0
  219. data/lib/active_record/type/text.rb +2 -0
  220. data/lib/active_record/type/time.rb +2 -0
  221. data/lib/active_record/type/type_map.rb +2 -0
  222. data/lib/active_record/type/unsigned_integer.rb +2 -0
  223. data/lib/active_record/type_caster.rb +2 -0
  224. data/lib/active_record/type_caster/connection.rb +2 -0
  225. data/lib/active_record/type_caster/map.rb +3 -1
  226. data/lib/active_record/validations.rb +2 -0
  227. data/lib/active_record/validations/absence.rb +2 -0
  228. data/lib/active_record/validations/associated.rb +2 -0
  229. data/lib/active_record/validations/length.rb +2 -0
  230. data/lib/active_record/validations/presence.rb +2 -0
  231. data/lib/active_record/validations/uniqueness.rb +36 -6
  232. data/lib/active_record/version.rb +2 -0
  233. data/lib/rails/generators/active_record.rb +3 -1
  234. data/lib/rails/generators/active_record/application_record/application_record_generator.rb +27 -0
  235. data/lib/rails/generators/active_record/{model/templates/application_record.rb → application_record/templates/application_record.rb.tt} +0 -0
  236. data/lib/rails/generators/active_record/migration.rb +2 -0
  237. data/lib/rails/generators/active_record/migration/migration_generator.rb +3 -1
  238. data/lib/rails/generators/active_record/migration/templates/{create_table_migration.rb → create_table_migration.rb.tt} +0 -0
  239. data/lib/rails/generators/active_record/migration/templates/{migration.rb → migration.rb.tt} +0 -0
  240. data/lib/rails/generators/active_record/model/model_generator.rb +2 -23
  241. data/lib/rails/generators/active_record/model/templates/{model.rb → model.rb.tt} +0 -0
  242. data/lib/rails/generators/active_record/model/templates/{module.rb → module.rb.tt} +0 -0
  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.rb +0 -240
  252. data/lib/active_record/attribute/user_provided_default.rb +0 -30
  253. data/lib/active_record/attribute_mutation_tracker.rb +0 -113
  254. data/lib/active_record/attribute_set.rb +0 -113
  255. data/lib/active_record/attribute_set/builder.rb +0 -124
  256. data/lib/active_record/attribute_set/yaml_encoder.rb +0 -41
  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 -33
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ActiveRecord
2
4
  module Associations
3
5
  # Association proxies in Active Record are middlemen between the object that
@@ -30,7 +32,10 @@ module ActiveRecord
30
32
  class CollectionProxy < Relation
31
33
  def initialize(klass, association) #:nodoc:
32
34
  @association = association
33
- super klass, klass.arel_table, klass.predicate_builder
35
+ super klass
36
+
37
+ extensions = association.extensions
38
+ extend(*extensions) if extensions.any?
34
39
  end
35
40
 
36
41
  def target
@@ -130,8 +135,9 @@ module ActiveRecord
130
135
  # # #<Pet id: 2, name: "Spook", person_id: 1>,
131
136
  # # #<Pet id: 3, name: "Choo-Choo", person_id: 1>
132
137
  # # ]
133
- def find(*args, &block)
134
- @association.find(*args, &block)
138
+ def find(*args)
139
+ return super if block_given?
140
+ @association.find(*args)
135
141
  end
136
142
 
137
143
  ##
@@ -360,34 +366,6 @@ module ActiveRecord
360
366
  @association.create!(attributes, &block)
361
367
  end
362
368
 
363
- # Add one or more records to the collection by setting their foreign keys
364
- # to the association's primary key. Since #<< flattens its argument list and
365
- # inserts each record, +push+ and #concat behave identically. Returns +self+
366
- # so method calls may be chained.
367
- #
368
- # class Person < ActiveRecord::Base
369
- # has_many :pets
370
- # end
371
- #
372
- # person.pets.size # => 0
373
- # person.pets.concat(Pet.new(name: 'Fancy-Fancy'))
374
- # person.pets.concat(Pet.new(name: 'Spook'), Pet.new(name: 'Choo-Choo'))
375
- # person.pets.size # => 3
376
- #
377
- # person.id # => 1
378
- # person.pets
379
- # # => [
380
- # # #<Pet id: 1, name: "Fancy-Fancy", person_id: 1>,
381
- # # #<Pet id: 2, name: "Spook", person_id: 1>,
382
- # # #<Pet id: 3, name: "Choo-Choo", person_id: 1>
383
- # # ]
384
- #
385
- # person.pets.concat([Pet.new(name: 'Brain'), Pet.new(name: 'Benny')])
386
- # person.pets.size # => 5
387
- def concat(*records)
388
- @association.concat(*records)
389
- end
390
-
391
369
  # Replaces this collection with +other_array+. This will perform a diff
392
370
  # and delete/add only records that have changed.
393
371
  #
@@ -494,7 +472,7 @@ module ActiveRecord
494
472
  # Pet.find(1, 2, 3)
495
473
  # # => ActiveRecord::RecordNotFound: Couldn't find all Pets with 'id': (1, 2, 3)
496
474
  def delete_all(dependent = nil)
497
- @association.delete_all(dependent)
475
+ @association.delete_all(dependent).tap { reset_scope }
498
476
  end
499
477
 
500
478
  # Deletes the records of the collection directly from the database
@@ -521,7 +499,7 @@ module ActiveRecord
521
499
  #
522
500
  # Pet.find(1) # => Couldn't find Pet with id=1
523
501
  def destroy_all
524
- @association.destroy_all
502
+ @association.destroy_all.tap { reset_scope }
525
503
  end
526
504
 
527
505
  # Deletes the +records+ supplied from the collection according to the strategy
@@ -640,7 +618,7 @@ module ActiveRecord
640
618
  # # #<Pet id: 3, name: "Choo-Choo", person_id: 1>
641
619
  # # ]
642
620
  def delete(*records)
643
- @association.delete(*records)
621
+ @association.delete(*records).tap { reset_scope }
644
622
  end
645
623
 
646
624
  # Destroys the +records+ supplied and removes them from the collection.
@@ -712,7 +690,7 @@ module ActiveRecord
712
690
  #
713
691
  # Pet.find(4, 5, 6) # => ActiveRecord::RecordNotFound: Couldn't find all Pets with 'id': (4, 5, 6)
714
692
  def destroy(*records)
715
- @association.destroy(*records)
693
+ @association.destroy(*records).tap { reset_scope }
716
694
  end
717
695
 
718
696
  ##
@@ -743,10 +721,6 @@ module ActiveRecord
743
721
  # # ]
744
722
 
745
723
  #--
746
- def uniq
747
- load_target.uniq
748
- end
749
-
750
724
  def calculate(operation, column_name)
751
725
  null_scope? ? scope.calculate(operation, column_name) : super
752
726
  end
@@ -986,6 +960,12 @@ module ActiveRecord
986
960
  load_target == other
987
961
  end
988
962
 
963
+ ##
964
+ # :method: to_ary
965
+ #
966
+ # :call-seq:
967
+ # to_ary()
968
+ #
989
969
  # Returns a new array of objects from the collection. If the collection
990
970
  # hasn't been loaded, it fetches the records from the database.
991
971
  #
@@ -1019,18 +999,15 @@ module ActiveRecord
1019
999
  # # #<Pet id: 5, name: "Brain", person_id: 1>,
1020
1000
  # # #<Pet id: 6, name: "Boss", person_id: 1>
1021
1001
  # # ]
1022
- def to_ary
1023
- load_target.dup
1024
- end
1025
- alias_method :to_a, :to_ary
1026
1002
 
1027
1003
  def records # :nodoc:
1028
1004
  load_target
1029
1005
  end
1030
1006
 
1031
1007
  # Adds one or more +records+ to the collection by setting their foreign keys
1032
- # to the association's primary key. Returns +self+, so several appends may be
1033
- # chained together.
1008
+ # to the association's primary key. Since +<<+ flattens its argument list and
1009
+ # inserts each record, +push+ and +concat+ behave identically. Returns +self+
1010
+ # so several appends may be chained together.
1034
1011
  #
1035
1012
  # class Person < ActiveRecord::Base
1036
1013
  # has_many :pets
@@ -1053,6 +1030,7 @@ module ActiveRecord
1053
1030
  end
1054
1031
  alias_method :push, :<<
1055
1032
  alias_method :append, :<<
1033
+ alias_method :concat, :<<
1056
1034
 
1057
1035
  def prepend(*args)
1058
1036
  raise NoMethodError, "prepend on association is not defined. Please use <<, push or append"
@@ -1070,7 +1048,6 @@ module ActiveRecord
1070
1048
  end
1071
1049
 
1072
1050
  # Reloads the collection from the database. Returns +self+.
1073
- # Equivalent to <tt>collection(true)</tt>.
1074
1051
  #
1075
1052
  # class Person < ActiveRecord::Base
1076
1053
  # has_many :pets
@@ -1084,13 +1061,9 @@ module ActiveRecord
1084
1061
  #
1085
1062
  # person.pets.reload # fetches pets from the database
1086
1063
  # # => [#<Pet id: 1, name: "Snoop", group: "dogs", person_id: 1>]
1087
- #
1088
- # person.pets(true) # fetches pets from the database
1089
- # # => [#<Pet id: 1, name: "Snoop", group: "dogs", person_id: 1>]
1090
1064
  def reload
1091
- @scope = nil
1092
1065
  proxy_association.reload
1093
- self
1066
+ reset_scope
1094
1067
  end
1095
1068
 
1096
1069
  # Unloads the association. Returns +self+.
@@ -1110,9 +1083,14 @@ module ActiveRecord
1110
1083
  # person.pets # fetches pets from the database
1111
1084
  # # => [#<Pet id: 1, name: "Snoop", group: "dogs", person_id: 1>]
1112
1085
  def reset
1113
- @scope = nil
1114
1086
  proxy_association.reset
1115
1087
  proxy_association.reset_scope
1088
+ reset_scope
1089
+ end
1090
+
1091
+ def reset_scope # :nodoc:
1092
+ @offsets = {}
1093
+ @scope = nil
1116
1094
  self
1117
1095
  end
1118
1096
 
@@ -1125,19 +1103,6 @@ module ActiveRecord
1125
1103
 
1126
1104
  delegate(*delegate_methods, to: :scope)
1127
1105
 
1128
- module DelegateExtending # :nodoc:
1129
- private
1130
- def method_missing(method, *args, &block)
1131
- extending_values = association_scope.extending_values
1132
- if extending_values.any? && (extending_values - self.class.included_modules).any?
1133
- self.class.include(*extending_values)
1134
- public_send(method, *args, &block)
1135
- else
1136
- super
1137
- end
1138
- end
1139
- end
1140
-
1141
1106
  private
1142
1107
 
1143
1108
  def find_nth_with_limit(index, limit)
@@ -1158,17 +1123,9 @@ module ActiveRecord
1158
1123
  @association.find_from_target?
1159
1124
  end
1160
1125
 
1161
- def association_scope
1162
- @association.association_scope
1163
- end
1164
-
1165
1126
  def exec_queries
1166
1127
  load_target
1167
1128
  end
1168
-
1169
- def respond_to_missing?(method, _)
1170
- association_scope.respond_to?(method) || super
1171
- end
1172
1129
  end
1173
1130
  end
1174
1131
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ActiveRecord::Associations
2
4
  module ForeignAssociation # :nodoc:
3
5
  def foreign_key_present?
@@ -1,6 +1,8 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ActiveRecord
2
- # = Active Record Has Many Association
3
4
  module Associations
5
+ # = Active Record Has Many Association
4
6
  # This is the proxy that handles a has many association.
5
7
  #
6
8
  # If the association has a <tt>:through</tt> option further specialization
@@ -61,7 +63,7 @@ module ActiveRecord
61
63
  count = if reflection.has_cached_counter?
62
64
  owner._read_attribute(reflection.counter_cache_column).to_i
63
65
  else
64
- scope.count
66
+ scope.count(:all)
65
67
  end
66
68
 
67
69
  # If there's nothing in the database and @target has no new records
@@ -97,6 +99,7 @@ module ActiveRecord
97
99
  def delete_or_nullify_all_records(method)
98
100
  count = delete_count(method, scope)
99
101
  update_counter(-count)
102
+ count
100
103
  end
101
104
 
102
105
  # Deletes the records according to the <tt>:dependent</tt> option.
@@ -128,6 +131,14 @@ module ActiveRecord
128
131
  end
129
132
  saved_successfully
130
133
  end
134
+
135
+ def difference(a, b)
136
+ a - b
137
+ end
138
+
139
+ def intersection(a, b)
140
+ a & b
141
+ end
131
142
  end
132
143
  end
133
144
  end
@@ -1,14 +1,14 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ActiveRecord
2
- # = Active Record Has Many Through Association
3
4
  module Associations
5
+ # = Active Record Has Many Through Association
4
6
  class HasManyThroughAssociation < HasManyAssociation #:nodoc:
5
7
  include ThroughAssociation
6
8
 
7
9
  def initialize(owner, reflection)
8
10
  super
9
-
10
- @through_records = {}
11
- @through_association = nil
11
+ @through_records = {}
12
12
  end
13
13
 
14
14
  def concat(*records)
@@ -48,11 +48,6 @@ module ActiveRecord
48
48
  end
49
49
 
50
50
  private
51
-
52
- def through_association
53
- @through_association ||= owner.association(through_reflection.name)
54
- end
55
-
56
51
  # The through record (built with build_record) is temporarily cached
57
52
  # so that it may be reused if insert_record is subsequently called.
58
53
  #
@@ -95,7 +90,7 @@ module ActiveRecord
95
90
  def build_record(attributes)
96
91
  ensure_not_nested
97
92
 
98
- record = super(attributes)
93
+ record = super
99
94
 
100
95
  inverse = source_reflection.inverse_of
101
96
  if inverse
@@ -109,6 +104,11 @@ module ActiveRecord
109
104
  record
110
105
  end
111
106
 
107
+ def remove_records(existing_records, records, method)
108
+ super
109
+ delete_through_records(records)
110
+ end
111
+
112
112
  def target_reflection_has_associated_record?
113
113
  !(through_reflection.belongs_to? && owner[through_reflection.foreign_key].blank?)
114
114
  end
@@ -133,21 +133,15 @@ module ActiveRecord
133
133
 
134
134
  scope = through_association.scope
135
135
  scope.where! construct_join_attributes(*records)
136
+ scope = scope.where(through_scope_attributes)
136
137
 
137
138
  case method
138
139
  when :destroy
139
140
  if scope.klass.primary_key
140
- count = scope.destroy_all.length
141
+ count = scope.destroy_all.count(&:destroyed?)
141
142
  else
142
143
  scope.each(&:_run_destroy_callbacks)
143
-
144
- arel = scope.arel
145
-
146
- stmt = Arel::DeleteManager.new
147
- stmt.from scope.klass.arel_table
148
- stmt.wheres = arel.constraints
149
-
150
- count = scope.klass.connection.delete(stmt, "SQL", scope.bound_attributes)
144
+ count = scope.delete_all
151
145
  end
152
146
  when :nullify
153
147
  count = scope.update_all(source_reflection.foreign_key => nil)
@@ -167,6 +161,30 @@ module ActiveRecord
167
161
  else
168
162
  update_counter(-count)
169
163
  end
164
+
165
+ count
166
+ end
167
+
168
+ def difference(a, b)
169
+ distribution = distribution(b)
170
+
171
+ a.reject { |record| mark_occurrence(distribution, record) }
172
+ end
173
+
174
+ def intersection(a, b)
175
+ distribution = distribution(b)
176
+
177
+ a.select { |record| mark_occurrence(distribution, record) }
178
+ end
179
+
180
+ def mark_occurrence(distribution, record)
181
+ distribution[record] > 0 && distribution[record] -= 1
182
+ end
183
+
184
+ def distribution(array)
185
+ array.each_with_object(Hash.new(0)) do |record, distribution|
186
+ distribution[record] += 1
187
+ end
170
188
  end
171
189
 
172
190
  def through_records_for(record)
@@ -1,6 +1,8 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ActiveRecord
2
- # = Active Record Has One Association
3
4
  module Associations
5
+ # = Active Record Has One Association
4
6
  class HasOneAssociation < SingularAssociation #:nodoc:
5
7
  include ForeignAssociation
6
8
 
@@ -56,7 +58,9 @@ module ActiveRecord
56
58
  when :delete
57
59
  target.delete
58
60
  when :destroy
61
+ target.destroyed_by_association = reflection
59
62
  target.destroy
63
+ throw(:abort) unless target.destroyed?
60
64
  when :nullify
61
65
  target.update_columns(reflection.foreign_key => nil) if target.persisted?
62
66
  end
@@ -78,6 +82,7 @@ module ActiveRecord
78
82
  when :delete
79
83
  target.delete
80
84
  when :destroy
85
+ target.destroyed_by_association = reflection
81
86
  target.destroy
82
87
  else
83
88
  nullify_owner_attributes(target)
@@ -102,6 +107,14 @@ module ActiveRecord
102
107
  yield
103
108
  end
104
109
  end
110
+
111
+ def _create_record(attributes, raise_error = false, &block)
112
+ unless owner.persisted?
113
+ raise ActiveRecord::RecordNotSaved, "You cannot call create unless the parent is saved"
114
+ end
115
+
116
+ super
117
+ end
105
118
  end
106
119
  end
107
120
  end
@@ -1,20 +1,21 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ActiveRecord
2
- # = Active Record Has One Through Association
3
4
  module Associations
5
+ # = Active Record Has One Through Association
4
6
  class HasOneThroughAssociation < HasOneAssociation #:nodoc:
5
7
  include ThroughAssociation
6
8
 
7
- def replace(record)
8
- create_through_record(record)
9
+ def replace(record, save = true)
10
+ create_through_record(record, save)
9
11
  self.target = record
10
12
  end
11
13
 
12
14
  private
13
-
14
- def create_through_record(record)
15
+ def create_through_record(record, save)
15
16
  ensure_not_nested
16
17
 
17
- through_proxy = owner.association(through_reflection.name)
18
+ through_proxy = through_association
18
19
  through_record = through_proxy.load_target
19
20
 
20
21
  if through_record && !record
@@ -27,8 +28,12 @@ module ActiveRecord
27
28
  end
28
29
 
29
30
  if through_record
30
- through_record.update(attributes)
31
- elsif owner.new_record?
31
+ if through_record.new_record?
32
+ through_record.assign_attributes(attributes)
33
+ else
34
+ through_record.update(attributes)
35
+ end
36
+ elsif owner.new_record? || !save
32
37
  through_proxy.build(attributes)
33
38
  else
34
39
  through_proxy.create(attributes)