activerecord 5.1.7 → 5.2.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 (259) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG.md +221 -900
  3. data/README.rdoc +3 -3
  4. data/examples/performance.rb +2 -0
  5. data/examples/simple.rb +2 -0
  6. data/lib/active_record.rb +10 -3
  7. data/lib/active_record/aggregations.rb +2 -0
  8. data/lib/active_record/association_relation.rb +2 -0
  9. data/lib/active_record/associations.rb +13 -42
  10. data/lib/active_record/associations/alias_tracker.rb +17 -17
  11. data/lib/active_record/associations/association.rb +11 -22
  12. data/lib/active_record/associations/association_scope.rb +32 -44
  13. data/lib/active_record/associations/belongs_to_association.rb +6 -4
  14. data/lib/active_record/associations/belongs_to_polymorphic_association.rb +3 -1
  15. data/lib/active_record/associations/builder/association.rb +2 -5
  16. data/lib/active_record/associations/builder/belongs_to.rb +7 -12
  17. data/lib/active_record/associations/builder/collection_association.rb +1 -1
  18. data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +3 -1
  19. data/lib/active_record/associations/builder/has_many.rb +2 -0
  20. data/lib/active_record/associations/builder/has_one.rb +2 -0
  21. data/lib/active_record/associations/builder/singular_association.rb +2 -0
  22. data/lib/active_record/associations/collection_association.rb +41 -33
  23. data/lib/active_record/associations/collection_proxy.rb +11 -14
  24. data/lib/active_record/associations/foreign_association.rb +2 -0
  25. data/lib/active_record/associations/has_many_association.rb +4 -2
  26. data/lib/active_record/associations/has_many_through_association.rb +4 -2
  27. data/lib/active_record/associations/has_one_association.rb +3 -1
  28. data/lib/active_record/associations/has_one_through_association.rb +3 -1
  29. data/lib/active_record/associations/join_dependency.rb +22 -40
  30. data/lib/active_record/associations/join_dependency/join_association.rb +17 -56
  31. data/lib/active_record/associations/join_dependency/join_base.rb +9 -8
  32. data/lib/active_record/associations/join_dependency/join_part.rb +2 -9
  33. data/lib/active_record/associations/preloader.rb +17 -37
  34. data/lib/active_record/associations/preloader/association.rb +42 -58
  35. data/lib/active_record/associations/preloader/through_association.rb +71 -79
  36. data/lib/active_record/associations/singular_association.rb +14 -10
  37. data/lib/active_record/associations/through_association.rb +3 -1
  38. data/lib/active_record/attribute_assignment.rb +2 -0
  39. data/lib/active_record/attribute_decorators.rb +3 -2
  40. data/lib/active_record/attribute_methods.rb +47 -7
  41. data/lib/active_record/attribute_methods/before_type_cast.rb +2 -0
  42. data/lib/active_record/attribute_methods/dirty.rb +25 -214
  43. data/lib/active_record/attribute_methods/primary_key.rb +7 -6
  44. data/lib/active_record/attribute_methods/query.rb +2 -0
  45. data/lib/active_record/attribute_methods/read.rb +8 -2
  46. data/lib/active_record/attribute_methods/serialization.rb +23 -0
  47. data/lib/active_record/attribute_methods/time_zone_conversion.rb +6 -8
  48. data/lib/active_record/attribute_methods/write.rb +21 -9
  49. data/lib/active_record/attributes.rb +7 -6
  50. data/lib/active_record/autosave_association.rb +5 -11
  51. data/lib/active_record/base.rb +2 -0
  52. data/lib/active_record/callbacks.rb +6 -8
  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 +10 -5
  56. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +110 -35
  57. data/lib/active_record/connection_adapters/abstract/database_limits.rb +2 -0
  58. data/lib/active_record/connection_adapters/abstract/database_statements.rb +120 -28
  59. data/lib/active_record/connection_adapters/abstract/query_cache.rb +7 -2
  60. data/lib/active_record/connection_adapters/abstract/quoting.rb +14 -33
  61. data/lib/active_record/connection_adapters/abstract/savepoints.rb +2 -0
  62. data/lib/active_record/connection_adapters/abstract/schema_creation.rb +13 -5
  63. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +40 -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 +103 -63
  66. data/lib/active_record/connection_adapters/abstract/transaction.rb +45 -9
  67. data/lib/active_record/connection_adapters/abstract_adapter.rb +62 -90
  68. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +75 -138
  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 +3 -1
  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 -6
  78. data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +30 -30
  79. data/lib/active_record/connection_adapters/mysql/schema_statements.rb +91 -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.rb +2 -1
  86. data/lib/active_record/connection_adapters/postgresql/oid/array.rb +3 -11
  87. data/lib/active_record/connection_adapters/postgresql/oid/bit.rb +2 -0
  88. data/lib/active_record/connection_adapters/postgresql/oid/bit_varying.rb +2 -0
  89. data/lib/active_record/connection_adapters/postgresql/oid/bytea.rb +2 -0
  90. data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +2 -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 +3 -1
  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 +3 -5
  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/quoting.rb +10 -0
  108. data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +19 -25
  109. data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +2 -0
  110. data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +11 -7
  111. data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +20 -13
  112. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +79 -65
  113. data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +2 -0
  114. data/lib/active_record/connection_adapters/postgresql/utils.rb +2 -0
  115. data/lib/active_record/connection_adapters/postgresql_adapter.rb +47 -82
  116. data/lib/active_record/connection_adapters/schema_cache.rb +2 -0
  117. data/lib/active_record/connection_adapters/sql_type_metadata.rb +2 -0
  118. data/lib/active_record/connection_adapters/sqlite3/explain_pretty_printer.rb +2 -0
  119. data/lib/active_record/connection_adapters/sqlite3/quoting.rb +19 -2
  120. data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +2 -0
  121. data/lib/active_record/connection_adapters/sqlite3/schema_definitions.rb +6 -15
  122. data/lib/active_record/connection_adapters/sqlite3/schema_dumper.rb +3 -2
  123. data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +71 -1
  124. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +34 -89
  125. data/lib/active_record/connection_adapters/statement_pool.rb +2 -0
  126. data/lib/active_record/connection_handling.rb +4 -2
  127. data/lib/active_record/core.rb +27 -57
  128. data/lib/active_record/counter_cache.rb +15 -12
  129. data/lib/active_record/define_callbacks.rb +5 -3
  130. data/lib/active_record/dynamic_matchers.rb +9 -9
  131. data/lib/active_record/enum.rb +15 -13
  132. data/lib/active_record/errors.rb +54 -21
  133. data/lib/active_record/explain.rb +3 -1
  134. data/lib/active_record/explain_registry.rb +2 -0
  135. data/lib/active_record/explain_subscriber.rb +2 -0
  136. data/lib/active_record/fixture_set/file.rb +2 -0
  137. data/lib/active_record/fixtures.rb +40 -24
  138. data/lib/active_record/gem_version.rb +5 -3
  139. data/lib/active_record/inheritance.rb +6 -5
  140. data/lib/active_record/integration.rb +58 -19
  141. data/lib/active_record/internal_metadata.rb +2 -0
  142. data/lib/active_record/legacy_yaml_adapter.rb +3 -1
  143. data/lib/active_record/locking/optimistic.rb +31 -20
  144. data/lib/active_record/locking/pessimistic.rb +10 -7
  145. data/lib/active_record/log_subscriber.rb +2 -0
  146. data/lib/active_record/migration.rb +47 -21
  147. data/lib/active_record/migration/command_recorder.rb +11 -9
  148. data/lib/active_record/migration/compatibility.rb +20 -2
  149. data/lib/active_record/migration/join_table.rb +2 -0
  150. data/lib/active_record/model_schema.rb +29 -38
  151. data/lib/active_record/nested_attributes.rb +18 -6
  152. data/lib/active_record/no_touching.rb +3 -1
  153. data/lib/active_record/null_relation.rb +2 -0
  154. data/lib/active_record/persistence.rb +184 -40
  155. data/lib/active_record/query_cache.rb +17 -12
  156. data/lib/active_record/querying.rb +3 -1
  157. data/lib/active_record/railtie.rb +54 -1
  158. data/lib/active_record/railties/console_sandbox.rb +2 -0
  159. data/lib/active_record/railties/controller_runtime.rb +2 -0
  160. data/lib/active_record/railties/databases.rake +41 -28
  161. data/lib/active_record/readonly_attributes.rb +3 -2
  162. data/lib/active_record/reflection.rb +100 -182
  163. data/lib/active_record/relation.rb +61 -193
  164. data/lib/active_record/relation/batches.rb +20 -5
  165. data/lib/active_record/relation/batches/batch_enumerator.rb +2 -0
  166. data/lib/active_record/relation/calculations.rb +40 -23
  167. data/lib/active_record/relation/delegation.rb +10 -27
  168. data/lib/active_record/relation/finder_methods.rb +53 -49
  169. data/lib/active_record/relation/from_clause.rb +2 -8
  170. data/lib/active_record/relation/merger.rb +22 -19
  171. data/lib/active_record/relation/predicate_builder.rb +42 -79
  172. data/lib/active_record/relation/predicate_builder/array_handler.rb +10 -7
  173. data/lib/active_record/relation/predicate_builder/association_query_value.rb +46 -0
  174. data/lib/active_record/relation/predicate_builder/base_handler.rb +2 -2
  175. data/lib/active_record/relation/predicate_builder/basic_object_handler.rb +12 -1
  176. data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +54 -0
  177. data/lib/active_record/relation/predicate_builder/range_handler.rb +22 -6
  178. data/lib/active_record/relation/predicate_builder/relation_handler.rb +6 -0
  179. data/lib/active_record/relation/query_attribute.rb +9 -2
  180. data/lib/active_record/relation/query_methods.rb +80 -69
  181. data/lib/active_record/relation/record_fetch_warning.rb +2 -0
  182. data/lib/active_record/relation/spawn_methods.rb +2 -0
  183. data/lib/active_record/relation/where_clause.rb +50 -67
  184. data/lib/active_record/relation/where_clause_factory.rb +4 -46
  185. data/lib/active_record/result.rb +2 -0
  186. data/lib/active_record/runtime_registry.rb +2 -0
  187. data/lib/active_record/sanitization.rb +15 -9
  188. data/lib/active_record/schema.rb +3 -1
  189. data/lib/active_record/schema_dumper.rb +24 -23
  190. data/lib/active_record/schema_migration.rb +2 -0
  191. data/lib/active_record/scoping.rb +9 -8
  192. data/lib/active_record/scoping/default.rb +6 -7
  193. data/lib/active_record/scoping/named.rb +15 -7
  194. data/lib/active_record/secure_token.rb +2 -0
  195. data/lib/active_record/serialization.rb +2 -0
  196. data/lib/active_record/statement_cache.rb +22 -12
  197. data/lib/active_record/store.rb +2 -0
  198. data/lib/active_record/suppressor.rb +2 -0
  199. data/lib/active_record/table_metadata.rb +3 -1
  200. data/lib/active_record/tasks/database_tasks.rb +23 -12
  201. data/lib/active_record/tasks/mysql_database_tasks.rb +9 -48
  202. data/lib/active_record/tasks/postgresql_database_tasks.rb +10 -2
  203. data/lib/active_record/tasks/sqlite_database_tasks.rb +25 -3
  204. data/lib/active_record/timestamp.rb +5 -12
  205. data/lib/active_record/touch_later.rb +2 -0
  206. data/lib/active_record/transactions.rb +9 -7
  207. data/lib/active_record/translation.rb +2 -0
  208. data/lib/active_record/type.rb +4 -1
  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_caster.rb +2 -0
  222. data/lib/active_record/type_caster/connection.rb +2 -0
  223. data/lib/active_record/type_caster/map.rb +2 -0
  224. data/lib/active_record/validations.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 +36 -6
  230. data/lib/active_record/version.rb +2 -0
  231. data/lib/rails/generators/active_record.rb +3 -1
  232. data/lib/rails/generators/active_record/application_record/application_record_generator.rb +27 -0
  233. data/lib/rails/generators/active_record/{model/templates/application_record.rb → application_record/templates/application_record.rb.tt} +0 -0
  234. data/lib/rails/generators/active_record/migration.rb +2 -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/model/model_generator.rb +2 -23
  239. data/lib/rails/generators/active_record/model/templates/{model.rb → model.rb.tt} +0 -0
  240. data/lib/rails/generators/active_record/model/templates/{module.rb → module.rb.tt} +0 -0
  241. metadata +25 -38
  242. data/lib/active_record/associations/preloader/belongs_to.rb +0 -15
  243. data/lib/active_record/associations/preloader/collection_association.rb +0 -17
  244. data/lib/active_record/associations/preloader/has_many.rb +0 -15
  245. data/lib/active_record/associations/preloader/has_many_through.rb +0 -19
  246. data/lib/active_record/associations/preloader/has_one.rb +0 -15
  247. data/lib/active_record/associations/preloader/has_one_through.rb +0 -9
  248. data/lib/active_record/associations/preloader/singular_association.rb +0 -18
  249. data/lib/active_record/attribute.rb +0 -240
  250. data/lib/active_record/attribute/user_provided_default.rb +0 -30
  251. data/lib/active_record/attribute_mutation_tracker.rb +0 -122
  252. data/lib/active_record/attribute_set.rb +0 -113
  253. data/lib/active_record/attribute_set/builder.rb +0 -126
  254. data/lib/active_record/attribute_set/yaml_encoder.rb +0 -41
  255. data/lib/active_record/connection_adapters/postgresql/oid/json.rb +0 -10
  256. data/lib/active_record/railties/jdbcmysql_error.rb +0 -16
  257. data/lib/active_record/relation/predicate_builder/association_query_handler.rb +0 -88
  258. data/lib/active_record/relation/predicate_builder/polymorphic_array_handler.rb +0 -59
  259. data/lib/active_record/type/internal/abstract_json.rb +0 -37
