activerecord 4.2.11.3 → 5.0.0.beta1

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 (229) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG.md +1029 -1349
  3. data/MIT-LICENSE +1 -1
  4. data/README.rdoc +6 -7
  5. data/examples/performance.rb +2 -2
  6. data/lib/active_record.rb +7 -3
  7. data/lib/active_record/aggregations.rb +35 -25
  8. data/lib/active_record/association_relation.rb +2 -2
  9. data/lib/active_record/associations.rb +305 -204
  10. data/lib/active_record/associations/alias_tracker.rb +19 -16
  11. data/lib/active_record/associations/association.rb +10 -8
  12. data/lib/active_record/associations/association_scope.rb +73 -102
  13. data/lib/active_record/associations/belongs_to_association.rb +20 -32
  14. data/lib/active_record/associations/builder/association.rb +28 -34
  15. data/lib/active_record/associations/builder/belongs_to.rb +41 -18
  16. data/lib/active_record/associations/builder/collection_association.rb +8 -24
  17. data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +11 -11
  18. data/lib/active_record/associations/builder/has_many.rb +4 -4
  19. data/lib/active_record/associations/builder/has_one.rb +10 -5
  20. data/lib/active_record/associations/builder/singular_association.rb +2 -9
  21. data/lib/active_record/associations/collection_association.rb +40 -43
  22. data/lib/active_record/associations/collection_proxy.rb +55 -29
  23. data/lib/active_record/associations/foreign_association.rb +1 -1
  24. data/lib/active_record/associations/has_many_association.rb +20 -71
  25. data/lib/active_record/associations/has_many_through_association.rb +8 -52
  26. data/lib/active_record/associations/has_one_association.rb +12 -5
  27. data/lib/active_record/associations/join_dependency.rb +28 -18
  28. data/lib/active_record/associations/join_dependency/join_association.rb +13 -12
  29. data/lib/active_record/associations/preloader.rb +13 -4
  30. data/lib/active_record/associations/preloader/association.rb +45 -51
  31. data/lib/active_record/associations/preloader/collection_association.rb +0 -6
  32. data/lib/active_record/associations/preloader/has_many_through.rb +1 -1
  33. data/lib/active_record/associations/preloader/has_one.rb +0 -8
  34. data/lib/active_record/associations/preloader/through_association.rb +5 -4
  35. data/lib/active_record/associations/singular_association.rb +6 -0
  36. data/lib/active_record/associations/through_association.rb +11 -3
  37. data/lib/active_record/attribute.rb +61 -17
  38. data/lib/active_record/attribute/user_provided_default.rb +23 -0
  39. data/lib/active_record/attribute_assignment.rb +27 -140
  40. data/lib/active_record/attribute_decorators.rb +6 -5
  41. data/lib/active_record/attribute_methods.rb +79 -26
  42. data/lib/active_record/attribute_methods/before_type_cast.rb +1 -1
  43. data/lib/active_record/attribute_methods/dirty.rb +46 -86
  44. data/lib/active_record/attribute_methods/primary_key.rb +2 -2
  45. data/lib/active_record/attribute_methods/query.rb +2 -2
  46. data/lib/active_record/attribute_methods/read.rb +26 -42
  47. data/lib/active_record/attribute_methods/serialization.rb +13 -16
  48. data/lib/active_record/attribute_methods/time_zone_conversion.rb +42 -9
  49. data/lib/active_record/attribute_methods/write.rb +13 -24
  50. data/lib/active_record/attribute_mutation_tracker.rb +70 -0
  51. data/lib/active_record/attribute_set.rb +30 -3
  52. data/lib/active_record/attribute_set/builder.rb +6 -4
  53. data/lib/active_record/attributes.rb +194 -81
  54. data/lib/active_record/autosave_association.rb +33 -15
  55. data/lib/active_record/base.rb +30 -18
  56. data/lib/active_record/callbacks.rb +36 -40
  57. data/lib/active_record/coders/yaml_column.rb +20 -8
  58. data/lib/active_record/collection_cache_key.rb +31 -0
  59. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +431 -122
  60. data/lib/active_record/connection_adapters/abstract/database_limits.rb +3 -3
  61. data/lib/active_record/connection_adapters/abstract/database_statements.rb +40 -22
  62. data/lib/active_record/connection_adapters/abstract/quoting.rb +62 -8
  63. data/lib/active_record/connection_adapters/abstract/schema_creation.rb +46 -38
  64. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +229 -185
  65. data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +52 -13
  66. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +275 -115
  67. data/lib/active_record/connection_adapters/abstract/transaction.rb +32 -33
  68. data/lib/active_record/connection_adapters/abstract_adapter.rb +83 -32
  69. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +384 -221
  70. data/lib/active_record/connection_adapters/column.rb +27 -41
  71. data/lib/active_record/connection_adapters/connection_specification.rb +2 -21
  72. data/lib/active_record/connection_adapters/determine_if_preparable_visitor.rb +22 -0
  73. data/lib/active_record/connection_adapters/mysql/schema_creation.rb +57 -0
  74. data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +69 -0
  75. data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +59 -0
  76. data/lib/active_record/connection_adapters/mysql2_adapter.rb +22 -101
  77. data/lib/active_record/connection_adapters/postgresql/column.rb +6 -10
  78. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +3 -3
  79. data/lib/active_record/connection_adapters/postgresql/oid.rb +1 -6
  80. data/lib/active_record/connection_adapters/postgresql/oid/array.rb +23 -57
  81. data/lib/active_record/connection_adapters/postgresql/oid/bit.rb +2 -2
  82. data/lib/active_record/connection_adapters/postgresql/oid/bytea.rb +1 -1
  83. data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +1 -1
  84. data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +7 -22
  85. data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +3 -3
  86. data/lib/active_record/connection_adapters/postgresql/oid/json.rb +1 -26
  87. data/lib/active_record/connection_adapters/postgresql/oid/jsonb.rb +2 -2
  88. data/lib/active_record/connection_adapters/postgresql/oid/money.rb +0 -2
  89. data/lib/active_record/connection_adapters/postgresql/oid/point.rb +4 -4
  90. data/lib/active_record/connection_adapters/postgresql/oid/rails_5_1_point.rb +50 -0
  91. data/lib/active_record/connection_adapters/postgresql/oid/range.rb +23 -16
  92. data/lib/active_record/connection_adapters/postgresql/oid/specialized_string.rb +0 -4
  93. data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +2 -2
  94. data/lib/active_record/connection_adapters/postgresql/oid/vector.rb +1 -1
  95. data/lib/active_record/connection_adapters/postgresql/oid/xml.rb +1 -1
  96. data/lib/active_record/connection_adapters/postgresql/quoting.rb +18 -11
  97. data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +29 -10
  98. data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +107 -79
  99. data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +54 -0
  100. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +174 -128
  101. data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +35 -0
  102. data/lib/active_record/connection_adapters/postgresql_adapter.rb +184 -112
  103. data/lib/active_record/connection_adapters/schema_cache.rb +36 -23
  104. data/lib/active_record/connection_adapters/sql_type_metadata.rb +32 -0
  105. data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +15 -0
  106. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +134 -110
  107. data/lib/active_record/connection_adapters/statement_pool.rb +28 -11
  108. data/lib/active_record/connection_handling.rb +5 -5
  109. data/lib/active_record/core.rb +72 -104
  110. data/lib/active_record/counter_cache.rb +9 -20
  111. data/lib/active_record/dynamic_matchers.rb +1 -20
  112. data/lib/active_record/enum.rb +110 -76
  113. data/lib/active_record/errors.rb +72 -47
  114. data/lib/active_record/explain_registry.rb +1 -1
  115. data/lib/active_record/explain_subscriber.rb +1 -1
  116. data/lib/active_record/fixture_set/file.rb +19 -4
  117. data/lib/active_record/fixtures.rb +76 -40
  118. data/lib/active_record/gem_version.rb +4 -4
  119. data/lib/active_record/inheritance.rb +27 -40
  120. data/lib/active_record/integration.rb +4 -4
  121. data/lib/active_record/legacy_yaml_adapter.rb +18 -2
  122. data/lib/active_record/locale/en.yml +3 -2
  123. data/lib/active_record/locking/optimistic.rb +10 -14
  124. data/lib/active_record/locking/pessimistic.rb +1 -1
  125. data/lib/active_record/log_subscriber.rb +40 -22
  126. data/lib/active_record/migration.rb +304 -133
  127. data/lib/active_record/migration/command_recorder.rb +59 -18
  128. data/lib/active_record/migration/compatibility.rb +90 -0
  129. data/lib/active_record/model_schema.rb +92 -40
  130. data/lib/active_record/nested_attributes.rb +45 -34
  131. data/lib/active_record/null_relation.rb +15 -7
  132. data/lib/active_record/persistence.rb +112 -72
  133. data/lib/active_record/querying.rb +6 -5
  134. data/lib/active_record/railtie.rb +20 -13
  135. data/lib/active_record/railties/controller_runtime.rb +1 -1
  136. data/lib/active_record/railties/databases.rake +47 -38
  137. data/lib/active_record/readonly_attributes.rb +1 -1
  138. data/lib/active_record/reflection.rb +182 -57
  139. data/lib/active_record/relation.rb +152 -100
  140. data/lib/active_record/relation/batches.rb +133 -33
  141. data/lib/active_record/relation/batches/batch_enumerator.rb +67 -0
  142. data/lib/active_record/relation/calculations.rb +80 -101
  143. data/lib/active_record/relation/delegation.rb +6 -19
  144. data/lib/active_record/relation/finder_methods.rb +58 -46
  145. data/lib/active_record/relation/from_clause.rb +32 -0
  146. data/lib/active_record/relation/merger.rb +13 -42
  147. data/lib/active_record/relation/predicate_builder.rb +99 -105
  148. data/lib/active_record/relation/predicate_builder/array_handler.rb +11 -16
  149. data/lib/active_record/relation/predicate_builder/association_query_handler.rb +78 -0
  150. data/lib/active_record/relation/predicate_builder/base_handler.rb +17 -0
  151. data/lib/active_record/relation/predicate_builder/basic_object_handler.rb +17 -0
  152. data/lib/active_record/relation/predicate_builder/class_handler.rb +27 -0
  153. data/lib/active_record/relation/predicate_builder/range_handler.rb +17 -0
  154. data/lib/active_record/relation/query_attribute.rb +19 -0
  155. data/lib/active_record/relation/query_methods.rb +274 -238
  156. data/lib/active_record/relation/record_fetch_warning.rb +51 -0
  157. data/lib/active_record/relation/spawn_methods.rb +3 -6
  158. data/lib/active_record/relation/where_clause.rb +173 -0
  159. data/lib/active_record/relation/where_clause_factory.rb +37 -0
  160. data/lib/active_record/result.rb +4 -3
  161. data/lib/active_record/runtime_registry.rb +1 -1
  162. data/lib/active_record/sanitization.rb +94 -65
  163. data/lib/active_record/schema.rb +23 -22
  164. data/lib/active_record/schema_dumper.rb +33 -22
  165. data/lib/active_record/schema_migration.rb +10 -4
  166. data/lib/active_record/scoping.rb +17 -6
  167. data/lib/active_record/scoping/default.rb +19 -6
  168. data/lib/active_record/scoping/named.rb +39 -28
  169. data/lib/active_record/secure_token.rb +38 -0
  170. data/lib/active_record/serialization.rb +2 -4
  171. data/lib/active_record/statement_cache.rb +15 -13
  172. data/lib/active_record/store.rb +8 -3
  173. data/lib/active_record/suppressor.rb +54 -0
  174. data/lib/active_record/table_metadata.rb +64 -0
  175. data/lib/active_record/tasks/database_tasks.rb +30 -40
  176. data/lib/active_record/tasks/mysql_database_tasks.rb +7 -15
  177. data/lib/active_record/tasks/postgresql_database_tasks.rb +11 -2
  178. data/lib/active_record/tasks/sqlite_database_tasks.rb +5 -1
  179. data/lib/active_record/timestamp.rb +16 -9
  180. data/lib/active_record/touch_later.rb +58 -0
  181. data/lib/active_record/transactions.rb +138 -56
  182. data/lib/active_record/type.rb +66 -17
  183. data/lib/active_record/type/adapter_specific_registry.rb +130 -0
  184. data/lib/active_record/type/date.rb +2 -45
  185. data/lib/active_record/type/date_time.rb +2 -49
  186. data/lib/active_record/type/internal/abstract_json.rb +33 -0
  187. data/lib/active_record/type/internal/timezone.rb +15 -0
  188. data/lib/active_record/type/serialized.rb +9 -14
  189. data/lib/active_record/type/time.rb +3 -21
  190. data/lib/active_record/type/type_map.rb +4 -4
  191. data/lib/active_record/type_caster.rb +7 -0
  192. data/lib/active_record/type_caster/connection.rb +29 -0
  193. data/lib/active_record/type_caster/map.rb +19 -0
  194. data/lib/active_record/validations.rb +33 -32
  195. data/lib/active_record/validations/absence.rb +24 -0
  196. data/lib/active_record/validations/associated.rb +10 -3
  197. data/lib/active_record/validations/length.rb +36 -0
  198. data/lib/active_record/validations/presence.rb +12 -12
  199. data/lib/active_record/validations/uniqueness.rb +24 -21
  200. data/lib/rails/generators/active_record/migration.rb +7 -0
  201. data/lib/rails/generators/active_record/migration/migration_generator.rb +7 -4
  202. data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb +8 -3
  203. data/lib/rails/generators/active_record/migration/templates/migration.rb +4 -1
  204. data/lib/rails/generators/active_record/model/model_generator.rb +21 -15
  205. data/lib/rails/generators/active_record/model/templates/model.rb +3 -0
  206. metadata +50 -35
  207. data/lib/active_record/connection_adapters/mysql_adapter.rb +0 -498
  208. data/lib/active_record/connection_adapters/postgresql/array_parser.rb +0 -93
  209. data/lib/active_record/connection_adapters/postgresql/oid/date.rb +0 -11
  210. data/lib/active_record/connection_adapters/postgresql/oid/float.rb +0 -21
  211. data/lib/active_record/connection_adapters/postgresql/oid/infinity.rb +0 -13
  212. data/lib/active_record/connection_adapters/postgresql/oid/integer.rb +0 -11
  213. data/lib/active_record/connection_adapters/postgresql/oid/time.rb +0 -11
  214. data/lib/active_record/serializers/xml_serializer.rb +0 -193
  215. data/lib/active_record/type/big_integer.rb +0 -13
  216. data/lib/active_record/type/binary.rb +0 -50
  217. data/lib/active_record/type/boolean.rb +0 -31
  218. data/lib/active_record/type/decimal.rb +0 -64
  219. data/lib/active_record/type/decimal_without_scale.rb +0 -11
  220. data/lib/active_record/type/decorator.rb +0 -14
  221. data/lib/active_record/type/float.rb +0 -19
  222. data/lib/active_record/type/integer.rb +0 -59
  223. data/lib/active_record/type/mutable.rb +0 -16
  224. data/lib/active_record/type/numeric.rb +0 -36
  225. data/lib/active_record/type/string.rb +0 -40
  226. data/lib/active_record/type/text.rb +0 -11
  227. data/lib/active_record/type/time_value.rb +0 -38
  228. data/lib/active_record/type/unsigned_integer.rb +0 -15
  229. data/lib/active_record/type/value.rb +0 -110
