activerecord 5.0.7.2 → 5.1.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 (216) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG.md +389 -2252
  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.rb +20 -20
  8. data/lib/active_record/aggregations.rb +244 -244
  9. data/lib/active_record/association_relation.rb +5 -5
  10. data/lib/active_record/associations.rb +1579 -1569
  11. data/lib/active_record/associations/alias_tracker.rb +1 -1
  12. data/lib/active_record/associations/association.rb +23 -15
  13. data/lib/active_record/associations/association_scope.rb +83 -81
  14. data/lib/active_record/associations/belongs_to_association.rb +0 -1
  15. data/lib/active_record/associations/builder/belongs_to.rb +16 -14
  16. data/lib/active_record/associations/builder/collection_association.rb +1 -2
  17. data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +27 -27
  18. data/lib/active_record/associations/collection_association.rb +74 -241
  19. data/lib/active_record/associations/collection_proxy.rb +144 -70
  20. data/lib/active_record/associations/has_many_association.rb +15 -19
  21. data/lib/active_record/associations/has_many_through_association.rb +12 -5
  22. data/lib/active_record/associations/has_one_association.rb +22 -28
  23. data/lib/active_record/associations/has_one_through_association.rb +5 -1
  24. data/lib/active_record/associations/join_dependency.rb +117 -115
  25. data/lib/active_record/associations/join_dependency/join_association.rb +16 -13
  26. data/lib/active_record/associations/join_dependency/join_base.rb +1 -1
  27. data/lib/active_record/associations/join_dependency/join_part.rb +1 -1
  28. data/lib/active_record/associations/preloader.rb +94 -94
  29. data/lib/active_record/associations/preloader/association.rb +87 -64
  30. data/lib/active_record/associations/preloader/belongs_to.rb +0 -2
  31. data/lib/active_record/associations/preloader/collection_association.rb +6 -6
  32. data/lib/active_record/associations/preloader/has_many.rb +0 -2
  33. data/lib/active_record/associations/preloader/singular_association.rb +6 -8
  34. data/lib/active_record/associations/preloader/through_association.rb +34 -41
  35. data/lib/active_record/associations/singular_association.rb +8 -25
  36. data/lib/active_record/associations/through_association.rb +3 -6
  37. data/lib/active_record/attribute.rb +98 -71
  38. data/lib/active_record/attribute/user_provided_default.rb +4 -2
  39. data/lib/active_record/attribute_assignment.rb +61 -61
  40. data/lib/active_record/attribute_decorators.rb +35 -13
  41. data/lib/active_record/attribute_methods.rb +56 -65
  42. data/lib/active_record/attribute_methods/before_type_cast.rb +7 -7
  43. data/lib/active_record/attribute_methods/dirty.rb +216 -34
  44. data/lib/active_record/attribute_methods/primary_key.rb +78 -73
  45. data/lib/active_record/attribute_methods/read.rb +39 -35
  46. data/lib/active_record/attribute_methods/serialization.rb +7 -7
  47. data/lib/active_record/attribute_methods/time_zone_conversion.rb +35 -58
  48. data/lib/active_record/attribute_methods/write.rb +36 -30
  49. data/lib/active_record/attribute_mutation_tracker.rb +53 -10
  50. data/lib/active_record/attribute_set.rb +9 -6
  51. data/lib/active_record/attribute_set/builder.rb +41 -49
  52. data/lib/active_record/attribute_set/yaml_encoder.rb +41 -0
  53. data/lib/active_record/attributes.rb +21 -21
  54. data/lib/active_record/autosave_association.rb +13 -13
  55. data/lib/active_record/base.rb +24 -22
  56. data/lib/active_record/callbacks.rb +52 -14
  57. data/lib/active_record/coders/yaml_column.rb +9 -11
  58. data/lib/active_record/collection_cache_key.rb +6 -17
  59. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +320 -278
  60. data/lib/active_record/connection_adapters/abstract/database_limits.rb +1 -3
  61. data/lib/active_record/connection_adapters/abstract/database_statements.rb +22 -34
  62. data/lib/active_record/connection_adapters/abstract/query_cache.rb +31 -27
  63. data/lib/active_record/connection_adapters/abstract/quoting.rb +44 -57
  64. data/lib/active_record/connection_adapters/abstract/schema_creation.rb +9 -19
  65. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +78 -79
  66. data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +53 -41
  67. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +99 -93
  68. data/lib/active_record/connection_adapters/abstract/transaction.rb +1 -5
  69. data/lib/active_record/connection_adapters/abstract_adapter.rb +156 -128
  70. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +424 -382
  71. data/lib/active_record/connection_adapters/column.rb +27 -5
  72. data/lib/active_record/connection_adapters/connection_specification.rb +128 -118
  73. data/lib/active_record/connection_adapters/mysql/column.rb +6 -31
  74. data/lib/active_record/connection_adapters/mysql/database_statements.rb +45 -43
  75. data/lib/active_record/connection_adapters/mysql/explain_pretty_printer.rb +22 -22
  76. data/lib/active_record/connection_adapters/mysql/quoting.rb +6 -12
  77. data/lib/active_record/connection_adapters/mysql/schema_creation.rb +49 -45
  78. data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +16 -19
  79. data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +49 -31
  80. data/lib/active_record/connection_adapters/mysql/type_metadata.rb +5 -6
  81. data/lib/active_record/connection_adapters/mysql2_adapter.rb +24 -26
  82. data/lib/active_record/connection_adapters/postgresql/column.rb +1 -28
  83. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +46 -35
  84. data/lib/active_record/connection_adapters/postgresql/explain_pretty_printer.rb +3 -3
  85. data/lib/active_record/connection_adapters/postgresql/oid.rb +22 -21
  86. data/lib/active_record/connection_adapters/postgresql/oid/array.rb +9 -9
  87. data/lib/active_record/connection_adapters/postgresql/oid/bit.rb +5 -3
  88. data/lib/active_record/connection_adapters/postgresql/oid/bytea.rb +1 -1
  89. data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +1 -1
  90. data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +2 -2
  91. data/lib/active_record/connection_adapters/postgresql/oid/enum.rb +3 -3
  92. data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +16 -16
  93. data/lib/active_record/connection_adapters/postgresql/oid/{rails_5_1_point.rb → legacy_point.rb} +9 -16
  94. data/lib/active_record/connection_adapters/postgresql/oid/money.rb +2 -2
  95. data/lib/active_record/connection_adapters/postgresql/oid/oid.rb +13 -0
  96. data/lib/active_record/connection_adapters/postgresql/oid/point.rb +28 -8
  97. data/lib/active_record/connection_adapters/postgresql/oid/range.rb +28 -30
  98. data/lib/active_record/connection_adapters/postgresql/oid/specialized_string.rb +2 -1
  99. data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +51 -51
  100. data/lib/active_record/connection_adapters/postgresql/quoting.rb +38 -36
  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 +161 -170
  105. data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +4 -4
  106. data/lib/active_record/connection_adapters/postgresql/utils.rb +9 -7
  107. data/lib/active_record/connection_adapters/postgresql_adapter.rb +179 -152
  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 -20
  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_adapter.rb +187 -130
  116. data/lib/active_record/connection_adapters/statement_pool.rb +7 -7
  117. data/lib/active_record/connection_handling.rb +14 -26
  118. data/lib/active_record/core.rb +110 -93
  119. data/lib/active_record/counter_cache.rb +62 -13
  120. data/lib/active_record/define_callbacks.rb +20 -0
  121. data/lib/active_record/dynamic_matchers.rb +80 -79
  122. data/lib/active_record/enum.rb +8 -6
  123. data/lib/active_record/errors.rb +58 -15
  124. data/lib/active_record/explain.rb +1 -2
  125. data/lib/active_record/explain_registry.rb +1 -1
  126. data/lib/active_record/explain_subscriber.rb +7 -4
  127. data/lib/active_record/fixture_set/file.rb +11 -8
  128. data/lib/active_record/fixtures.rb +66 -53
  129. data/lib/active_record/gem_version.rb +3 -3
  130. data/lib/active_record/inheritance.rb +93 -79
  131. data/lib/active_record/integration.rb +7 -7
  132. data/lib/active_record/internal_metadata.rb +3 -16
  133. data/lib/active_record/legacy_yaml_adapter.rb +1 -1
  134. data/lib/active_record/locking/optimistic.rb +64 -56
  135. data/lib/active_record/locking/pessimistic.rb +10 -1
  136. data/lib/active_record/log_subscriber.rb +29 -29
  137. data/lib/active_record/migration.rb +155 -172
  138. data/lib/active_record/migration/command_recorder.rb +94 -94
  139. data/lib/active_record/migration/compatibility.rb +76 -37
  140. data/lib/active_record/migration/join_table.rb +6 -6
  141. data/lib/active_record/model_schema.rb +85 -119
  142. data/lib/active_record/nested_attributes.rb +200 -199
  143. data/lib/active_record/null_relation.rb +10 -33
  144. data/lib/active_record/persistence.rb +45 -38
  145. data/lib/active_record/query_cache.rb +4 -8
  146. data/lib/active_record/querying.rb +2 -3
  147. data/lib/active_record/railtie.rb +16 -17
  148. data/lib/active_record/railties/controller_runtime.rb +6 -2
  149. data/lib/active_record/railties/databases.rake +125 -140
  150. data/lib/active_record/railties/jdbcmysql_error.rb +1 -1
  151. data/lib/active_record/readonly_attributes.rb +2 -2
  152. data/lib/active_record/reflection.rb +79 -96
  153. data/lib/active_record/relation.rb +72 -115
  154. data/lib/active_record/relation/batches.rb +87 -58
  155. data/lib/active_record/relation/batches/batch_enumerator.rb +1 -1
  156. data/lib/active_record/relation/calculations.rb +154 -160
  157. data/lib/active_record/relation/delegation.rb +30 -29
  158. data/lib/active_record/relation/finder_methods.rb +195 -226
  159. data/lib/active_record/relation/merger.rb +58 -62
  160. data/lib/active_record/relation/predicate_builder.rb +92 -89
  161. data/lib/active_record/relation/predicate_builder/array_handler.rb +7 -5
  162. data/lib/active_record/relation/predicate_builder/association_query_handler.rb +23 -23
  163. data/lib/active_record/relation/predicate_builder/base_handler.rb +3 -1
  164. data/lib/active_record/relation/predicate_builder/basic_object_handler.rb +0 -8
  165. data/lib/active_record/relation/predicate_builder/polymorphic_array_handler.rb +12 -10
  166. data/lib/active_record/relation/predicate_builder/range_handler.rb +0 -8
  167. data/lib/active_record/relation/query_attribute.rb +1 -1
  168. data/lib/active_record/relation/query_methods.rb +247 -295
  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 +79 -65
  172. data/lib/active_record/relation/where_clause_factory.rb +47 -8
  173. data/lib/active_record/result.rb +29 -31
  174. data/lib/active_record/runtime_registry.rb +3 -3
  175. data/lib/active_record/sanitization.rb +182 -197
  176. data/lib/active_record/schema.rb +3 -3
  177. data/lib/active_record/schema_dumper.rb +14 -37
  178. data/lib/active_record/schema_migration.rb +3 -3
  179. data/lib/active_record/scoping.rb +9 -10
  180. data/lib/active_record/scoping/default.rb +87 -91
  181. data/lib/active_record/scoping/named.rb +16 -28
  182. data/lib/active_record/secure_token.rb +2 -2
  183. data/lib/active_record/statement_cache.rb +13 -15
  184. data/lib/active_record/store.rb +31 -32
  185. data/lib/active_record/suppressor.rb +2 -1
  186. data/lib/active_record/table_metadata.rb +9 -5
  187. data/lib/active_record/tasks/database_tasks.rb +72 -65
  188. data/lib/active_record/tasks/mysql_database_tasks.rb +75 -72
  189. data/lib/active_record/tasks/postgresql_database_tasks.rb +53 -48
  190. data/lib/active_record/tasks/sqlite_database_tasks.rb +18 -16
  191. data/lib/active_record/timestamp.rb +39 -25
  192. data/lib/active_record/touch_later.rb +1 -2
  193. data/lib/active_record/transactions.rb +98 -110
  194. data/lib/active_record/type.rb +17 -13
  195. data/lib/active_record/type/adapter_specific_registry.rb +46 -42
  196. data/lib/active_record/type/decimal_without_scale.rb +9 -0
  197. data/lib/active_record/type/hash_lookup_type_map.rb +3 -3
  198. data/lib/active_record/type/serialized.rb +8 -8
  199. data/lib/active_record/type/text.rb +9 -0
  200. data/lib/active_record/type/time.rb +0 -1
  201. data/lib/active_record/type/type_map.rb +11 -15
  202. data/lib/active_record/type/unsigned_integer.rb +15 -0
  203. data/lib/active_record/type_caster.rb +2 -2
  204. data/lib/active_record/type_caster/connection.rb +8 -6
  205. data/lib/active_record/type_caster/map.rb +3 -1
  206. data/lib/active_record/validations.rb +4 -4
  207. data/lib/active_record/validations/associated.rb +1 -1
  208. data/lib/active_record/validations/presence.rb +2 -2
  209. data/lib/active_record/validations/uniqueness.rb +8 -39
  210. data/lib/active_record/version.rb +1 -1
  211. data/lib/rails/generators/active_record.rb +4 -4
  212. data/lib/rails/generators/active_record/migration.rb +2 -2
  213. data/lib/rails/generators/active_record/migration/migration_generator.rb +37 -34
  214. data/lib/rails/generators/active_record/model/model_generator.rb +9 -9
  215. metadata +22 -13
  216. data/lib/active_record/relation/predicate_builder/class_handler.rb +0 -27
