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_support/core_ext/hash/keys'
1
+ require "active_support/core_ext/hash/keys"
2
2
 
3
3
  module ActiveRecord
4
4
  class Relation
@@ -83,85 +83,81 @@ module ActiveRecord
83
83
 
84
84
  private
85
85
 
86
- def merge_preloads
87
- return if other.preload_values.empty? && other.includes_values.empty?
86
+ def merge_preloads
87
+ return if other.preload_values.empty? && other.includes_values.empty?
88
88
 
89
- if other.klass == relation.klass
90
- relation.preload!(*other.preload_values) unless other.preload_values.empty?
91
- relation.includes!(other.includes_values) unless other.includes_values.empty?
92
- else
93
- reflection = relation.klass.reflect_on_all_associations.find do |r|
94
- r.class_name == other.klass.name
95
- end || return
89
+ if other.klass == relation.klass
90
+ relation.preload!(*other.preload_values) unless other.preload_values.empty?
91
+ relation.includes!(other.includes_values) unless other.includes_values.empty?
92
+ else
93
+ reflection = relation.klass.reflect_on_all_associations.find do |r|
94
+ r.class_name == other.klass.name
95
+ end || return
96
96
 
97
- unless other.preload_values.empty?
98
- relation.preload! reflection.name => other.preload_values
99
- end
97
+ unless other.preload_values.empty?
98
+ relation.preload! reflection.name => other.preload_values
99
+ end
100
100
 
101
- unless other.includes_values.empty?
102
- relation.includes! reflection.name => other.includes_values
101
+ unless other.includes_values.empty?
102
+ relation.includes! reflection.name => other.includes_values
103
+ end
103
104
  end
104
105
  end
105
- end
106
106
 
107
- def merge_joins
108
- return if other.joins_values.blank?
107
+ def merge_joins
108
+ return if other.joins_values.blank?
109
109
 
110
- if other.klass == relation.klass
111
- relation.joins!(*other.joins_values)
112
- else
113
- joins_dependency, rest = other.joins_values.partition do |join|
114
- case join
115
- when Hash, Symbol, Array
116
- true
117
- else
118
- false
110
+ if other.klass == relation.klass
111
+ relation.joins!(*other.joins_values)
112
+ else
113
+ joins_dependency, rest = other.joins_values.partition do |join|
114
+ case join
115
+ when Hash, Symbol, Array
116
+ true
117
+ else
118
+ false
119
+ end
119
120
  end
120
- end
121
-
122
- join_dependency = ActiveRecord::Associations::JoinDependency.new(other.klass,
123
- joins_dependency,
124
- [])
125
- relation.joins! rest
126
121
 
127
- @relation = relation.joins join_dependency
128
- end
129
- end
122
+ join_dependency = ActiveRecord::Associations::JoinDependency.new(other.klass,
123
+ joins_dependency,
124
+ [])
125
+ relation.joins! rest
130
126
 
131
- def merge_multi_values
132
- if other.reordering_value
133
- # override any order specified in the original relation
134
- relation.reorder! other.order_values
135
- elsif other.order_values
136
- # merge in order_values from relation
137
- relation.order! other.order_values
127
+ @relation = relation.joins join_dependency
128
+ end
138
129
  end
139
130
 
140
- relation.extend(*other.extending_values) unless other.extending_values.blank?
141
- end
131
+ def merge_multi_values
132
+ if other.reordering_value
133
+ # override any order specified in the original relation
134
+ relation.reorder! other.order_values
135
+ elsif other.order_values
136
+ # merge in order_values from relation
137
+ relation.order! other.order_values
138
+ end
142
139
 
143
- def merge_single_values
144
- if relation.from_clause.empty?
145
- relation.from_clause = other.from_clause
140
+ relation.extend(*other.extending_values) unless other.extending_values.blank?
146
141
  end
147
- relation.lock_value ||= other.lock_value
148
142
 
149
- unless other.create_with_value.blank?
150
- relation.create_with_value = (relation.create_with_value || {}).merge(other.create_with_value)
151
- end
152
- end
143
+ def merge_single_values
144
+ if relation.from_clause.empty?
145
+ relation.from_clause = other.from_clause
146
+ end
147
+ relation.lock_value ||= other.lock_value
153
148
 
154
- CLAUSE_METHOD_NAMES = CLAUSE_METHODS.map do |name|
155
- ["#{name}_clause", "#{name}_clause="]
156
- end
149
+ unless other.create_with_value.blank?
150
+ relation.create_with_value = (relation.create_with_value || {}).merge(other.create_with_value)
151
+ end
152
+ end
157
153
 