@@ -1,6 +1,8 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ActiveRecord
2
- # = Active Record Belongs To Association
3
4
  module Associations
5
+ # = Active Record Belongs To Association
4
6
  class BelongsToAssociation < SingularAssociation #:nodoc:
5
7
  def handle_dependency
6
8
  target.send(options[:dependent]) if load_target
@@ -47,9 +49,9 @@ module ActiveRecord
47
49
  def update_counters(by)
48
50
  if require_counter_update? && foreign_key_present?
49
51
  if target && !stale_target?
50
- target.increment!(reflection.counter_cache_column, by, touch: reflection.options[:touch])
52
+ target.increment!(reflection.counter_cache_column, by)
51
53
  else
52
- klass.update_counters(target_id, reflection.counter_cache_column => by, touch: reflection.options[:touch])
54
+ klass.update_counters(target_id, reflection.counter_cache_column => by)
53
55
  end
54
56
  end
55
57
  end
@@ -65,7 +67,7 @@ module ActiveRecord
65
67
  def update_counters_on_replace(record)
66
68
  if require_counter_update? && different_target?(record)
67
69
  owner.instance_variable_set :@_after_replace_counter_called, true
68
- record.increment!(reflection.counter_cache_column, touch: reflection.options[:touch])
70
+ record.increment!(reflection.counter_cache_column)
69
71
  decrement_counters