@@ -33,7 +33,7 @@ module ActiveRecord
33
33
 
34
34
  def initialize(klass, association) #:nodoc:
35
35
  @association = association
36
- super klass, klass.arel_table
36
+ super klass, klass.arel_table, klass.predicate_builder
37
37
  merge! association.scope(nullify: false)
38
38
  end
39
39
 
@@ -112,7 +112,7 @@ module ActiveRecord
112
112
  end
113
113
 
114
114
  # Finds an object in the collection responding to the +id+. Uses the same
115
- # rules as <tt>ActiveRecord::Base.find</tt>. Returns <tt>ActiveRecord::RecordNotFound</tt>
115
+ # rules as ActiveRecord::Base.find. Returns ActiveRecord::RecordNotFound
116
116
  # error if the object cannot be found.
117
117
  #
118
118
  # class Person < ActiveRecord::Base
@@ -127,7 +127,7 @@ module ActiveRecord
127
127
  # # ]
128
128
  #
129
129
  # person.pets.find(1) # => #<Pet id: 1, name: "Fancy-Fancy", person_id: 1>
130
- # person.pets.find(4) # => ActiveRecord::RecordNotFound: Couldn't find Pet with id=4
130
+ # person.pets.find(4) # => ActiveRecord::RecordNotFound: Couldn't find Pet with 'id'=4
131
131
  #