@@ -1,4 +1,4 @@
1
- require 'active_record/associations/join_dependency/join_part'
1
+ require "active_record/associations/join_dependency/join_part"
2
2
 
3
3
  module ActiveRecord
4
4
  module Associations
@@ -15,7 +15,7 @@ module ActiveRecord
15
15
  # association.
16
16
  attr_reader :base_klass, :children
17
17
 
18
- delegate :table_name, :column_names, :primary_key, :to => :base_klass
18
+ delegate :table_name, :column_names, :primary_key, to: :base_klass
19
19
 
20
20
  def initialize(base_klass, children)
21
21
  @base_klass = base_klass
@@ -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
@@ -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,113 @@ 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
+ @key_conversion_required ||= association_key_type != owner_key_type
94
+ end
99
95
 
100
- def convert_key(key)
101
- if key_conversion_required?
102
- key.to_s
103
- else
104
- key
96
+ def convert_key(key)
97
+ if key_conversion_required?
98
+ key.to_s
99
+ else
100
+ key
101
+ end
105
102
  end
106
- end
107
103
 
108
- def association_key_type
109
- @klass.type_for_attribute(association_key_name.to_s).type
110
- end
104
+ def association_key_type
105
+ @klass.type_for_attribute(association_key_name.to_s).type
106
+ end
111
107
 
