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,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  # This class is inherited by the has_one and belongs_to association classes
2
4
 
3
5
  module ActiveRecord::Associations::Builder # :nodoc:
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ActiveRecord
2
4
  module Associations
3
5
  # = Active Record Association Collection
@@ -50,17 +52,19 @@ module ActiveRecord
50
52
 
51
53
  # Implements the ids writer method, e.g. foo.item_ids= for Foo.has_many :items
52
54
  def ids_writer(ids)
53
- pk_type = reflection.association_primary_key_type
55
+ primary_key = reflection.association_primary_key
56
+ pk_type = klass.type_for_attribute(primary_key)
54
57
  ids = Array(ids).reject(&:blank?)
55
58
  ids.map! { |i| pk_type.cast(i) }
56
59
 
57
- primary_key = reflection.association_primary_key
58
60
  records = klass.where(primary_key => ids).index_by do |r|
59
61
  r.public_send(primary_key)
60
62
  end.values_at(*ids).compact
61
63
 
62
64
  if records.size != ids.size
63
- klass.all.raise_record_not_found_exception!(ids, records.size, ids.size, primary_key)
65
+ found_ids = records.map { |record| record.public_send(primary_key) }
66
+ not_found_ids = ids - found_ids
67
+ klass.all.raise_record_not_found_exception!(ids, records.size, ids.size, primary_key, not_found_ids)
64
68
  else
65
69
  replace(records)
66
70
  end
@@ -69,26 +73,29 @@ module ActiveRecord
69
73
  def reset
70
74
  super
71
75
  @target = []
76
+ @association_ids = nil
72
77
  end
73
78
 
74
79
  def find(*args)
75
- if block_given?
76
- load_target.find(*args) { |*block_args| yield(*block_args) }
77
- else
78
- if options[:inverse_of] && loaded?
79
- args_flatten = args.flatten
80
- raise RecordNotFound, "Couldn't find #{scope.klass.name} without an ID" if args_flatten.blank?
81
- result = find_by_scan(*args)
82
-
83
- result_size = Array(result).size
84
- if !result || result_size != args_flatten.size
85
- scope.raise_record_not_found_exception!(args_flatten, result_size, args_flatten.size)
86
- else
87
- result
88
- end
80
+ if options[:inverse_of] && loaded?
81
+ args_flatten = args.flatten
82
+ model = scope.klass
83
+
84
+ if args_flatten.blank?
85
+ error_message = "Couldn't find #{model.name} without an ID"
86
+ raise RecordNotFound.new(error_message, model.name, model.primary_key, args)
87
+ end
88
+
89
+ result = find_by_scan(*args)
90
+
91
+ result_size = Array(result).size
92
+ if !result || result_size != args_flatten.size
93
+ scope.raise_record_not_found_exception!(args_flatten, result_size, args_flatten.size)
89
94
  else
90
- scope.find(*args)
95
+ result
91
96
  end
97
+ else
98
+ scope.find(*args)
92
99
  end
93
100
  end
94
101
 
@@ -180,8 +187,6 @@ module ActiveRecord
180
187
  # are actually removed from the database, that depends precisely on
181
188
  # +delete_records+. They are in any case removed from the collection.
182
189
  def delete(*records)
183
- return if records.empty?
184
- records = find(records) if records.any? { |record| record.kind_of?(Integer) || record.kind_of?(String) }
185
190
  delete_or_destroy(records, options[:dependent])
186
191
  end
187
192
 
@@ -191,8 +196,6 @@ module ActiveRecord
191
196
  # Note that this method removes records from the database ignoring the
192
197
  # +:dependent+ option.
193
198
  def destroy(*records)
194
- return if records.empty?
195
- records = find(records) if records.any? { |record| record.kind_of?(Integer) || record.kind_of?(String) }
196
199
  delete_or_destroy(records, :destroy)
197
200
  end
198
201
 
@@ -300,18 +303,17 @@ module ActiveRecord
300
303
  private
301
304
 
302
305
  def find_target
303
- return scope.to_a if skip_statement_cache?
306
+ scope = self.scope
307
+ return scope.to_a if skip_statement_cache?(scope)
304
308
 