132
132
  # person.pets.find(2) { |pet| pet.name.downcase! }
133
133
  # # => #<Pet id: 2, name: "fancy-fancy", person_id: 1>
@@ -171,27 +171,27 @@ module ActiveRecord
171
171
  @association.first(*args)
172
172
  end
173
173
 
174
- # Same as +first+ except returns only the second record.
174
+ # Same as #first except returns only the second record.
175
175
  def second(*args)
176
176
  @association.second(*args)
177
177
  end
178
178
 
179
- # Same as +first+ except returns only the third record.
179
+ # Same as #first except returns only the third record.
180
180
  def third(*args)
181
181
  @association.third(*args)
182
182
  end
183
183
 
184
- # Same as +first+ except returns only the fourth record.
184
+ # Same as #first except returns only the fourth record.
185
185
  def fourth(*args)
186
186
  @association.fourth(*args)
187
187
  end
188
188
 
189
- # Same as +first+ except returns only the fifth record.
189
+ # Same as #first except returns only the fifth record.
190
190
  def fifth(*args)
191
191
  @association.fifth(*args)
192
192
  end
193
193
 
194
- # Same as +first+ except returns only the forty second record.
194
+ # Same as #first except returns only the forty second record.
195
195
  # Also known as accessing "the reddit".
196
196
  def forty_two(*args)
