activerecord 5.0.7 → 5.1.7

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 (219) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG.md +657 -2080
  3. data/MIT-LICENSE +1 -1
  4. data/README.rdoc +1 -1
  5. data/examples/performance.rb +28 -28
  6. data/examples/simple.rb +3 -3
  7. data/lib/active_record/aggregations.rb +244 -244
  8. data/lib/active_record/association_relation.rb +5 -5
  9. data/lib/active_record/associations/alias_tracker.rb +10 -11
  10. data/lib/active_record/associations/association.rb +23 -5
  11. data/lib/active_record/associations/association_scope.rb +95 -81
  12. data/lib/active_record/associations/belongs_to_association.rb +7 -4
  13. data/lib/active_record/associations/builder/belongs_to.rb +30 -16
  14. data/lib/active_record/associations/builder/collection_association.rb +1 -2
  15. data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +27 -27
  16. data/lib/active_record/associations/collection_association.rb +36 -205
  17. data/lib/active_record/associations/collection_proxy.rb +132 -63
  18. data/lib/active_record/associations/has_many_association.rb +10 -19
  19. data/lib/active_record/associations/has_many_through_association.rb +12 -4
  20. data/lib/active_record/associations/has_one_association.rb +24 -28
  21. data/lib/active_record/associations/has_one_through_association.rb +5 -1
  22. data/lib/active_record/associations/join_dependency/join_association.rb +4 -28
  23. data/lib/active_record/associations/join_dependency/join_base.rb +1 -1
  24. data/lib/active_record/associations/join_dependency/join_part.rb +1 -1
  25. data/lib/active_record/associations/join_dependency.rb +121 -118
  26. data/lib/active_record/associations/preloader/association.rb +64 -64
  27. data/lib/active_record/associations/preloader/belongs_to.rb +0 -2
  28. data/lib/active_record/associations/preloader/collection_association.rb +6 -6
  29. data/lib/active_record/associations/preloader/has_many.rb +0 -2
  30. data/lib/active_record/associations/preloader/singular_association.rb +6 -8
  31. data/lib/active_record/associations/preloader/through_association.rb +41 -41
  32. data/lib/active_record/associations/preloader.rb +94 -94
  33. data/lib/active_record/associations/singular_association.rb +8 -25
  34. data/lib/active_record/associations/through_association.rb +2 -5
  35. data/lib/active_record/associations.rb +1591 -1562
  36. data/lib/active_record/attribute/user_provided_default.rb +4 -2
  37. data/lib/active_record/attribute.rb +98 -71
  38. data/lib/active_record/attribute_assignment.rb +61 -61
  39. data/lib/active_record/attribute_decorators.rb +35 -13
  40. data/lib/active_record/attribute_methods/before_type_cast.rb +7 -7
  41. data/lib/active_record/attribute_methods/dirty.rb +229 -46
  42. data/lib/active_record/attribute_methods/primary_key.rb +74 -73
  43. data/lib/active_record/attribute_methods/read.rb +39 -35
  44. data/lib/active_record/attribute_methods/serialization.rb +7 -7
  45. data/lib/active_record/attribute_methods/time_zone_conversion.rb +35 -58
  46. data/lib/active_record/attribute_methods/write.rb +30 -33
  47. data/lib/active_record/attribute_methods.rb +56 -65
  48. data/lib/active_record/attribute_mutation_tracker.rb +63 -11
  49. data/lib/active_record/attribute_set/builder.rb +27 -33
  50. data/lib/active_record/attribute_set/yaml_encoder.rb +41 -0
  51. data/lib/active_record/attribute_set.rb +9 -6
  52. data/lib/active_record/attributes.rb +22 -22
  53. data/lib/active_record/autosave_association.rb +18 -13
  54. data/lib/active_record/base.rb +24 -22
  55. data/lib/active_record/callbacks.rb +56 -14
  56. data/lib/active_record/coders/yaml_column.rb +9 -11
  57. data/lib/active_record/collection_cache_key.rb +3 -4
  58. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +330 -284
  59. data/lib/active_record/connection_adapters/abstract/database_limits.rb +1 -3
  60. data/lib/active_record/connection_adapters/abstract/database_statements.rb +39 -37
  61. data/lib/active_record/connection_adapters/abstract/query_cache.rb +32 -27
  62. data/lib/active_record/connection_adapters/abstract/quoting.rb +62 -51
  63. data/lib/active_record/connection_adapters/abstract/schema_creation.rb +10 -20
  64. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +74 -79
  65. data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +53 -41
  66. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +120 -100
  67. data/lib/active_record/connection_adapters/abstract/transaction.rb +49 -43
  68. data/lib/active_record/connection_adapters/abstract_adapter.rb +165 -135
  69. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +404 -424
  70. data/lib/active_record/connection_adapters/column.rb +26 -4
  71. data/lib/active_record/connection_adapters/connection_specification.rb +128 -118
  72. data/lib/active_record/connection_adapters/mysql/column.rb +6 -31
  73. data/lib/active_record/connection_adapters/mysql/database_statements.rb +36 -49
  74. data/lib/active_record/connection_adapters/mysql/explain_pretty_printer.rb +22 -22
  75. data/lib/active_record/connection_adapters/mysql/quoting.rb +6 -12
  76. data/lib/active_record/connection_adapters/mysql/schema_creation.rb +49 -45
  77. data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +16 -19
  78. data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +54 -28
  79. data/lib/active_record/connection_adapters/mysql/schema_statements.rb +43 -0
  80. data/lib/active_record/connection_adapters/mysql/type_metadata.rb +7 -6
  81. data/lib/active_record/connection_adapters/mysql2_adapter.rb +23 -27
  82. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +32 -53
  83. data/lib/active_record/connection_adapters/postgresql/explain_pretty_printer.rb +3 -3
  84. data/lib/active_record/connection_adapters/postgresql/oid/array.rb +19 -9
  85. data/lib/active_record/connection_adapters/postgresql/oid/bit.rb +5 -3
  86. data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +1 -1
  87. data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +2 -2
  88. data/lib/active_record/connection_adapters/postgresql/oid/decimal.rb +1 -1
  89. data/lib/active_record/connection_adapters/postgresql/oid/enum.rb +3 -3
  90. data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +16 -16
  91. data/lib/active_record/connection_adapters/postgresql/oid/jsonb.rb +0 -10
  92. data/lib/active_record/connection_adapters/postgresql/oid/{rails_5_1_point.rb → legacy_point.rb} +9 -16
  93. data/lib/active_record/connection_adapters/postgresql/oid/money.rb +2 -2
  94. data/lib/active_record/connection_adapters/postgresql/oid/oid.rb +13 -0
  95. data/lib/active_record/connection_adapters/postgresql/oid/point.rb +28 -8
  96. data/lib/active_record/connection_adapters/postgresql/oid/range.rb +32 -30
  97. data/lib/active_record/connection_adapters/postgresql/oid/specialized_string.rb +2 -1
  98. data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +51 -51
  99. data/lib/active_record/connection_adapters/postgresql/oid.rb +22 -21
  100. data/lib/active_record/connection_adapters/postgresql/quoting.rb +40 -35
  101. data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +15 -0
  102. data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +37 -24
  103. data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +19 -23
  104. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +182 -222
  105. data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +6 -4
  106. data/lib/active_record/connection_adapters/postgresql/utils.rb +7 -5
  107. data/lib/active_record/connection_adapters/postgresql_adapter.rb +198 -167
  108. data/lib/active_record/connection_adapters/schema_cache.rb +16 -7
  109. data/lib/active_record/connection_adapters/sql_type_metadata.rb +3 -3
  110. data/lib/active_record/connection_adapters/sqlite3/explain_pretty_printer.rb +1 -1
  111. data/lib/active_record/connection_adapters/sqlite3/quoting.rb +16 -19
  112. data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +1 -8
  113. data/lib/active_record/connection_adapters/sqlite3/schema_definitions.rb +28 -0
  114. data/lib/active_record/connection_adapters/sqlite3/schema_dumper.rb +17 -0
  115. data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +32 -0
  116. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +184 -167
  117. data/lib/active_record/connection_adapters/statement_pool.rb +7 -7
  118. data/lib/active_record/connection_handling.rb +14 -26
  119. data/lib/active_record/core.rb +109 -93
  120. data/lib/active_record/counter_cache.rb +60 -13
  121. data/lib/active_record/define_callbacks.rb +20 -0
  122. data/lib/active_record/dynamic_matchers.rb +80 -79
  123. data/lib/active_record/enum.rb +8 -6
  124. data/lib/active_record/errors.rb +64 -15
  125. data/lib/active_record/explain.rb +1 -2
  126. data/lib/active_record/explain_registry.rb +1 -1
  127. data/lib/active_record/explain_subscriber.rb +7 -4
  128. data/lib/active_record/fixture_set/file.rb +11 -8
  129. data/lib/active_record/fixtures.rb +66 -53
  130. data/lib/active_record/gem_version.rb +1 -1
  131. data/lib/active_record/inheritance.rb +93 -79
  132. data/lib/active_record/integration.rb +7 -7
  133. data/lib/active_record/internal_metadata.rb +3 -16
  134. data/lib/active_record/legacy_yaml_adapter.rb +1 -1
  135. data/lib/active_record/locking/optimistic.rb +69 -74
  136. data/lib/active_record/locking/pessimistic.rb +10 -1
  137. data/lib/active_record/log_subscriber.rb +23 -28
  138. data/lib/active_record/migration/command_recorder.rb +94 -94
  139. data/lib/active_record/migration/compatibility.rb +100 -47
  140. data/lib/active_record/migration/join_table.rb +6 -6
  141. data/lib/active_record/migration.rb +153 -155
  142. data/lib/active_record/model_schema.rb +94 -107
  143. data/lib/active_record/nested_attributes.rb +200 -199
  144. data/lib/active_record/null_relation.rb +11 -34
  145. data/lib/active_record/persistence.rb +65 -50
  146. data/lib/active_record/query_cache.rb +2 -6
  147. data/lib/active_record/querying.rb +3 -4
  148. data/lib/active_record/railtie.rb +16 -17
  149. data/lib/active_record/railties/controller_runtime.rb +6 -2
  150. data/lib/active_record/railties/databases.rake +105 -133
  151. data/lib/active_record/railties/jdbcmysql_error.rb +1 -1
  152. data/lib/active_record/readonly_attributes.rb +2 -2
  153. data/lib/active_record/reflection.rb +154 -108
  154. data/lib/active_record/relation/batches/batch_enumerator.rb +1 -1
  155. data/lib/active_record/relation/batches.rb +80 -51
  156. data/lib/active_record/relation/calculations.rb +169 -162
  157. data/lib/active_record/relation/delegation.rb +32 -31
  158. data/lib/active_record/relation/finder_methods.rb +197 -231
  159. data/lib/active_record/relation/merger.rb +58 -62
  160. data/lib/active_record/relation/predicate_builder/array_handler.rb +7 -5
  161. data/lib/active_record/relation/predicate_builder/association_query_handler.rb +23 -23
  162. data/lib/active_record/relation/predicate_builder/base_handler.rb +3 -1
  163. data/lib/active_record/relation/predicate_builder/basic_object_handler.rb +0 -8
  164. data/lib/active_record/relation/predicate_builder/polymorphic_array_handler.rb +12 -10
  165. data/lib/active_record/relation/predicate_builder/range_handler.rb +0 -8
  166. data/lib/active_record/relation/predicate_builder.rb +92 -89
  167. data/lib/active_record/relation/query_attribute.rb +1 -1
  168. data/lib/active_record/relation/query_methods.rb +255 -293
  169. data/lib/active_record/relation/record_fetch_warning.rb +3 -3
  170. data/lib/active_record/relation/spawn_methods.rb +4 -5
  171. data/lib/active_record/relation/where_clause.rb +80 -65
  172. data/lib/active_record/relation/where_clause_factory.rb +47 -8
  173. data/lib/active_record/relation.rb +93 -119
  174. data/lib/active_record/result.rb +41 -32
  175. data/lib/active_record/runtime_registry.rb +3 -3
  176. data/lib/active_record/sanitization.rb +176 -192
  177. data/lib/active_record/schema.rb +3 -3
  178. data/lib/active_record/schema_dumper.rb +15 -38
  179. data/lib/active_record/schema_migration.rb +8 -4
  180. data/lib/active_record/scoping/default.rb +90 -90
  181. data/lib/active_record/scoping/named.rb +11 -11
  182. data/lib/active_record/scoping.rb +6 -6
  183. data/lib/active_record/secure_token.rb +2 -2
  184. data/lib/active_record/statement_cache.rb +13 -15
  185. data/lib/active_record/store.rb +31 -32
  186. data/lib/active_record/suppressor.rb +2 -1
  187. data/lib/active_record/table_metadata.rb +9 -5
  188. data/lib/active_record/tasks/database_tasks.rb +65 -55
  189. data/lib/active_record/tasks/mysql_database_tasks.rb +76 -73
  190. data/lib/active_record/tasks/postgresql_database_tasks.rb +72 -47
  191. data/lib/active_record/tasks/sqlite_database_tasks.rb +18 -16
  192. data/lib/active_record/timestamp.rb +46 -25
  193. data/lib/active_record/touch_later.rb +1 -2
  194. data/lib/active_record/transactions.rb +97 -109
  195. data/lib/active_record/type/adapter_specific_registry.rb +46 -42
  196. data/lib/active_record/type/decimal_without_scale.rb +13 -0
  197. data/lib/active_record/type/hash_lookup_type_map.rb +3 -3
  198. data/lib/active_record/type/internal/abstract_json.rb +4 -0
  199. data/lib/active_record/type/serialized.rb +14 -8
  200. data/lib/active_record/type/text.rb +9 -0
  201. data/lib/active_record/type/time.rb +0 -1
  202. data/lib/active_record/type/type_map.rb +11 -15
  203. data/lib/active_record/type/unsigned_integer.rb +15 -0
  204. data/lib/active_record/type.rb +17 -13
  205. data/lib/active_record/type_caster/connection.rb +8 -6
  206. data/lib/active_record/type_caster/map.rb +3 -1
  207. data/lib/active_record/type_caster.rb +2 -2
  208. data/lib/active_record/validations/associated.rb +1 -1
  209. data/lib/active_record/validations/presence.rb +2 -2
  210. data/lib/active_record/validations/uniqueness.rb +8 -39
  211. data/lib/active_record/validations.rb +4 -4
  212. data/lib/active_record/version.rb +1 -1
  213. data/lib/active_record.rb +20 -20
  214. data/lib/rails/generators/active_record/migration/migration_generator.rb +37 -34
  215. data/lib/rails/generators/active_record/migration.rb +1 -1
  216. data/lib/rails/generators/active_record/model/model_generator.rb +9 -9
  217. data/lib/rails/generators/active_record.rb +4 -4
  218. metadata +24 -13
  219. data/lib/active_record/relation/predicate_builder/class_handler.rb +0 -27