158
- def merge_clauses
159
- CLAUSE_METHOD_NAMES.each do |(reader, writer)|
160
- clause = relation.send(reader)
161
- other_clause = other.send(reader)
162
- relation.send(writer, clause.merge(other_clause))
154
+ def merge_clauses
155
+ CLAUSE_METHODS.each do |method|
156
+ clause = relation.get_value(method)
157
+ other_clause = other.get_value(method)
158
+ relation.set_value(method, clause.merge(other_clause))
159
+ end
163
160
  end
164
- end
165
161
  end
166
162
  end
167
163
  end
@@ -1,13 +1,12 @@
1
1
  module ActiveRecord
2
2
  class PredicateBuilder # :nodoc:
3
- require 'active_record/relation/predicate_builder/array_handler'
4
- require 'active_record/relation/predicate_builder/association_query_handler'
5
- require 'active_record/relation/predicate_builder/base_handler'
6
- require 'active_record/relation/predicate_builder/basic_object_handler'
7
- require 'active_record/relation/predicate_builder/class_handler'
8
- require 'active_record/relation/predicate_builder/polymorphic_array_handler'
9
- require 'active_record/relation/predicate_builder/range_handler'
10
- require 'active_record/relation/predicate_builder/relation_handler'
3
+ require "active_record/relation/predicate_builder/array_handler"
4
+ require "active_record/relation/predicate_builder/association_query_handler"
5
+ require "active_record/relation/predicate_builder/base_handler"
6
+ require "active_record/relation/predicate_builder/basic_object_handler"
7
+ require "active_record/relation/predicate_builder/polymorphic_array_handler"
8
+ require "active_record/relation/predicate_builder/range_handler"
9
+ require "active_record/relation/predicate_builder/relation_handler"
11
10
 
12
11
  delegate :resolve_column_aliases, to: :table
13
12
 
@@ -15,11 +14,10 @@ module ActiveRecord
15
14
  @table = table
16
15
  @handlers = []
17
16
 
18
- register_handler(BasicObject, BasicObjectHandler.new(self))
19
- register_handler(Class, ClassHandler.new(self))
17
+ register_handler(BasicObject, BasicObjectHandler.new)
20
18
  register_handler(Base, BaseHandler.new(self))
21
- register_handler(Range, RangeHandler.new(self))
22
- register_handler(RangeHandler::RangeWithBinds, RangeHandler.new(self))
19
+ register_handler(Range, RangeHandler.new)
20
+ register_handler(RangeHandler::RangeWithBinds, RangeHandler.new)
23
21
  register_handler(Relation, RelationHandler.new)
24
22
  register_handler(Array, ArrayHandler.new(self))
25
23
  register_handler(AssociationQueryValue, AssociationQueryHandler.new(self))
@@ -36,23 +34,13 @@ module ActiveRecord
36
34
  create_binds_for_hash(attributes)
37
35
  end
38
36
 
39
- def expand(column, value)
40
- # Find the foreign key when using queries such as:
41
- # Post.where(author: author)
42
- #
43
- # For polymorphic relationships, find the foreign key and type:
44
- # PriceEstimate.where(estimate_of: treasure)
45
- value = AssociationQueryHandler.value_for(table, column, value) if table.associated_with?(column)
46
- build(table.arel_attribute(column), value)
47
- end
48
-
49
37
  def self.references(attributes)
50
38
  attributes.map do |key, value|
51
39
  if value.is_a?(Hash)
52
40
  key
53
41
  else
54
42
  key = key.to_s
55
- key.split('.'.freeze).first if key.include?('.'.freeze)
43
+ key.split(".".freeze).first if key.include?(".".freeze)
56
44
  end
57
45
  end.compact
58
46
  end
@@ -76,93 +64,108 @@ module ActiveRecord
76
64
  handler_for(value).call(attribute, value)
77
65
  end
78
66
 
67
+ # TODO Change this to private once we've dropped Ruby 2.2 support.
68
+ # Workaround for Ruby 2.2 "private attribute?" warning.
79
69
  protected
80
70
 
81
- attr_reader :table
71
+ attr_reader :table
82
72
 
83
- def expand_from_hash(attributes)
84
- return ["1=0"] if attributes.empty?
73
+ def expand_from_hash(attributes)
74
+ return ["1=0"] if attributes.empty?
85
75
 