197
197
  @association.forty_two(*args)
@@ -227,6 +227,31 @@ module ActiveRecord
227
227
  @association.last(*args)
228
228
  end
229
229
 
230
+ # Gives a record (or N records if a parameter is supplied) from the collection
231
+ # using the same rules as <tt>ActiveRecord::Base.take</tt>.
232
+ #
233
+ # class Person < ActiveRecord::Base
234
+ # has_many :pets
235
+ # end
236
+ #
237
+ # person.pets
238
+ # # => [
239
+ # # #<Pet id: 1, name: "Fancy-Fancy", person_id: 1>,
240
+ # # #<Pet id: 2, name: "Spook", person_id: 1>,
241
+ # # #<Pet id: 3, name: "Choo-Choo", person_id: 1>
242
+ # # ]
243
+ #
244
+ # person.pets.take # => #<Pet id: 1, name: "Fancy-Fancy", person_id: 1>
245
+ #
246
+ # person.pets.take(2)
247
+ # # => [
248
+ # # #<Pet id: 1, name: "Fancy-Fancy", person_id: 1>,
249
+ # # #<Pet id: 2, name: "Spook", person_id: 1>
250
+ # # ]
251
+ #
252
+ # another_person_without.pets # => []
253
+ # another_person_without.pets.take # => nil
254
+ # another_person_without.pets.take(2) # => []
230
255
  def take(n = nil)