@@ -28,10 +28,6 @@ module ActiveRecord
28
28
  end
29
29
 
30
30
  def records_for(ids)
31
- query_scope(ids)
32
- end
33
-
34
- def query_scope(ids)
35
31
  scope.where(association_key_name => ids)
36
32
  end
37
33
 
@@ -61,86 +57,90 @@ module ActiveRecord
61
57
 
62
58
  private
63
59
 
64
- def associated_records_by_owner(preloader)
65
- records = load_records do |record|
66
- owner = owners_by_key[convert_key(record[association_key_name])]
67
- association = owner.association(reflection.name)
68
- association.set_inverse_instance(record)
69
- end
60
+ def associated_records_by_owner(preloader)
61
+ records = load_records do |record|
62
+ owner = owners_by_key[convert_key(record[association_key_name])]
63
+ association = owner.association(reflection.name)
64
+ association.set_inverse_instance(record)
65
+ end
70
66
 
71
- owners.each_with_object({}) do |owner, result|
72
- result[owner] = records[convert_key(owner[owner_key_name])] || []
67
+ owners.each_with_object({}) do |owner, result|
68
+ result[owner] = records[convert_key(owner[owner_key_name])] || []
69
+ end
73
70
  end
74
- end
75
71
 
76
- def owner_keys
77
- unless defined?(@owner_keys)
78
- @owner_keys = owners.map do |owner|
79
- owner[owner_key_name]
72
+ def owner_keys
73
+ unless defined?(@owner_keys)
74
+ @owner_keys = owners.map do |owner|
75
+ owner[owner_key_name]
76
+ end
77
+ @owner_keys.uniq!
78
+ @owner_keys.compact!
80
79
  end