70
72
  end
71
73
  end
@@ -1,6 +1,8 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ActiveRecord
2
- # = Active Record Belongs To Polymorphic Association
3
4
  module Associations
5
+ # = Active Record Belongs To Polymorphic Association
4
6
  class BelongsToPolymorphicAssociation < BelongsToAssociation #:nodoc:
5
7
  def klass
6
8
  type = owner[reflection.foreign_type]
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  # This is the parent Association class which defines the variables
2
4
  # used by all associations.
3
5
  #
@@ -36,11 +38,6 @@ module ActiveRecord::Associations::Builder # :nodoc:
36
38
  def self.create_reflection(model, name, scope, options, extension = nil)
37
39
  raise ArgumentError, "association names must be a Symbol" unless name.kind_of?(Symbol)
38
40
 
39
- if scope.is_a?(Hash)
40
- options = scope
41
- scope = nil
42
- end
43
-
44
41
  validate_options(options)
45
42
 
46
43
  scope = build_scope(scope, extension)
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ActiveRecord::Associations::Builder # :nodoc:
2
4
  class BelongsTo < SingularAssociation #:nodoc:
3
5
  def self.macro
@@ -32,9 +34,7 @@ module ActiveRecord::Associations::Builder # :nodoc:
32
34
  foreign_key = reflection.foreign_key