231
256
  @association.take(n)
232
257
  end
@@ -290,7 +315,7 @@ module ActiveRecord
290
315
  @association.create(attributes, &block)
291
316
  end
292
317
 
293
- # Like +create+, except that if the record is invalid, raises an exception.
318
+ # Like #create, except that if the record is invalid, raises an exception.
294
319
  #
295
320
  # class Person
296
321
  # has_many :pets
@@ -307,8 +332,8 @@ module ActiveRecord
307
332
  end
308
333
 
309
334
  # Add one or more records to the collection by setting their foreign keys
310
- # to the association's primary key. Since << flattens its argument list and
311
- # inserts each record, +push+ and +concat+ behave identically. Returns +self+
335
+ # to the association's primary key. Since #<< flattens its argument list and
336
+ # inserts each record, +push+ and #concat behave identically. Returns +self+
312
337
  # so method calls may be chained.
313
338
  #
314
339
  # class Person < ActiveRecord::Base
@@ -364,7 +389,7 @@ module ActiveRecord
364
389
  # specified by the +:dependent+ option. If no +:dependent+ option is given,
365
390
  # then it will follow the default strategy.
366
391
  #
367
- # For +has_many :through+ associations, the default deletion strategy is
392
+ # For <tt>has_many :through</tt> associations, the default deletion strategy is
368
393
  # +:delete_all+.
369
394
  #
370
395
  # For +has_many+ associations, the default deletion strategy is +:nullify+.
@@ -399,7 +424,7 @@ module ActiveRecord
399
424
  # # #<Pet id: 3, name: "Choo-Choo", person_id: nil>
400
425
  # # ]
401
426
  #
402
- # Both +has_many+ and +has_many :through+ dependencies default to the
427
+ # Both +has_many+ and <tt>has_many :through</tt> dependencies default to the
403
428
  # +:delete_all+ strategy if the +:dependent+ option is set to +:destroy+.
404
429
  # Records are not instantiated and callbacks will not be fired.
405
430
  #
@@ -418,7 +443,7 @@ module ActiveRecord
418
443
  # person.pets.delete_all
419
444
  #
420
445
  # Pet.find(1, 2, 3)
421
- # # => ActiveRecord::RecordNotFound
446
+ # # => ActiveRecord::RecordNotFound: Couldn't find all Pets with 'id': (1, 2, 3)
422
447
  #
423
448
  # If it is set to <tt>:delete_all</tt>, all the objects are deleted
424
449
  # *without* calling their +destroy+ method.
@@ -438,7 +463,7 @@ module ActiveRecord
438
463
  # person.pets.delete_all
439
464
  #
440
465
  # Pet.find(1, 2, 3)
441
- # # => ActiveRecord::RecordNotFound
466
+ # # => ActiveRecord::RecordNotFound: Couldn't find all Pets with 'id': (1, 2, 3)
442
467
  def delete_all(dependent = nil)
443
468
  @association.delete_all(dependent)
444
469
  end
@@ -475,7 +500,7 @@ module ActiveRecord
475
500
  # then it will follow the default strategy. Returns an array with the
476
501
  # deleted records.
477
502
  #
478
- # For +has_many :through+ associations, the default deletion strategy is
503
+ # For <tt>has_many :through</tt> associations, the default deletion strategy is
479
504
  # +:delete_all+.
480
505
  #
481
506
  # For +has_many+ associations, the default deletion strategy is +:nullify+.
@@ -532,7 +557,7 @@ module ActiveRecord
532
557
  # # => [#<Pet id: 2, name: "Spook", person_id: 1>]
533
558
  #
534
559
  # Pet.find(1, 3)
535
- # # => ActiveRecord::RecordNotFound: Couldn't find all Pets with IDs (1, 3)
560
+ # # => ActiveRecord::RecordNotFound: Couldn't find all Pets with 'id': (1, 3)
536
561
  #
537
562
  # If it is set to <tt>:delete_all</tt>, all the +records+ are deleted
538
563
  # *without* calling their +destroy+ method.
@@ -560,9 +585,9 @@ module ActiveRecord
560
585
  # # ]
561
586
  #