112
- def owner_key_type
113
- @model.type_for_attribute(owner_key_name.to_s).type
114
- end
108
+ def owner_key_type
109
+ @model.type_for_attribute(owner_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 load_records(&block)
113
+ return {} if owner_keys.empty?
114
+ # Some databases impose a limit on the number of ids in a list (in Oracle it's 1000)
115
+ # Make several smaller queries if necessary or make one query if the adapter supports it
116
+ slices = owner_keys.each_slice(klass.connection.in_clause_length || owner_keys.size)
117
+ @preloaded_records = slices.flat_map do |slice|
118
+ records_for(slice).load(&block)
119
+ end
120
+ @preloaded_records.group_by do |record|
121
+ convert_key(record[association_key_name])
122
+ end
123
123
  end
124
- @preloaded_records.group_by do |record|
125
- convert_key(record[association_key_name])
124
+
125
+ def reflection_scope
126
+ @reflection_scope ||= reflection.scope_for(klass)
126
127
  end
127
- end
128
128
 
129
- def reflection_scope
130
- @reflection_scope ||= reflection.scope_for(klass)
131
- end
129
+ def build_scope
130
+ scope = klass.unscoped
132
131
 
133
- def build_scope
134
- scope = klass.scope_for_association
132
+ values = reflection_scope.values
133
+ preload_values = preload_scope.values
135
134
 
136
- if reflection.type
137
- scope.where!(reflection.type => model.base_class.sti_name)
138
- end
135
+ scope.where_clause = reflection_scope.where_clause + preload_scope.where_clause
136
+ scope.references_values = Array(values[:references]) + Array(preload_values[:references])
139
137
 
140
- scope.merge!(reflection_scope)
141
- scope.merge!(preload_scope) if preload_scope != NULL_RELATION
142
- scope
143
- end
138
+ if preload_values[:select] || values[:select]
139
+ scope._select!(preload_values[:select] || values[:select])
140
+ end
141
+ scope.includes! preload_values[:includes] || values[:includes]
142
+ if preload_scope.joins_values.any?
143
+ scope.joins!(preload_scope.joins_values)
144
+ else
145
+ scope.joins!(reflection_scope.joins_values)
146
+ end
147
+
148
+ if order_values = preload_values[:order] || values[:order]
149
+ scope.order!(order_values)
150
+ end
151
+
152
+ if preload_values[:reordering] || values[:reordering]
153
+ scope.reordering_value = true
154
+ end
155
+
156
+ if preload_values[:readonly] || values[:readonly]
157
+ scope.readonly!
158
+ end
159
+
160
+ if options[:as]
161
+ scope.where!(klass.table_name => { reflection.type => model.base_class.sti_name })
162
+ end
163
+
164
+ scope.unscope_values = Array(values[:unscope]) + Array(preload_values[:unscope])
165
+ klass.default_scoped.merge(scope)
166
+ end
144
167
  end
145
168
  end
146
169
  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