33
35
  cache_column = reflection.counter_cache_column
34
36
 
35
- if (@_after_create_counter_called ||= false)
36
- @_after_create_counter_called = false
37
- elsif (@_after_replace_counter_called ||= false)
37
+ if (@_after_replace_counter_called ||= false)
38
38
  @_after_replace_counter_called = false
39
39
  elsif saved_change_to_attribute?(foreign_key) && !new_record?
40
40
  if reflection.polymorphic?
@@ -84,8 +84,7 @@ module ActiveRecord::Associations::Builder # :nodoc:
84
84
  else
85
85
  klass = association.klass
86
86
  end
87
- primary_key = reflection.association_primary_key(klass)
88
- old_record = klass.find_by(primary_key => old_foreign_id)
87
+ old_record = klass.find_by(klass.primary_key => old_foreign_id)
89
88
 
90
89
  if old_record
91
90
  if touch != true
@@ -115,13 +114,9 @@ module ActiveRecord::Associations::Builder # :nodoc:
115
114
  BelongsTo.touch_record(record, record.send(changes_method), foreign_key, n, touch, belongs_to_touch_method)
116
115
  }}
117
116
 
118
- unless reflection.counter_cache_column
119
- model.after_create callback.(:saved_changes), if: :saved_changes?
120
- model.after_destroy callback.(:changes_to_save)
121
- end
122
-
123
- model.after_update callback.(:saved_changes), if: :saved_changes?
124
- model.after_touch callback.(:changes_to_save)
117
+ model.after_save callback.(:saved_changes), if: :saved_changes?
118
+ model.after_touch callback.(:changes_to_save)
119
+ model.after_destroy callback.(:changes_to_save)
125
120
  end