562
587
  # Pet.find(1)
563
- # # => ActiveRecord::RecordNotFound: Couldn't find Pet with id=1
588
+ # # => ActiveRecord::RecordNotFound: Couldn't find Pet with 'id'=1
564
589
  #
565
- # You can pass +Integer+ or +String+ values, it finds the records
590
+ # You can pass +Fixnum+ or +String+ values, it finds the records
566
591
  # responding to the +id+ and executes delete on them.
567
592
  #
568
593
  # class Person < ActiveRecord::Base
@@ -624,9 +649,9 @@ module ActiveRecord
624
649
  # person.pets.size # => 0
625
650
  # person.pets # => []
626
651
  #
627
- # Pet.find(1, 2, 3) # => ActiveRecord::RecordNotFound: Couldn't find all Pets with IDs (1, 2, 3)
652
+ # Pet.find(1, 2, 3) # => ActiveRecord::RecordNotFound: Couldn't find all Pets with 'id': (1, 2, 3)
628
653
  #
629
- # You can pass +Integer+ or +String+ values, it finds the records
654
+ # You can pass +Fixnum+ or +String+ values, it finds the records
630
655
  # responding to the +id+ and then deletes them from the database.
631
656
  #
632
657
  # person.pets.size # => 3
@@ -656,7 +681,7 @@ module ActiveRecord
656
681
  # person.pets.size # => 0
657
682
  # person.pets # => []
658
683
  #
659
- # Pet.find(4, 5, 6) # => ActiveRecord::RecordNotFound: Couldn't find all Pets with IDs (4, 5, 6)
684
+ # Pet.find(4, 5, 6) # => ActiveRecord::RecordNotFound: Couldn't find all Pets with 'id': (4, 5, 6)
660
685
  def destroy(*records)
661
686
  @association.destroy(*records)
662
687
  end
@@ -693,10 +718,8 @@ module ActiveRecord
693
718
  # # #<Pet id: 2, name: "Spook", person_id: 1>,
694
719
  # # #<Pet id: 3, name: "Choo-Choo", person_id: 1>
695
720
  # # ]
696
- def count(column_name = nil, options = {})
697
- # TODO: Remove options argument as soon we remove support to
698
- # activerecord-deprecated_finders.
699
- @association.count(column_name, options)
721
+ def count(column_name = nil)
722
+ @association.count(column_name)
700
723
  end
701
724
 
702
725
  # Returns the size of the collection. If the collection hasn't been loaded,
@@ -783,7 +806,7 @@ module ActiveRecord
783
806
  # person.pets.any? # => false
784
807
  #
785
808
  # person.pets << Pet.new(name: 'Snoop')
786
- # person.pets.count # => 0
809
+ # person.pets.count # => 1
787
810
  # person.pets.any? # => true
788
811
  #
789
812
  # You can also pass a +block+ to define criteria. The behavior
@@ -858,7 +881,7 @@ module ActiveRecord
858
881
  !!@association.include?(record)
859
882
  end
860
883
 
861
- def arel
884
+ def arel #:nodoc:
862
885
  scope.arel
863
886
  end
864
887
 
@@ -973,12 +996,15 @@ module ActiveRecord
973
996
  alias_method :append, :<<
974
997
 
975
998
  def prepend(*args)
976
- raise NoMethodError, "prepend on association is not defined. Please use << or append"
999
+ raise NoMethodError, "prepend on association is not defined. Please use <<, push or append"
977
1000
  end
978
1001
 
979
1002
  # Equivalent to +delete_all+. The difference is that returns +self+, instead
980
1003
  # of an array with the deleted objects, so methods can be chained. See
981
1004
  # +delete_all+ for more information.
1005
+ # Note that because +delete_all+ removes records by directly
1006
+ # running an SQL query into the database, the +updated_at+ column of
1007
+ # the object is not changed.
982
1008
  def clear
983
1009
  delete_all
984
1010
  self
@@ -1,5 +1,5 @@
1
1
  module ActiveRecord::Associations
2
- module ForeignAssociation
2
+ module ForeignAssociation # :nodoc:
3
3
  def foreign_key_present?
4
4
  if reflection.klass.primary_key
5
5
  owner.attribute_present?(reflection.active_record_primary_key)
@@ -15,9 +15,16 @@ module ActiveRecord
15
15
 
16
16
  when :restrict_with_error
17
17
  unless empty?