305
309
  conn = klass.connection
306
- sc = reflection.association_scope_cache(conn, owner) do
307
- StatementCache.create(conn) { |params|
308
- as = AssociationScope.create { params.bind }
309
- target_scope.merge as.scope(self, conn)
310
- }
310
+ sc = reflection.association_scope_cache(conn, owner) do |params|
311
+ as = AssociationScope.create { params.bind }
312
+ target_scope.merge!(as.scope(self))
311
313
  end
312
314
 
313
315
  binds = AssociationScope.get_bind_values(owner, reflection.chain)
314
- sc.execute(binds, klass, conn) do |record|
316
+ sc.execute(binds, conn) do |record|
315
317
  set_inverse_instance(record)
316
318
  end
317
319
  end
@@ -357,7 +359,10 @@ module ActiveRecord
357
359
  transaction do
358
360
  add_to_target(build_record(attributes)) do |record|
359
361
  yield(record) if block_given?
360
- insert_record(record, true, raise) { @_was_loaded = loaded? }
362
+ insert_record(record, true, raise) {
363
+ @_was_loaded = loaded?
364
+ @association_ids = nil
365
+ }
361
366
  end
362
367
  end
363
368
  end
@@ -372,11 +377,9 @@ module ActiveRecord
372
377
  end
373
378
  end
374
379
 
375
- def create_scope
376
- scope.scope_for_create.stringify_keys
377
- end
378
-
379
380
  def delete_or_destroy(records, method)
381
+ return if records.empty?
382
+ records = find(records) if records.any? { |record| record.kind_of?(Integer) || record.kind_of?(String) }
380
383
  records = records.flatten
381
384
  records.each { |record| raise_on_type_mismatch!(record) }
382
385
  existing_records = records.reject(&:new_record?)
@@ -430,7 +433,12 @@ module ActiveRecord
430
433
  records.each do |record|
431
434
  raise_on_type_mismatch!(record)
432
435
  add_to_target(record) do
433
- result &&= insert_record(record, true, raise) { @_was_loaded = loaded? } unless owner.new_record?
436
+ unless owner.new_record?
437
+ result &&= insert_record(record, true, raise) {
438
+ @_was_loaded = loaded?
439
+ @association_ids = nil
440
+ }
441
+ end
434
442
  end
435
443
  end
436
444
 
@@ -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,7 @@ 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
34
36
 
35
37
  extensions = association.extensions
36
38
  extend(*extensions) if extensions.any?
@@ -133,8 +135,9 @@ module ActiveRecord
133
135
  # # #<Pet id: 2, name: "Spook", person_id: 1>,
134
136
  # # #<Pet id: 3, name: "Choo-Choo", person_id: 1>
135
137
  # # ]
136
- def find(*args, &block)
137
- @association.find(*args, &block)
138
+ def find(*args)
139
+ return super if block_given?
140
+ @association.find(*args)
138
141
  end
139
142
 
140
143
  ##
@@ -746,10 +749,6 @@ module ActiveRecord
746
749
  # # ]
747
750
 
748
751
  #--
749
- def uniq
750
- load_target.uniq
751
- end
752
-
753
752
  def calculate(operation, column_name)
754
753
  null_scope? ? scope.calculate(operation, column_name) : super
755
754
  end
@@ -989,6 +988,12 @@ module ActiveRecord
989
988
  load_target == other
990
989
  end
991
990
 
991
+ ##
992
+ # :method: to_ary
993
+ #
994
+ # :call-seq:
995
+ # to_ary()
996
+ #
992
997
  # Returns a new array of objects from the collection. If the collection
993
998
  # hasn't been loaded, it fetches the records from the database.
994
999
  #
@@ -1022,10 +1027,6 @@ module ActiveRecord
1022
1027
  # # #<Pet id: 5, name: "Brain", person_id: 1>,
1023
1028
  # # #<Pet id: 6, name: "Boss", person_id: 1>
1024
1029
  # # ]
1025
- def to_ary
1026
- load_target.dup
1027
- end
1028
- alias_method :to_a, :to_ary
1029
1030
 
1030
1031
  def records # :nodoc:
1031
1032
  load_target