81
- @owner_keys.uniq!
82
- @owner_keys.compact!
80
+ @owner_keys
83
81
  end
84
- @owner_keys
85
- end
86
82
 
87
- def owners_by_key
88
- unless defined?(@owners_by_key)
89
- @owners_by_key = owners.each_with_object({}) do |owner, h|
90
- h[convert_key(owner[owner_key_name])] = owner
83
+ def owners_by_key
84
+ unless defined?(@owners_by_key)
85
+ @owners_by_key = owners.each_with_object({}) do |owner, h|
86
+ h[convert_key(owner[owner_key_name])] = owner
87
+ end
91
88
  end
89
+ @owners_by_key
92
90
  end
93
- @owners_by_key
94
- end
95
91
 
96
- def key_conversion_required?
97
- @key_conversion_required ||= association_key_type != owner_key_type
98
- end
92
+ def key_conversion_required?
93
+ unless defined?(@key_conversion_required)
94
+ @key_conversion_required = (association_key_type != owner_key_type)
95
+ end
99
96
 
100
- def convert_key(key)
101
- if key_conversion_required?
102
- key.to_s
103
- else
104
- key
97
+ @key_conversion_required
105
98
  end
106
- end
107
99
 
108
- def association_key_type
109
- @klass.type_for_attribute(association_key_name.to_s).type
110
- end
100
+ def convert_key(key)
101
+ if key_conversion_required?
102
+ key.to_s
103
+ else
104
+ key
105
+ end
106
+ end
111
107
 