18
- record = klass.human_attribute_name(reflection.name).downcase
19
- owner.errors.add(:base, :"restrict_dependent_destroy.many", record: record)
20
- false
18
+ record = owner.class.human_attribute_name(reflection.name).downcase
19
+ message = owner.errors.generate_message(:base, :'restrict_dependent_destroy.many', record: record, raise: true) rescue nil
20
+ if message
21
+ ActiveSupport::Deprecation.warn(<<-MESSAGE.squish)
22
+ The error key `:'restrict_dependent_destroy.many'` has been deprecated and will be removed in Rails 5.1.
23
+ Please use `:'restrict_dependent_destroy.has_many'` instead.
24
+ MESSAGE
25
+ end
26
+ owner.errors.add(:base, message || :'restrict_dependent_destroy.has_many', record: record)
27
+ throw(:abort)
21
28
  end
22
29
 
23
30
  else
@@ -43,7 +50,7 @@ module ActiveRecord
43
50
  end
44
51
 
45
52
  def empty?
46
- if has_cached_counter?
53
+ if reflection.has_cached_counter?
47
54
  size.zero?
48
55
  else
49
56
  super
@@ -66,8 +73,8 @@ module ActiveRecord
66
73
  # If the collection is empty the target is set to an empty array and
67
74
  # the loaded flag is set to true as well.
68
75
  def count_records
69
- count = if has_cached_counter?
70
- owner._read_attribute cached_counter_attribute_name
76
+ count = if reflection.has_cached_counter?
77
+ owner._read_attribute reflection.counter_cache_column
71
78
  else
72
79
  scope.count
73
80
  end
@@ -80,78 +87,20 @@ module ActiveRecord
80
87
  [association_scope.limit_value, count].compact.min
81
88
  end
82
89
 
83
-
84
- # Returns whether a counter cache should be used for this association.
85
- #
86
- # The counter_cache option must be given on either the owner or inverse
87
- # association, and the column must be present on the owner.
88
- def has_cached_counter?(reflection = reflection())
89
- if reflection.options[:counter_cache] || (inverse = inverse_which_updates_counter_cache(reflection)) && inverse.options[:counter_cache]
90
- owner.attribute_present?(cached_counter_attribute_name(reflection))
91
- end
92
- end
93
-
94
- def cached_counter_attribute_name(reflection = reflection())
95
- if reflection.options[:counter_cache]
96
- reflection.options[:counter_cache].to_s
97
- else
98
- "#{reflection.name}_count"
99
- end
100
- end
101
-
102
90
  def update_counter(difference, reflection = reflection())
103
- update_counter_in_database(difference, reflection)
104
- update_counter_in_memory(difference, reflection)
105
- end
106
-
107
- def update_counter_in_database(difference, reflection = reflection())
108
- if has_cached_counter?(reflection)
109
- counter = cached_counter_attribute_name(reflection)
110
- owner.class.update_counters(owner.id, counter => difference)
91
+ if reflection.has_cached_counter?
92
+ owner.increment!(reflection.counter_cache_column, difference)
111
93
  end
112
94
  end
113
95
 
114
96
  def update_counter_in_memory(difference, reflection = reflection())
115
- if counter_must_be_updated_by_has_many?(reflection)
116
- counter = cached_counter_attribute_name(reflection)
117
- owner[counter] += difference
118
- owner.send(:clear_attribute_changes, counter) # eww
97
+ if reflection.counter_must_be_updated_by_has_many?
98
+ counter = reflection.counter_cache_column
99
+ owner.increment(counter, difference)
100
+ owner.send(:clear_attribute_change, counter) # eww
119
101
  end
120
102
  end
121
103
 
122
- # This shit is nasty. We need to avoid the following situation:
123
- #
124
- # * An associated record is deleted via record.destroy
125
- # * Hence the callbacks run, and they find a belongs_to on the record with a
126
- # :counter_cache options which points back at our owner. So they update the
127
- # counter cache.
128
- # * In which case, we must make sure to *not* update the counter cache, or else
129
- # it will be decremented twice.
130
- #
131
- # Hence this method.
132
- def inverse_which_updates_counter_cache(reflection = reflection())
133
- counter_name = cached_counter_attribute_name(reflection)
134
- inverse_which_updates_counter_named(counter_name, reflection)
135
- end
136
- alias inverse_updates_counter_cache? inverse_which_updates_counter_cache
137
-
138
- def inverse_which_updates_counter_named(counter_name, reflection)
139
- reflection.klass._reflections.values.find { |inverse_reflection|
140
- inverse_reflection.belongs_to? &&
141
- inverse_reflection.counter_cache_column == counter_name
142
- }
143
- end
144
- alias inverse_updates_counter_named? inverse_which_updates_counter_named
145
-
146
- def inverse_updates_counter_in_memory?(reflection)
147
- inverse = inverse_which_updates_counter_cache(reflection)
148
- inverse && inverse == reflection.inverse_of
149
- end
150
-
151
- def counter_must_be_updated_by_has_many?(reflection)
152
- !inverse_updates_counter_in_memory?(reflection) && has_cached_counter?(reflection)
153
- end
154
-
155
104
  def delete_count(method, scope)
156
105
  if method == :delete_all