86
- attributes.flat_map do |key, value|
87
- if value.is_a?(Hash)
88
- associated_predicate_builder(key).expand_from_hash(value)
89
- else
90
- expand(key, value)
76
+ attributes.flat_map do |key, value|
77
+ if value.is_a?(Hash) && !table.has_column?(key)
78
+ associated_predicate_builder(key).expand_from_hash(value)
79
+ else
80
+ build(table.arel_attribute(key), value)
81
+ end
91
82
  end
92
83
  end
93
- end
94
-
95
-
96
- def create_binds_for_hash(attributes)
97
- result = attributes.dup
98
- binds = []
99
84
 
100
- attributes.each do |column_name, value|
101
- case value
102
- when Hash
103
- attrs, bvs = associated_predicate_builder(column_name).create_binds_for_hash(value)
104
- result[column_name] = attrs
105
- binds += bvs
106
- when Relation
107
- binds += value.bound_attributes
108
- when Range
109
- first = value.begin
110
- last = value.end
111
- unless first.respond_to?(:infinite?) && first.infinite?
112
- binds << build_bind_param(column_name, first)
113
- first = Arel::Nodes::BindParam.new
114
- end
115
- unless last.respond_to?(:infinite?) && last.infinite?
116
- binds << build_bind_param(column_name, last)
117
- last = Arel::Nodes::BindParam.new
85
+ def create_binds_for_hash(attributes)
86
+ result = attributes.dup
87
+ binds = []
88
+
89
+ attributes.each do |column_name, value|
90
+ case
91
+ when value.is_a?(Hash) && !table.has_column?(column_name)
92
+ attrs, bvs = associated_predicate_builder(column_name).create_binds_for_hash(value)
93
+ result[column_name] = attrs
94
+ binds += bvs
95
+ next
96
+ when value.is_a?(Relation)
97
+ binds += value.bound_attributes
98
+ when value.is_a?(Range) && !table.type(column_name).respond_to?(:subtype)
99
+ first = value.begin
100
+ last = value.end
101
+ unless first.respond_to?(:infinite?) && first.infinite?
102
+ binds << build_bind_param(column_name, first)
103
+ first = Arel::Nodes::BindParam.new
104
+ end
105
+ unless last.respond_to?(:infinite?) && last.infinite?
106
+ binds << build_bind_param(column_name, last)
107
+ last = Arel::Nodes::BindParam.new
108
+ end
109
+
110
+ result[column_name] = RangeHandler::RangeWithBinds.new(first, last, value.exclude_end?)
111
+ else
112
+ if can_be_bound?(column_name, value)
113
+ result[column_name] = Arel::Nodes::BindParam.new
114
+ binds << build_bind_param(column_name, value)
115
+ end
118
116
  end
119
117
 
120
- result[column_name] = RangeHandler::RangeWithBinds.new(first, last, value.exclude_end?)
121
- else
122
- if can_be_bound?(column_name, value)
123
- result[column_name] = Arel::Nodes::BindParam.new
124
- binds << build_bind_param(column_name, value)
118
+ # Find the foreign key when using queries such as:
119
+ # Post.where(author: author)
120
+ #
121
+ # For polymorphic relationships, find the foreign key and type:
122
+ # PriceEstimate.where(estimate_of: treasure)
123
+ if table.associated_with?(column_name)
124
+ result[column_name] = AssociationQueryHandler.value_for(table, column_name, value)
125
125
  end
126
126
  end
127
- end
128
127
 
129
- [result, binds]
130
- end
128
+ [result, binds]
129
+ end
131
130
 
132
131
  private
133
132
 
134
- def associated_predicate_builder(association_name)
135
- self.class.new(table.associated_table(association_name))
136
- end
137
-
138
- def convert_dot_notation_to_hash(attributes)
139
- dot_notation = attributes.select do |k, v|
140
- k.include?(".".freeze) && !v.is_a?(Hash)
133
+ def associated_predicate_builder(association_name)
134
+ self.class.new(table.associated_table(association_name))
141
135
  end
142
136
 
143
- dot_notation.each_key do |key|
144
- table_name, column_name = key.split(".".freeze)
145
- value = attributes.delete(key)
146
- attributes[table_name] ||= {}
137
+ def convert_dot_notation_to_hash(attributes)
138
+ dot_notation = attributes.select do |k, v|
139
+ k.include?(".".freeze) && !v.is_a?(Hash)
140
+ end
147
141
 
148
- attributes[table_name] = attributes[table_name].merge(column_name => value)
149
- end
142
+ dot_notation.each_key do |key|
143
+ table_name, column_name = key.split(".".freeze)
144
+ value = attributes.delete(key)
145
+ attributes[table_name] ||= {}
150
146
 