112
- def owner_key_type
113
- @model.type_for_attribute(owner_key_name.to_s).type
114
- end
108
+ def association_key_type
109
+ @klass.type_for_attribute(association_key_name.to_s).type
110
+ end
115
111
 
116
- def load_records(&block)
117
- return {} if owner_keys.empty?
118
- # Some databases impose a limit on the number of ids in a list (in Oracle it's 1000)
119
- # Make several smaller queries if necessary or make one query if the adapter supports it
120
- slices = owner_keys.each_slice(klass.connection.in_clause_length || owner_keys.size)
121
- @preloaded_records = slices.flat_map do |slice|
122
- records_for(slice).load(&block)
112
+ def owner_key_type
113
+ @model.type_for_attribute(owner_key_name.to_s).type
123
114
  end
124
- @preloaded_records.group_by do |record|
125
- convert_key(record[association_key_name])
115
+
116
+ def load_records(&block)
117
+ return {} if owner_keys.empty?
118
+ # Some databases impose a limit on the number of ids in a list (in Oracle it's 1000)
119
+ # Make several smaller queries if necessary or make one query if the adapter supports it
120
+ slices = owner_keys.each_slice(klass.connection.in_clause_length || owner_keys.size)
121
+ @preloaded_records = slices.flat_map do |slice|
122
+ records_for(slice).load(&block)
123
+ end
124
+ @preloaded_records.group_by do |record|
125
+ convert_key(record[association_key_name])
126
+ end
126
127
  end
127
- end
128
128
 
129
- def reflection_scope
130
- @reflection_scope ||= reflection.scope_for(klass)
131
- end
129
+ def reflection_scope
130
+ @reflection_scope ||= reflection.scope_for(klass)
131
+ end
132
132
 