157
106
  scope.delete_all
@@ -169,7 +118,7 @@ module ActiveRecord
169
118
  def delete_records(records, method)
170
119
  if method == :destroy
171
120
  records.each(&:destroy!)
172
- update_counter(-records.length) unless inverse_updates_counter_cache?
121
+ update_counter(-records.length) unless reflection.inverse_updates_counter_cache?
173
122
  else
174
123
  scope = self.scope.where(reflection.klass.primary_key => records)
175
124
  update_counter(-delete_count(method, scope))
@@ -1,5 +1,3 @@
1
- require 'active_support/core_ext/string/filters'
2
-
3
1
  module ActiveRecord
4
2
  # = Active Record Has Many Through Association
5
3
  module Associations
@@ -13,21 +11,6 @@ module ActiveRecord
13
11
  @through_association = nil
14
12
  end
15
13
 
16
- # Returns the size of the collection by executing a SELECT COUNT(*) query
17
- # if the collection hasn't been loaded, and by calling collection.size if
18
- # it has. If the collection will likely have a size greater than zero,
19
- # and if fetching the collection will be needed afterwards, one less
20
- # SELECT query will be generated by using #length instead.
21
- def size
22
- if has_cached_counter?
23
- owner._read_attribute cached_counter_attribute_name(reflection)
24
- elsif loaded?
25
- target.size
26
- else
27
- super
28
- end
29
- end
30
-
31
14
  def concat(*records)
32
15
  unless owner.new_record?
33
16
  records.flatten.each do |record|
@@ -55,25 +38,14 @@ module ActiveRecord
55
38
  def insert_record(record, validate = true, raise = false)
56
39
  ensure_not_nested
57
40
 
58
- if record.new_record?
59
- if raise
60
- record.save!(:validate => validate)
61
- else
62
- return unless record.save(:validate => validate)
63
- end
41
+ if raise
42
+ record.save!(:validate => validate)
43
+ else
44
+ return unless record.save(:validate => validate)
64
45
  end
65
46
 
66
47
  save_through_record(record)
67
- if has_cached_counter? && !through_reflection_updates_counter_cache?
68
- ActiveSupport::Deprecation.warn(<<-MSG.squish)
69
- Automatic updating of counter caches on through associations has been
70
- deprecated, and will be removed in Rails 5. Instead, please set the
71
- appropriate `counter_cache` options on the `has_many` and `belongs_to`
72
- for your associations to #{through_reflection.name}.
73
- MSG
74
48
 
75
- update_counter_in_database(1)
76
- end
77
49
  record
78
50
  end
79
51
 
@@ -94,11 +66,6 @@ module ActiveRecord
94
66
 
95
67
  through_record = through_association.build(*options_for_through_record)
96
68
  through_record.send("#{source_reflection.name}=", record)
97
-
98
- if options[:source_type]
99
- through_record.send("#{source_reflection.foreign_type}=", options[:source_type])
100
- end
101
-
102
69
  through_record
103
70
  end
104
71
  end
@@ -143,7 +110,7 @@ module ActiveRecord
143
110
  def update_through_counter?(method)
144
111
  case method
145
112
  when :destroy
146
- !inverse_updates_counter_cache?(through_reflection)
113
+ !through_reflection.inverse_updates_counter_cache?
147
114
  when :nullify
148
115
  false
149
116
  else
@@ -166,17 +133,15 @@ module ActiveRecord
166
133
  if scope.klass.primary_key
167
134
  count = scope.destroy_all.length
168
135
  else
169
- scope.each do |record|
170
- record._run_destroy_callbacks
171
- end
136
+ scope.each(&:_run_destroy_callbacks)
172
137
 
173
138
  arel = scope.arel
174
139
 
175
- stmt = Arel::DeleteManager.new arel.engine
140
+ stmt = Arel::DeleteManager.new
176
141
  stmt.from scope.klass.arel_table
177
142
  stmt.wheres = arel.constraints
178
143
 
179
- count = scope.klass.connection.delete(stmt, 'SQL', scope.bind_values)
144
+ count = scope.klass.connection.delete(stmt, 'SQL', scope.bound_attributes)
180
145
  end
181
146
  when :nullify
182
147
  count = scope.update_all(source_reflection.foreign_key => nil)
@@ -233,15 +198,6 @@ module ActiveRecord
233
198
  def invertible_for?(record)
234
199
  false
235
200
  end
236
-
237
- def has_cached_counter?(reflection = reflection())
238
- owner.attribute_present?(cached_counter_attribute_name(reflection))
239
- end
240
-
241
- def through_reflection_updates_counter_cache?
242
- counter_name = cached_counter_attribute_name
243
- inverse_updates_counter_named?(counter_name, through_reflection)
244
- end
245
201
  end
246
202
  end
247
203
  end