151
- attributes
152
- end
147
+ attributes[table_name] = attributes[table_name].merge(column_name => value)
148
+ end
153
149
 
154
- def handler_for(object)
155
- @handlers.detect { |klass, _| klass === object }.last
156
- end
150
+ attributes
151
+ end
157
152
 
158
- def can_be_bound?(column_name, value)
159
- !value.nil? &&
160
- handler_for(value).is_a?(BasicObjectHandler) &&
161
- !table.associated_with?(column_name)
162
- end
153
+ def handler_for(object)
154
+ @handlers.detect { |klass, _| klass === object }.last
155
+ end
163
156
 
164
- def build_bind_param(column_name, value)
165
- Relation::QueryAttribute.new(column_name.to_s, value, table.type(column_name))
166
- end
157
+ def can_be_bound?(column_name, value)
158
+ return if table.associated_with?(column_name)
159
+ case value
160
+ when Array, Range
161
+ table.type(column_name).respond_to?(:subtype)
162
+ else
163
+ !value.nil? && handler_for(value).is_a?(BasicObjectHandler)
164
+ end
165
+ end
166
+
167
+ def build_bind_param(column_name, value)
168
+ Relation::QueryAttribute.new(column_name.to_s, value, table.type(column_name))
169
+ end
167
170
  end
168
171
  end
@@ -29,15 +29,17 @@ module ActiveRecord
29
29
  array_predicates.inject { |composite, predicate| composite.or(predicate) }
30
30
  end
31
31
 
32
+ # TODO Change this to private once we've dropped Ruby 2.2 support.
33
+ # Workaround for Ruby 2.2 "private attribute?" warning.
32
34
  protected
33
35
 
34
- attr_reader :predicate_builder
36
+ attr_reader :predicate_builder
35
37
 
36
- module NullPredicate # :nodoc:
37
- def self.or(other)
38
- other
38
+ module NullPredicate # :nodoc:
39
+ def self.or(other)
40
+ other
41
+ end
39
42
  end
40
- end
41
43
  end
42
44
  end
43
45
  end
@@ -2,13 +2,14 @@ module ActiveRecord
2
2
  class PredicateBuilder
3
3
  class AssociationQueryHandler # :nodoc:
4
4
  def self.value_for(table, column, value)
5
- klass = if table.associated_table(column).polymorphic_association? && ::Array === value && value.first.is_a?(Base)
5
+ associated_table = table.associated_table(column)
6
+ klass = if associated_table.polymorphic_association? && ::Array === value && value.first.is_a?(Base)
6
7
  PolymorphicArrayValue
7
8
  else
8
9
  AssociationQueryValue
9
10
  end
10
11
 
11
- klass.new(table.associated_table(column), value)
12
+ klass.new(associated_table, value)
12
13
  end
13
14
 
14
15
  def initialize(predicate_builder)
@@ -27,9 +28,11 @@ module ActiveRecord
27
28
  predicate_builder.build_from_hash(queries)
28
29
  end
29
30
 
31
+ # TODO Change this to private once we've dropped Ruby 2.2 support.
32
+ # Workaround for Ruby 2.2 "private attribute?" warning.
30
33
  protected
31
34
 
32
- attr_reader :predicate_builder
35
+ attr_reader :predicate_builder
33
36
  end
34
37
 
35
38
  class AssociationQueryValue # :nodoc:
@@ -59,30 +62,27 @@ module ActiveRecord
59
62
 
60
63
  private
61
64
 
62
- def primary_key
63
- associated_table.association_primary_key(base_class)
64
- end
65
+ def primary_key
66
+ associated_table.association_primary_key(base_class)
67
+ end
65
68
 
66
- def polymorphic_base_class_from_value
67
- case value
68
- when Relation
69
- value.klass.base_class
70
- when Array
71
- val = value.compact.first
72
- val.class.base_class if val.is_a?(Base)
73
- when Base
74
- value.class.base_class
69
+ def polymorphic_base_class_from_value
70
+ case value
71
+ when Relation
72
+ value.klass.base_class
73
+ when Base
74
+ value.class.base_class
75
+ end
75
76
  end
76
- end
77
77
 
78
- def convert_to_id(value)
79
- case value
80
- when Base
81
- value._read_attribute(primary_key)
82
- else
83
- value
78
+ def convert_to_id(value)
79
+ case value
80
+ when Base
81
+ value._read_attribute(primary_key)
82
+ else
83
+ value
84
+ end
84
85
  end
85
- end
86
86
  end
87
87
  end
88
88
  end