133
- def build_scope
134
- scope = klass.scope_for_association
133
+ def build_scope
134
+ scope = klass.scope_for_association
135
135
 
136
- if reflection.type
137
- scope.where!(reflection.type => model.base_class.sti_name)
138
- end
136
+ if reflection.type
137
+ scope.where!(reflection.type => model.base_class.sti_name)
138
+ end
139
139
 
140
- scope.merge!(reflection_scope)
141
- scope.merge!(preload_scope) if preload_scope != NULL_RELATION
142
- scope
143
- end
140
+ scope.merge!(reflection_scope)
141
+ scope.merge!(preload_scope) if preload_scope != NULL_RELATION
142
+ scope
143
+ end
144
144
  end
145
145
  end
146
146
  end
@@ -2,7 +2,6 @@ module ActiveRecord
2
2
  module Associations
3
3
  class Preloader
4
4
  class BelongsTo < SingularAssociation #:nodoc:
5
-
6
5
  def association_key_name
7
6
  reflection.options[:primary_key] || klass && klass.primary_key
8
7
  end
@@ -10,7 +9,6 @@ module ActiveRecord
10
9
  def owner_key_name
11
10
  reflection.foreign_key
12
11
  end
13
-
14
12
  end
15
13
  end
16
14
  end
@@ -4,13 +4,13 @@ module ActiveRecord
4
4
  class CollectionAssociation < Association #:nodoc:
5
5
  private
6
6
 
7
- def preload(preloader)
8
- associated_records_by_owner(preloader).each do |owner, records|
9
- association = owner.association(reflection.name)
10
- association.loaded!
11
- association.target.concat(records)
7
+ def preload(preloader)
8
+ associated_records_by_owner(preloader).each do |owner, records|
9
+ association = owner.association(reflection.name)
10
+ association.loaded!
11
+ association.target.concat(records)
12
+ end
12
13
  end
13
- end
14
14
  end
15
15
  end
16
16
  end
@@ -2,7 +2,6 @@ module ActiveRecord
2
2
  module Associations
3
3
  class Preloader
4
4
  class HasMany < CollectionAssociation #:nodoc:
5
-
6
5
  def association_key_name
7
6
  reflection.foreign_key
8
7
  end
@@ -10,7 +9,6 @@ module ActiveRecord
10
9
  def owner_key_name
11
10
  reflection.active_record_primary_key
12
11
  end
13
-
14
12
  end
15
13
  end
16
14
  end
@@ -2,18 +2,16 @@ module ActiveRecord
2
2
  module Associations
3
3
  class Preloader
4
4
  class SingularAssociation < Association #:nodoc:
5
-
6
5
  private
7
6
 
8
- def preload(preloader)
9
- associated_records_by_owner(preloader).each do |owner, associated_records|
10
- record = associated_records.first
7
+ def preload(preloader)
8
+ associated_records_by_owner(preloader).each do |owner, associated_records|
9
+ record = associated_records.first
11
10
 
12
- association = owner.association(reflection.name)
13
- association.target = record
11
+ association = owner.association(reflection.name)
12
+ association.target = record
13
+ end
14
14
  end
15
- end
16
-
17
15
  end
18
16
  end
19
17
  end
@@ -24,7 +24,7 @@ module ActiveRecord
24
24
 
25
25
  reset_association owners, through_reflection.name
26
26
 
27
- middle_records = through_records.flat_map { |(_,rec)| rec }
27
+ middle_records = through_records.flat_map { |(_, rec)| rec }
28
28
 