126
121
 
127
122
  def self.add_default_callbacks(model, reflection)
@@ -1,4 +1,4 @@
1
- # This class is inherited by the has_many and has_many_and_belongs_to_many association classes
1
+ # frozen_string_literal: true
2
2
 
3
3
  require "active_record/associations"
4
4
 
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ActiveRecord::Associations::Builder # :nodoc:
2
4
  class HasAndBelongsToMany # :nodoc:
3
5
  class JoinTableResolver # :nodoc:
@@ -45,7 +47,7 @@ module ActiveRecord::Associations::Builder # :nodoc:
45
47
  habtm = JoinTableResolver.build lhs_model, association_name, options
46
48
 
47
49
  join_model = Class.new(ActiveRecord::Base) {
48
- class << self;
50
+ class << self
49
51
  attr_accessor :left_model
50
52
  attr_accessor :name
51
53
  attr_accessor :table_name_resolver
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ActiveRecord::Associations::Builder # :nodoc:
2
4
  class HasMany < CollectionAssociation #:nodoc:
3
5
  def self.macro
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ActiveRecord::Associations::Builder # :nodoc:
2
4
  class HasOne < SingularAssociation #:nodoc:
3
5
  def self.macro
@@ -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
@@ -60,7 +62,9 @@ module ActiveRecord
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
@@ -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
@@ -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(:all)
66
+ scope.count
65
67
  end
66
68
 
67
69
  # If there's nothing in the database and @target has no new records
@@ -1,6 +1,8 @@
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
 
@@ -152,7 +154,7 @@ module ActiveRecord
152
154
  stmt.from scope.klass.arel_table
153
155
  stmt.wheres = arel.constraints
154
156
 
155
- count = scope.klass.connection.delete(stmt, "SQL", scope.bound_attributes)
157
+ count = scope.klass.connection.delete(stmt, "SQL")
156
158
  end
157
159
  when :nullify
158
160
  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
 
@@ -1,6 +1,8 @@
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
 
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ActiveRecord
2
4
  module Associations
3
5
  class JoinDependency # :nodoc:
@@ -33,20 +35,14 @@ module ActiveRecord
33
35
  end
34
36
 
35
37
  Table = Struct.new(:node, :columns) do # :nodoc:
36
- def table
37
- Arel::Nodes::TableAlias.new node.table, node.aliased_table_name
38
- end
39
-
40
38
  def column_aliases
41
- t = table
39
+ t = node.table
42
40
  columns.map { |column| t[column.name].as Arel.sql column.alias }
43
41
  end
44
42
  end
45
43
  Column = Struct.new(:name, :alias)
46
44
  end
47
45
 
48
- attr_reader :alias_tracker, :base_klass, :join_root
49
-
50
46
  def self.make_tree(associations)
51
47
  hash = {}
52
48
  walk_tree associations, hash
@@ -92,11 +88,11 @@ module ActiveRecord
92
88
  # associations # => [:appointments]
93
89
  # joins # => []
94
90
  #
95
- def initialize(base, associations, joins, eager_loading: true)
96
- @alias_tracker = AliasTracker.create_with_joins(base.connection, base.table_name, joins)
91
+ def initialize(base, table, associations, alias_tracker, eager_loading: true)
92
+ @alias_tracker = alias_tracker
97
93
  @eager_loading = eager_loading
98
94
  tree = self.class.make_tree associations
99
- @join_root = JoinBase.new base, build(tree, base)
95
+ @join_root = JoinBase.new(base, table, build(tree, base))
100
96
  @join_root.children.each { |child| construct_tables! @join_root, child }
101
97
  end
102
98
 
@@ -104,22 +100,17 @@ module ActiveRecord
104
100
  join_root.drop(1).map!(&:reflection)
105
101
  end
106
102
 
107
- def join_constraints(outer_joins, join_type)
103
+ def join_constraints(joins_to_add, join_type)
108
104
  joins = join_root.children.flat_map { |child|
109
-
110
- if join_type == Arel::Nodes::OuterJoin
111
- make_left_outer_joins join_root, child
112
- else
113
- make_inner_joins join_root, child
114
- end
105
+ make_join_constraints(join_root, child, join_type)
115
106
  }
116
107
 
117
- joins.concat outer_joins.flat_map { |oj|
108
+ joins.concat joins_to_add.flat_map { |oj|
118
109
  if join_root.match? oj.join_root
119
110
  walk join_root, oj.join_root
120
111
  else
121
112
  oj.join_root.children.flat_map { |child|
122
- make_outer_joins oj.join_root, child
113
+ make_join_constraints(oj.join_root, child, join_type)
123
114
  }
124
115
  end
125
116
  }
@@ -165,6 +156,9 @@ module ActiveRecord
165
156
  parents.values
166
157
  end
167
158
 
159
+ protected
160
+ attr_reader :alias_tracker, :base_klass, :join_root
161
+
168
162
  private
169
163
 
170
164
  def make_constraints(parent, child, tables, join_type)
@@ -175,27 +169,15 @@ module ActiveRecord
175
169
  end
176
170
 
177
171
  def make_outer_joins(parent, child)
178
- tables = table_aliases_for(parent, child)
179
- join_type = Arel::Nodes::OuterJoin
180
- info = make_constraints parent, child, tables, join_type
181
-
182
- [info] + child.children.flat_map { |c| make_outer_joins(child, c) }
183
- end
184
-
185
- def make_left_outer_joins(parent, child)
186
- tables = child.tables
187
172
  join_type = Arel::Nodes::OuterJoin
188
- info = make_constraints parent, child, tables, join_type
189
-
190
- [info] + child.children.flat_map { |c| make_left_outer_joins(child, c) }
173
+ make_join_constraints(parent, child, join_type, true)
191
174
  end
192
175
 
193
- def make_inner_joins(parent, child)
194
- tables = child.tables
195
- join_type = Arel::Nodes::InnerJoin
196
- info = make_constraints parent, child, tables, join_type
176
+ def make_join_constraints(parent, child, join_type, aliasing = false)
177
+ tables = aliasing ? table_aliases_for(parent, child) : child.tables
178
+ joins = make_constraints(parent, child, tables, join_type)
197
179
 
198
- [info] + child.children.flat_map { |c| make_inner_joins(child, c) }
180
+ joins.concat child.children.flat_map { |c| make_join_constraints(child, c, join_type, aliasing) }
199
181
  end
200
182
 
201
183
  def table_aliases_for(parent, node)
@@ -215,8 +197,7 @@ module ActiveRecord
215
197
 
216
198
  def table_alias_for(reflection, parent, join)
217
199
  name = "#{reflection.plural_name}_#{parent.table_name}"
218
- name << "_join" if join
219
- name
200
+ join ? "#{name}_join" : name
220
201
  end
221
202
 
222
203
  def walk(left, right)
@@ -244,7 +225,7 @@ module ActiveRecord
244
225
  raise EagerLoadPolymorphicError.new(reflection)
245
226
  end
246
227
 
247
- JoinAssociation.new reflection, build(right, reflection.klass)
228
+ JoinAssociation.new(reflection, build(right, reflection.klass), alias_tracker)
248
229
  end.compact
249
230
  end
250
231
 
@@ -276,7 +257,8 @@ module ActiveRecord
276
257
  else
277
258
  model = construct_model(ar_parent, node, row, model_cache, id, aliases)
278
259
 
279
- if node.reflection.scope_for(node.base_klass).readonly_value
260
+ if node.reflection.scope &&
261
+ node.reflection.scope_for(node.base_klass.unscoped).readonly_value
280
262
  model.readonly!
281
263
  end
282
264