@@ -1073,7 +1074,6 @@ module ActiveRecord
1073
1074
  end
1074
1075
 
1075
1076
  # Reloads the collection from the database. Returns +self+.
1076
- # Equivalent to <tt>collection(true)</tt>.
1077
1077
  #
1078
1078
  # class Person < ActiveRecord::Base
1079
1079
  # has_many :pets
@@ -1087,9 +1087,6 @@ module ActiveRecord
1087
1087
  #
1088
1088
  # person.pets.reload # fetches pets from the database
1089
1089
  # # => [#<Pet id: 1, name: "Snoop", group: "dogs", person_id: 1>]
1090
- #
1091
- # person.pets(true) # fetches pets from the database
1092
- # # => [#<Pet id: 1, name: "Snoop", group: "dogs", person_id: 1>]
1093
1090
  def reload
1094
1091
  proxy_association.reload
1095
1092
  reset_scope
@@ -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
@@ -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
  #
@@ -138,21 +133,15 @@ module ActiveRecord
138
133
 
139
134
  scope = through_association.scope
140
135
  scope.where! construct_join_attributes(*records)
136
+ scope = scope.where(through_scope_attributes)
141
137
 
142
138
  case method
143
139
  when :destroy
144
140
  if scope.klass.primary_key
145
- count = scope.destroy_all.length
141
+ count = scope.destroy_all.count(&:destroyed?)
146
142
  else
147
143
  scope.each(&:_run_destroy_callbacks)
148
-
149
- arel = scope.arel
150
-
151
- stmt = Arel::DeleteManager.new
152
- stmt.from scope.klass.arel_table
153
- stmt.wheres = arel.constraints
154
-
155
- count = scope.klass.connection.delete(stmt, "SQL", scope.bound_attributes)
144
+ count = scope.delete_all
156
145
  end
157
146
  when :nullify
158
147
  count = scope.update_all(source_reflection.foreign_key => nil)
@@ -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
 
@@ -58,6 +60,7 @@ module ActiveRecord
58
60
  when :destroy
59
61
  target.destroyed_by_association = reflection
60
62
  target.destroy
63
+ throw(:abort) unless target.destroyed?
61
64
  when :nullify
62
65
  target.update_columns(reflection.foreign_key => nil) if target.persisted?
63
66
  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
@@ -28,7 +29,7 @@ module ActiveRecord
28
29
 
29
30
  if through_record
30
31
  through_record.update(attributes)
31
- elsif owner.new_record?
32
+ elsif owner.new_record? || !save
32
33
  through_proxy.build(attributes)
33
34
  else
34
35
  through_proxy.create(attributes)
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "active_record/associations/join_dependency/join_part"
2
4
 
3
5
  module ActiveRecord
@@ -9,11 +11,12 @@ module ActiveRecord
9
11
 
10
12
  attr_accessor :tables
11
13
 
12
- def initialize(reflection, children)
14
+ def initialize(reflection, children, alias_tracker)
13
15
  super(reflection.klass, children)
14
16
 
15
- @reflection = reflection
16
- @tables = nil
17
+ @alias_tracker = alias_tracker
18
+ @reflection = reflection
19
+ @tables = nil
17
20
  end
18
21
 
19
22
  def match?(other)
@@ -21,11 +24,8 @@ module ActiveRecord
21
24
  super && reflection == other.reflection
22
25
  end
23
26
 
24
- JoinInformation = Struct.new :joins, :binds
25
-
26
27
  def join_constraints(foreign_table, foreign_klass, join_type, tables, chain)
27
28
  joins = []
28
- binds = []
29
29
  tables = tables.reverse
30
30
 
31
31
  # The chain starts with the target table, but we want to end with it here (makes
@@ -34,71 +34,32 @@ module ActiveRecord
34
34
  table = tables.shift
35
35
  klass = reflection.klass
36
36
 
37
- join_keys = reflection.join_keys
38
- key = join_keys.key
39
- foreign_key = join_keys.foreign_key
40
-
41
- constraint = build_constraint(klass, table, key, foreign_table, foreign_key)
42
-
43
- rel = reflection.join_scope(table)
37
+ constraint = reflection.build_join_constraint(table, foreign_table)
44
38
 