29
29
  preloaders = preloader.preload(middle_records,
30
30
  source_reflection.name,
@@ -32,13 +32,13 @@ module ActiveRecord
32
32
 
33
33
  @preloaded_records = preloaders.flat_map(&:preloaded_records)
34
34
 
35
- middle_to_pl = preloaders.each_with_object({}) do |pl,h|
35
+ middle_to_pl = preloaders.each_with_object({}) do |pl, h|
36
36
  pl.owners.each { |middle|
37
37
  h[middle] = pl
38
38
  }
39
39
  end
40
40
 
41
- through_records.each_with_object({}) do |(lhs,center), records_by_owner|
41
+ through_records.each_with_object({}) do |(lhs, center), records_by_owner|
42
42
  pl_to_middle = center.group_by { |record| middle_to_pl[record] }
43
43
 
44
44
  records_by_owner[lhs] = pl_to_middle.flat_map do |pl, middles|
@@ -61,54 +61,54 @@ module ActiveRecord
61
61
 
62
62
  private
63
63
 
64
- def id_to_index_map(ids)
65
- id_map = {}
66
- ids.each_with_index { |id, index| id_map[id] = index }
67
- id_map
68
- end
64
+ def id_to_index_map(ids)
65
+ id_map = {}
66
+ ids.each_with_index { |id, index| id_map[id] = index }
67
+ id_map
68
+ end
69
69
 
70
- def reset_association(owners, association_name)
71
- should_reset = (through_scope != through_reflection.klass.unscoped) ||
72
- (reflection.options[:source_type] && through_reflection.collection?)
70
+ def reset_association(owners, association_name)
71
+ should_reset = (through_scope != through_reflection.klass.unscoped) ||
72
+ (reflection.options[:source_type] && through_reflection.collection?)
73
73
 
74
- # Don't cache the association - we would only be caching a subset
75
- if should_reset
76
- owners.each { |owner|
77
- owner.association(association_name).reset
78
- }
74
+ # Don't cache the association - we would only be caching a subset
75
+ if should_reset
76
+ owners.each { |owner|
77
+ owner.association(association_name).reset
78
+ }
79
+ end
79
80
  end
80
- end
81
81
 
82
- def through_scope
83
- scope = through_reflection.klass.unscoped
84
- values = reflection_scope.values
85
-
86
- if options[:source_type]
87
- scope.where! reflection.foreign_type => options[:source_type]
88
- else
89
- unless reflection_scope.where_clause.empty?
90
- scope.includes_values = Array(values[:includes] || options[:source])
91
- scope.where_clause = reflection_scope.where_clause
92
- if joins = values[:joins]
93
- scope.joins!(source_reflection.name => joins)
82
+ def through_scope
83
+ scope = through_reflection.klass.unscoped
84
+ values = reflection_scope.values
85
+
86
+ if options[:source_type]
87
+ scope.where! reflection.foreign_type => options[:source_type]
88
+ else
89
+ unless reflection_scope.where_clause.empty?
90
+ scope.includes_values = Array(values[:includes] || options[:source])
91
+ scope.where_clause = reflection_scope.where_clause
92
+ if joins = values[:joins]
93
+ scope.joins!(source_reflection.name => joins)
94
+ end
95
+ if left_outer_joins = values[:left_outer_joins]
96
+ scope.left_outer_joins!(source_reflection.name => left_outer_joins)
97
+ end
94
98
  end
95
- if left_outer_joins = values[:left_outer_joins]
96
- scope.left_outer_joins!(source_reflection.name => left_outer_joins)
99
+
100
+ scope.references! values[:references]
101
+ if scope.eager_loading? && order_values = values[:order]
102
+ scope = scope.order(order_values)
97
103
  end
98
104
  end
99
105
 
100
- scope.references! values[:references]
101
- if scope.eager_loading? && order_values = values[:order]
102
- scope = scope.order(order_values)
103
- end
106
+ scope
104
107
  end
105
108
 
106
- scope
107
- end
108
-
109
- def target_records_from_association(association)
110
- association.loaded? ? association.target : association.reader
111
- end
109
+ def target_records_from_association(association)
110
+ association.loaded? ? association.target : association.reader
111
+ end
112
112
  end
113
113
  end
114
114
  end
@@ -42,16 +42,16 @@ module ActiveRecord
42
42
  extend ActiveSupport::Autoload
43
43
 
44
44
  eager_autoload do
45
- autoload :Association, 'active_record/associations/preloader/association'
46
- autoload :SingularAssociation, 'active_record/associations/preloader/singular_association'
47
- autoload :CollectionAssociation, 'active_record/associations/preloader/collection_association'
48
- autoload :ThroughAssociation, 'active_record/associations/preloader/through_association'
49
-
50
- autoload :HasMany, 'active_record/associations/preloader/has_many'
51
- autoload :HasManyThrough, 'active_record/associations/preloader/has_many_through'
52
- autoload :HasOne, 'active_record/associations/preloader/has_one'
53
- autoload :HasOneThrough, 'active_record/associations/preloader/has_one_through'
54
- autoload :BelongsTo, 'active_record/associations/preloader/belongs_to'
45
+ autoload :Association, "active_record/associations/preloader/association"
46
+ autoload :SingularAssociation, "active_record/associations/preloader/singular_association"
47
+ autoload :CollectionAssociation, "active_record/associations/preloader/collection_association"
48
+ autoload :ThroughAssociation, "active_record/associations/preloader/through_association"
49
+
50
+ autoload :HasMany, "active_record/associations/preloader/has_many"
51
+ autoload :HasManyThrough, "active_record/associations/preloader/has_many_through"
52
+ autoload :HasOne, "active_record/associations/preloader/has_one"
53
+ autoload :HasOneThrough, "active_record/associations/preloader/has_one_through"
54
+ autoload :BelongsTo, "active_record/associations/preloader/belongs_to"
55
55
  end
56
56
 
57
57
  NULL_RELATION = Struct.new(:values, :where_clause, :joins_values).new({}, Relation::WhereClause.empty, [])
@@ -106,108 +106,108 @@ module ActiveRecord
106
106
 
107
107
  private
108
108
 
109
- # Loads all the given data into +records+ for the +association+.
110
- def preloaders_on(association, records, scope)
111
- case association
112
- when Hash
113
- preloaders_for_hash(association, records, scope)
114
- when Symbol
115
- preloaders_for_one(association, records, scope)
116
- when String
117
- preloaders_for_one(association.to_sym, records, scope)
118
- else
119
- raise ArgumentError, "#{association.inspect} was not recognized for preload"
109
+ # Loads all the given data into +records+ for the +association+.
110
+ def preloaders_on(association, records, scope)
111
+ case association
112
+ when Hash
113
+ preloaders_for_hash(association, records, scope)
114
+ when Symbol
115
+ preloaders_for_one(association, records, scope)
116
+ when String
117
+ preloaders_for_one(association.to_sym, records, scope)
118
+ else
119
+ raise ArgumentError, "#{association.inspect} was not recognized for preload"
120
+ end
120
121
  end
121
- end
122
122
 
123
- def preloaders_for_hash(association, records, scope)
124
- association.flat_map { |parent, child|
125
- loaders = preloaders_for_one parent, records, scope
123
+ def preloaders_for_hash(association, records, scope)
124
+ association.flat_map { |parent, child|
125
+ loaders = preloaders_for_one parent, records, scope
126
126
 
127
- recs = loaders.flat_map(&:preloaded_records).uniq
128
- loaders.concat Array.wrap(child).flat_map { |assoc|
129
- preloaders_on assoc, recs, scope
127
+ recs = loaders.flat_map(&:preloaded_records).uniq
128
+ loaders.concat Array.wrap(child).flat_map { |assoc|
129
+ preloaders_on assoc, recs, scope
130
+ }
131
+ loaders
130
132
  }
131
- loaders
132
- }
133
- end
133
+ end
134
134
 
135
- # Loads all the given data into +records+ for a singular +association+.
136
- #
137
- # Functions by instantiating a preloader class such as Preloader::HasManyThrough and
138
- # call the +run+ method for each passed in class in the +records+ argument.
139
- #
140
- # Not all records have the same class, so group then preload group on the reflection
141
- # itself so that if various subclass share the same association then we do not split
142
- # them unnecessarily
143
- #
144
- # Additionally, polymorphic belongs_to associations can have multiple associated
145
- # classes, depending on the polymorphic_type field. So we group by the classes as
146
- # well.
147
- def preloaders_for_one(association, records, scope)
148
- grouped_records(association, records).flat_map do |reflection, klasses|
149
- klasses.map do |rhs_klass, rs|
150
- loader = preloader_for(reflection, rs, rhs_klass).new(rhs_klass, rs, reflection, scope)
151
- loader.run self
152
- loader
135
+ # Loads all the given data into +records+ for a singular +association+.
136
+ #
137
+ # Functions by instantiating a preloader class such as Preloader::HasManyThrough and
138
+ # call the +run+ method for each passed in class in the +records+ argument.
139
+ #
140
+ # Not all records have the same class, so group then preload group on the reflection
141
+ # itself so that if various subclass share the same association then we do not split
142
+ # them unnecessarily
143
+ #
144
+ # Additionally, polymorphic belongs_to associations can have multiple associated
145
+ # classes, depending on the polymorphic_type field. So we group by the classes as
146
+ # well.
147
+ def preloaders_for_one(association, records, scope)
148
+ grouped_records(association, records).flat_map do |reflection, klasses|
149
+ klasses.map do |rhs_klass, rs|
150
+ loader = preloader_for(reflection, rs, rhs_klass).new(rhs_klass, rs, reflection, scope)
151
+ loader.run self
152
+ loader
153
+ end
153
154
  end
154
155
  end
155
- end
156
156
 
157
- def grouped_records(association, records)
158
- h = {}
159
- records.each do |record|
160
- next unless record
161
- assoc = record.association(association)
162
- klasses = h[assoc.reflection] ||= {}
163
- (klasses[assoc.klass] ||= []) << record
157
+ def grouped_records(association, records)
158
+ h = {}
159
+ records.each do |record|
160
+ next unless record
161
+ assoc = record.association(association)
162
+ klasses = h[assoc.reflection] ||= {}
163
+ (klasses[assoc.klass] ||= []) << record
164
+ end
165
+ h
164
166
  end
165
- h
166
- end
167
167
 
168
- class AlreadyLoaded # :nodoc:
169
- attr_reader :owners, :reflection
168
+ class AlreadyLoaded # :nodoc:
169
+ attr_reader :owners, :reflection
170
170
 
171
- def initialize(klass, owners, reflection, preload_scope)
172
- @owners = owners
173
- @reflection = reflection
174
- end
171
+ def initialize(klass, owners, reflection, preload_scope)
172
+ @owners = owners
173
+ @reflection = reflection
174
+ end
175
175
 
176
- def run(preloader); end
176
+ def run(preloader); end
177
177
 
178
- def preloaded_records
179
- owners.flat_map { |owner| owner.association(reflection.name).target }
178
+ def preloaded_records
179
+ owners.flat_map { |owner| owner.association(reflection.name).target }
180
+ end
180
181
  end
181
- end
182
182
 
183
- class NullPreloader # :nodoc:
184
- def self.new(klass, owners, reflection, preload_scope); self; end
185
- def self.run(preloader); end
186
- def self.preloaded_records; []; end
187
- def self.owners; []; end
188
- end
183
+ class NullPreloader # :nodoc:
184
+ def self.new(klass, owners, reflection, preload_scope); self; end
185
+ def self.run(preloader); end
186
+ def self.preloaded_records; []; end
187
+ def self.owners; []; end
188
+ end
189
189
 
190
- # Returns a class containing the logic needed to load preload the data
191
- # and attach it to a relation. For example +Preloader::Association+ or
192
- # +Preloader::HasManyThrough+. The class returned implements a `run` method
193
- # that accepts a preloader.
194
- def preloader_for(reflection, owners, rhs_klass)
195
- return NullPreloader unless rhs_klass
190
+ # Returns a class containing the logic needed to load preload the data
191
+ # and attach it to a relation. For example +Preloader::Association+ or
192
+ # +Preloader::HasManyThrough+. The class returned implements a `run` method
193
+ # that accepts a preloader.
194
+ def preloader_for(reflection, owners, rhs_klass)
195
+ return NullPreloader unless rhs_klass
196
196
 
197
- if owners.first.association(reflection.name).loaded?
198
- return AlreadyLoaded
199
- end
200
- reflection.check_preloadable!
201
-
202
- case reflection.macro
203
- when :has_many
204
- reflection.options[:through] ? HasManyThrough : HasMany
205
- when :has_one
206
- reflection.options[:through] ? HasOneThrough : HasOne
207
- when :belongs_to
208
- BelongsTo
197
+ if owners.first.association(reflection.name).loaded?
198
+ return AlreadyLoaded
199
+ end
200
+ reflection.check_preloadable!
201
+
202
+ case reflection.macro
203
+ when :has_many
204
+ reflection.options[:through] ? HasManyThrough : HasMany
205
+ when :has_one
206
+ reflection.options[:through] ? HasOneThrough : HasOne
207
+ when :belongs_to
208
+ BelongsTo
209
+ end
209
210
  end
210
- end
211
211
  end
212
212
  end
213
213
  end
@@ -2,15 +2,8 @@ module ActiveRecord
2
2
  module Associations
3
3
  class SingularAssociation < Association #:nodoc:
4
4
  # Implements the reader method, e.g. foo.bar for Foo.has_one :bar
5
- def reader(force_reload = false)
6
- if force_reload && klass
7
- ActiveSupport::Deprecation.warn(<<-MSG.squish)
8
- Passing an argument to force an association to reload is now
9
- deprecated and will be removed in Rails 5.1. Please call `reload_#{reflection.name}` instead.
10
- MSG
11
-
12
- klass.uncached { reload }
13
- elsif !loaded? || stale_target?
5
+ def reader
6
+ if !loaded? || stale_target?
14
7
  reload
15
8
  end
16
9
 
@@ -22,14 +15,6 @@ module ActiveRecord
22
15
  replace(record)
23
16
  end
24
17
 
25
- def create(attributes = {}, &block)
26
- _create_record(attributes, &block)
27
- end
28
-
29
- def create!(attributes = {}, &block)
30
- _create_record(attributes, true, &block)
31
- end
32
-
33
18
  def build(attributes = {})
34
19
  record = build_record(attributes)
35
20
  yield(record) if block_given?
@@ -50,8 +35,8 @@ module ActiveRecord
50
35
  scope.scope_for_create.stringify_keys.except(klass.primary_key)
51
36
  end
52
37
 
53
- def get_records
54
- return scope.limit(1).records if skip_statement_cache?
38
+ def find_target
39
+ return scope.take if skip_statement_cache?
55
40
 
56
41
  conn = klass.connection
57
42
  sc = reflection.association_scope_cache(conn, owner) do
@@ -62,13 +47,11 @@ module ActiveRecord
62
47
  end
63
48
 
64
49
  binds = AssociationScope.get_bind_values(owner, reflection.chain)
65
- sc.execute binds, klass, klass.connection
66
- end
67
-
68
- def find_target
69
- if record = get_records.first
50
+ sc.execute(binds, klass, conn) do |record|
70
51
  set_inverse_instance record
71
- end
52
+ end.first
53
+ rescue ::RangeError
54
+ nil
72
55
  end
73
56
 
74
57
  def replace(record)
@@ -2,10 +2,9 @@ module ActiveRecord
2
2
  # = Active Record Through Association
3
3
  module Associations
4
4
  module ThroughAssociation #:nodoc:
5
+ delegate :source_reflection, :through_reflection, to: :reflection
5
6
 
6
- delegate :source_reflection, :through_reflection, :to => :reflection
7
-
8
- protected
7
+ private
9
8
 
10
9
  # We merge in these scopes for two reasons:
11
10
  #
@@ -22,8 +21,6 @@ module ActiveRecord
22
21
  scope
23
22
  end
24
23
 
25
- private
26
-
27
24
  # Construct attributes for :through pointing to owner and associate. This is used by the
28
25
  # methods which create and delete records on the association.
29
26
  #