45
- if rel && !rel.arel.constraints.empty?
46
- binds += rel.bound_attributes
47
- constraint = constraint.and rel.arel.constraints
48
- end
39
+ joins << table.create_join(table, table.create_on(constraint), join_type)
49
40
 
50
- if reflection.type
51
- value = foreign_klass.base_class.name
52
- column = klass.columns_hash[reflection.type.to_s]
41
+ join_scope = reflection.join_scope(table, foreign_klass)
42
+ arel = join_scope.arel(alias_tracker.aliases)
53
43
 
54
- binds << Relation::QueryAttribute.new(column.name, value, klass.type_for_attribute(column.name))
55
- constraint = constraint.and klass.arel_attribute(reflection.type, table).eq(Arel::Nodes::BindParam.new)
44
+ if arel.constraints.any?
45
+ joins.concat arel.join_sources
46
+ right = joins.last.right
47
+ right.expr = right.expr.and(arel.constraints)
56
48
  end
57
49
 
58
- joins << table.create_join(table, table.create_on(constraint), join_type)
59
-
60
50
  # The current table in this iteration becomes the foreign table in the next
61
51
  foreign_table, foreign_klass = table, klass
62
52
  end
63
53
 
64
- JoinInformation.new joins, binds
65
- end
66
-
67
- # Builds equality condition.
68
- #
69
- # Example:
70
- #
71
- # class Physician < ActiveRecord::Base
72
- # has_many :appointments
73
- # end
74
- #
75
- # If I execute `Physician.joins(:appointments).to_a` then
76
- # klass # => Physician
77
- # table # => #<Arel::Table @name="appointments" ...>
78
- # key # => physician_id
79
- # foreign_table # => #<Arel::Table @name="physicians" ...>
80
- # foreign_key # => id
81
- #
82
- def build_constraint(klass, table, key, foreign_table, foreign_key)
83
- constraint = table[key].eq(foreign_table[foreign_key])
84
-
85
- if klass.finder_needs_type_condition?
86
- constraint = table.create_and([
87
- constraint,
88
- klass.send(:type_condition, table)
89
- ])
90
- end
91
-
92
- constraint
54
+ joins
93
55
  end
94
56
 
95
57
  def table
96
58
  tables.first
97
59
  end
98
60
 
99
- def aliased_table_name
100
- table.table_alias || table.name
101
- end
61
+ protected
62
+ attr_reader :alias_tracker
102
63
  end
103
64
  end
104
65
  end
@@ -1,20 +1,21 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "active_record/associations/join_dependency/join_part"
2
4
 
3
5
  module ActiveRecord
4
6
  module Associations
5
7
  class JoinDependency # :nodoc:
6
8
  class JoinBase < JoinPart # :nodoc:
7
- def match?(other)
8
- return true if self == other
9
- super && base_klass == other.base_klass
10
- end
9
+ attr_reader :table
11
10
 
12
- def table
13
- base_klass.arel_table
11
+ def initialize(base_klass, table, children)
12
+ super(base_klass, children)
13
+ @table = table
14
14
  end
15
15
 
16
- def aliased_table_name
17
- base_klass.table_name
16
+ def match?(other)
17
+ return true if self == other
18
+ super && base_klass == other.base_klass
18
19
  end
19
20
  end
20
21
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ActiveRecord
2
4
  module Associations
3
5
  class JoinDependency # :nodoc:
@@ -22,10 +24,6 @@ module ActiveRecord
22
24
  @children = children
23
25
  end
24
26
 
25
- def name
26
- reflection.name
27
- end
28
-
29
27
  def match?(other)
30
28
  self.class == other.class
31
29
  end
@@ -40,11 +38,6 @@ module ActiveRecord
40
38
  raise NotImplementedError
41
39
  end
42
40
 
43
- # The alias for the active_record's table
44
- def aliased_table_name
45
- raise NotImplementedError
46
- end
47
-
48
41
  def extract_record(row, column_names_with_alias)
49
42
  # This code is performance critical as it is called per row.
50
43
  # see: https://github.com/rails/rails/pull/12185