activerecord 5.2.3 → 6.0.0

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 (268) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +624 -548
  3. data/MIT-LICENSE +3 -1
  4. data/README.rdoc +4 -2
  5. data/examples/performance.rb +1 -1
  6. data/lib/active_record.rb +9 -2
  7. data/lib/active_record/aggregations.rb +4 -2
  8. data/lib/active_record/associations.rb +19 -14
  9. data/lib/active_record/associations/association.rb +52 -19
  10. data/lib/active_record/associations/association_scope.rb +4 -6
  11. data/lib/active_record/associations/belongs_to_association.rb +36 -42
  12. data/lib/active_record/associations/belongs_to_polymorphic_association.rb +0 -4
  13. data/lib/active_record/associations/builder/association.rb +14 -18
  14. data/lib/active_record/associations/builder/belongs_to.rb +19 -52
  15. data/lib/active_record/associations/builder/collection_association.rb +5 -15
  16. data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +17 -38
  17. data/lib/active_record/associations/builder/has_many.rb +2 -0
  18. data/lib/active_record/associations/builder/has_one.rb +35 -1
  19. data/lib/active_record/associations/builder/singular_association.rb +2 -0
  20. data/lib/active_record/associations/collection_association.rb +6 -21
  21. data/lib/active_record/associations/collection_proxy.rb +12 -15
  22. data/lib/active_record/associations/foreign_association.rb +7 -0
  23. data/lib/active_record/associations/has_many_association.rb +2 -10
  24. data/lib/active_record/associations/has_many_through_association.rb +18 -25
  25. data/lib/active_record/associations/has_one_association.rb +28 -30
  26. data/lib/active_record/associations/has_one_through_association.rb +5 -5
  27. data/lib/active_record/associations/join_dependency.rb +24 -28
  28. data/lib/active_record/associations/join_dependency/join_association.rb +27 -7
  29. data/lib/active_record/associations/join_dependency/join_part.rb +2 -2
  30. data/lib/active_record/associations/preloader.rb +39 -31
  31. data/lib/active_record/associations/preloader/association.rb +38 -36
  32. data/lib/active_record/associations/preloader/through_association.rb +48 -39
  33. data/lib/active_record/associations/singular_association.rb +2 -16
  34. data/lib/active_record/attribute_assignment.rb +7 -10
  35. data/lib/active_record/attribute_methods.rb +28 -100
  36. data/lib/active_record/attribute_methods/before_type_cast.rb +4 -1
  37. data/lib/active_record/attribute_methods/dirty.rb +111 -40
  38. data/lib/active_record/attribute_methods/primary_key.rb +15 -22
  39. data/lib/active_record/attribute_methods/query.rb +2 -3
  40. data/lib/active_record/attribute_methods/read.rb +15 -53
  41. data/lib/active_record/attribute_methods/serialization.rb +1 -1
  42. data/lib/active_record/attribute_methods/time_zone_conversion.rb +1 -1
  43. data/lib/active_record/attribute_methods/write.rb +17 -24
  44. data/lib/active_record/attributes.rb +13 -0
  45. data/lib/active_record/autosave_association.rb +16 -6
  46. data/lib/active_record/base.rb +2 -3
  47. data/lib/active_record/callbacks.rb +5 -19
  48. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +116 -19
  49. data/lib/active_record/connection_adapters/abstract/database_limits.rb +17 -4
  50. data/lib/active_record/connection_adapters/abstract/database_statements.rb +95 -123
  51. data/lib/active_record/connection_adapters/abstract/query_cache.rb +20 -11
  52. data/lib/active_record/connection_adapters/abstract/quoting.rb +68 -17
  53. data/lib/active_record/connection_adapters/abstract/schema_creation.rb +19 -12
  54. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +76 -48
  55. data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +1 -3
  56. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +133 -54
  57. data/lib/active_record/connection_adapters/abstract/transaction.rb +96 -56
  58. data/lib/active_record/connection_adapters/abstract_adapter.rb +180 -47
  59. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +128 -194
  60. data/lib/active_record/connection_adapters/column.rb +17 -13
  61. data/lib/active_record/connection_adapters/connection_specification.rb +52 -42
  62. data/lib/active_record/connection_adapters/determine_if_preparable_visitor.rb +6 -10
  63. data/lib/active_record/connection_adapters/mysql/database_statements.rb +73 -13
  64. data/lib/active_record/connection_adapters/mysql/quoting.rb +44 -7
  65. data/lib/active_record/connection_adapters/mysql/schema_creation.rb +3 -4
  66. data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +40 -32
  67. data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +14 -6
  68. data/lib/active_record/connection_adapters/mysql/schema_statements.rb +129 -13
  69. data/lib/active_record/connection_adapters/mysql/type_metadata.rb +6 -10
  70. data/lib/active_record/connection_adapters/mysql2_adapter.rb +26 -9
  71. data/lib/active_record/connection_adapters/postgresql/column.rb +17 -31
  72. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +20 -1
  73. data/lib/active_record/connection_adapters/postgresql/oid/array.rb +1 -1
  74. data/lib/active_record/connection_adapters/postgresql/oid/bit.rb +1 -4
  75. data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +1 -1
  76. data/lib/active_record/connection_adapters/postgresql/oid/legacy_point.rb +1 -1
  77. data/lib/active_record/connection_adapters/postgresql/oid/money.rb +2 -2
  78. data/lib/active_record/connection_adapters/postgresql/oid/point.rb +1 -1
  79. data/lib/active_record/connection_adapters/postgresql/oid/range.rb +1 -1
  80. data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +9 -7
  81. data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +6 -3
  82. data/lib/active_record/connection_adapters/postgresql/quoting.rb +44 -7
  83. data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +12 -1
  84. data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +107 -91
  85. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +55 -53
  86. data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +24 -27
  87. data/lib/active_record/connection_adapters/postgresql_adapter.rb +160 -74
  88. data/lib/active_record/connection_adapters/schema_cache.rb +37 -14
  89. data/lib/active_record/connection_adapters/sql_type_metadata.rb +11 -8
  90. data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +118 -0
  91. data/lib/active_record/connection_adapters/sqlite3/quoting.rb +42 -6
  92. data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +42 -11
  93. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +127 -143
  94. data/lib/active_record/connection_handling.rb +149 -27
  95. data/lib/active_record/core.rb +100 -60
  96. data/lib/active_record/counter_cache.rb +4 -29
  97. data/lib/active_record/database_configurations.rb +233 -0
  98. data/lib/active_record/database_configurations/database_config.rb +37 -0
  99. data/lib/active_record/database_configurations/hash_config.rb +50 -0
  100. data/lib/active_record/database_configurations/url_config.rb +79 -0
  101. data/lib/active_record/dynamic_matchers.rb +1 -1
  102. data/lib/active_record/enum.rb +37 -7
  103. data/lib/active_record/errors.rb +15 -7
  104. data/lib/active_record/explain.rb +1 -1
  105. data/lib/active_record/fixture_set/model_metadata.rb +33 -0
  106. data/lib/active_record/fixture_set/render_context.rb +17 -0
  107. data/lib/active_record/fixture_set/table_row.rb +153 -0
  108. data/lib/active_record/fixture_set/table_rows.rb +47 -0
  109. data/lib/active_record/fixtures.rb +145 -472
  110. data/lib/active_record/gem_version.rb +3 -3
  111. data/lib/active_record/inheritance.rb +13 -3
  112. data/lib/active_record/insert_all.rb +179 -0
  113. data/lib/active_record/integration.rb +68 -16
  114. data/lib/active_record/internal_metadata.rb +10 -2
  115. data/lib/active_record/locking/optimistic.rb +5 -6
  116. data/lib/active_record/locking/pessimistic.rb +3 -3
  117. data/lib/active_record/log_subscriber.rb +7 -26
  118. data/lib/active_record/middleware/database_selector.rb +75 -0
  119. data/lib/active_record/middleware/database_selector/resolver.rb +92 -0
  120. data/lib/active_record/middleware/database_selector/resolver/session.rb +45 -0
  121. data/lib/active_record/migration.rb +100 -81
  122. data/lib/active_record/migration/command_recorder.rb +50 -6
  123. data/lib/active_record/migration/compatibility.rb +76 -49
  124. data/lib/active_record/model_schema.rb +30 -9
  125. data/lib/active_record/nested_attributes.rb +2 -2
  126. data/lib/active_record/no_touching.rb +7 -0
  127. data/lib/active_record/persistence.rb +228 -24
  128. data/lib/active_record/query_cache.rb +11 -4
  129. data/lib/active_record/querying.rb +32 -20
  130. data/lib/active_record/railtie.rb +80 -43
  131. data/lib/active_record/railties/collection_cache_association_loading.rb +34 -0
  132. data/lib/active_record/railties/controller_runtime.rb +30 -35
  133. data/lib/active_record/railties/databases.rake +196 -46
  134. data/lib/active_record/reflection.rb +42 -44
  135. data/lib/active_record/relation.rb +310 -80
  136. data/lib/active_record/relation/batches.rb +13 -10
  137. data/lib/active_record/relation/calculations.rb +58 -51
  138. data/lib/active_record/relation/delegation.rb +26 -43
  139. data/lib/active_record/relation/finder_methods.rb +14 -27
  140. data/lib/active_record/relation/merger.rb +11 -20
  141. data/lib/active_record/relation/predicate_builder.rb +4 -6
  142. data/lib/active_record/relation/predicate_builder/array_handler.rb +5 -4
  143. data/lib/active_record/relation/predicate_builder/association_query_value.rb +1 -4
  144. data/lib/active_record/relation/predicate_builder/base_handler.rb +1 -2
  145. data/lib/active_record/relation/predicate_builder/basic_object_handler.rb +1 -2
  146. data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +1 -4
  147. data/lib/active_record/relation/predicate_builder/range_handler.rb +3 -23
  148. data/lib/active_record/relation/query_attribute.rb +13 -8
  149. data/lib/active_record/relation/query_methods.rb +206 -78
  150. data/lib/active_record/relation/spawn_methods.rb +1 -1
  151. data/lib/active_record/relation/where_clause.rb +14 -10
  152. data/lib/active_record/relation/where_clause_factory.rb +1 -2
  153. data/lib/active_record/result.rb +30 -11
  154. data/lib/active_record/sanitization.rb +32 -40
  155. data/lib/active_record/schema.rb +2 -11
  156. data/lib/active_record/schema_dumper.rb +22 -7
  157. data/lib/active_record/schema_migration.rb +5 -1
  158. data/lib/active_record/scoping.rb +8 -8
  159. data/lib/active_record/scoping/default.rb +6 -7
  160. data/lib/active_record/scoping/named.rb +19 -15
  161. data/lib/active_record/statement_cache.rb +32 -5
  162. data/lib/active_record/store.rb +87 -8
  163. data/lib/active_record/table_metadata.rb +10 -17
  164. data/lib/active_record/tasks/database_tasks.rb +194 -25
  165. data/lib/active_record/tasks/mysql_database_tasks.rb +5 -5
  166. data/lib/active_record/tasks/postgresql_database_tasks.rb +5 -7
  167. data/lib/active_record/tasks/sqlite_database_tasks.rb +2 -8
  168. data/lib/active_record/test_databases.rb +23 -0
  169. data/lib/active_record/test_fixtures.rb +224 -0
  170. data/lib/active_record/timestamp.rb +39 -25
  171. data/lib/active_record/touch_later.rb +4 -2
  172. data/lib/active_record/transactions.rb +56 -65
  173. data/lib/active_record/translation.rb +1 -1
  174. data/lib/active_record/type.rb +3 -4
  175. data/lib/active_record/type/adapter_specific_registry.rb +1 -8
  176. data/lib/active_record/type_caster/connection.rb +15 -14
  177. data/lib/active_record/type_caster/map.rb +1 -4
  178. data/lib/active_record/validations.rb +1 -0
  179. data/lib/active_record/validations/uniqueness.rb +15 -27
  180. data/lib/arel.rb +51 -0
  181. data/lib/arel/alias_predication.rb +9 -0
  182. data/lib/arel/attributes.rb +22 -0
  183. data/lib/arel/attributes/attribute.rb +37 -0
  184. data/lib/arel/collectors/bind.rb +24 -0
  185. data/lib/arel/collectors/composite.rb +31 -0
  186. data/lib/arel/collectors/plain_string.rb +20 -0
  187. data/lib/arel/collectors/sql_string.rb +20 -0
  188. data/lib/arel/collectors/substitute_binds.rb +28 -0
  189. data/lib/arel/crud.rb +42 -0
  190. data/lib/arel/delete_manager.rb +18 -0
  191. data/lib/arel/errors.rb +9 -0
  192. data/lib/arel/expressions.rb +29 -0
  193. data/lib/arel/factory_methods.rb +49 -0
  194. data/lib/arel/insert_manager.rb +49 -0
  195. data/lib/arel/math.rb +45 -0
  196. data/lib/arel/nodes.rb +68 -0
  197. data/lib/arel/nodes/and.rb +32 -0
  198. data/lib/arel/nodes/ascending.rb +23 -0
  199. data/lib/arel/nodes/binary.rb +52 -0
  200. data/lib/arel/nodes/bind_param.rb +36 -0
  201. data/lib/arel/nodes/case.rb +55 -0
  202. data/lib/arel/nodes/casted.rb +50 -0
  203. data/lib/arel/nodes/comment.rb +29 -0
  204. data/lib/arel/nodes/count.rb +12 -0
  205. data/lib/arel/nodes/delete_statement.rb +45 -0
  206. data/lib/arel/nodes/descending.rb +23 -0
  207. data/lib/arel/nodes/equality.rb +18 -0
  208. data/lib/arel/nodes/extract.rb +24 -0
  209. data/lib/arel/nodes/false.rb +16 -0
  210. data/lib/arel/nodes/full_outer_join.rb +8 -0
  211. data/lib/arel/nodes/function.rb +44 -0
  212. data/lib/arel/nodes/grouping.rb +8 -0
  213. data/lib/arel/nodes/in.rb +8 -0
  214. data/lib/arel/nodes/infix_operation.rb +80 -0
  215. data/lib/arel/nodes/inner_join.rb +8 -0
  216. data/lib/arel/nodes/insert_statement.rb +37 -0
  217. data/lib/arel/nodes/join_source.rb +20 -0
  218. data/lib/arel/nodes/matches.rb +18 -0
  219. data/lib/arel/nodes/named_function.rb +23 -0
  220. data/lib/arel/nodes/node.rb +50 -0
  221. data/lib/arel/nodes/node_expression.rb +13 -0
  222. data/lib/arel/nodes/outer_join.rb +8 -0
  223. data/lib/arel/nodes/over.rb +15 -0
  224. data/lib/arel/nodes/regexp.rb +16 -0
  225. data/lib/arel/nodes/right_outer_join.rb +8 -0
  226. data/lib/arel/nodes/select_core.rb +67 -0
  227. data/lib/arel/nodes/select_statement.rb +41 -0
  228. data/lib/arel/nodes/sql_literal.rb +16 -0
  229. data/lib/arel/nodes/string_join.rb +11 -0
  230. data/lib/arel/nodes/table_alias.rb +27 -0
  231. data/lib/arel/nodes/terminal.rb +16 -0
  232. data/lib/arel/nodes/true.rb +16 -0
  233. data/lib/arel/nodes/unary.rb +45 -0
  234. data/lib/arel/nodes/unary_operation.rb +20 -0
  235. data/lib/arel/nodes/unqualified_column.rb +22 -0
  236. data/lib/arel/nodes/update_statement.rb +41 -0
  237. data/lib/arel/nodes/values_list.rb +9 -0
  238. data/lib/arel/nodes/window.rb +126 -0
  239. data/lib/arel/nodes/with.rb +11 -0
  240. data/lib/arel/order_predications.rb +13 -0
  241. data/lib/arel/predications.rb +257 -0
  242. data/lib/arel/select_manager.rb +271 -0
  243. data/lib/arel/table.rb +110 -0
  244. data/lib/arel/tree_manager.rb +72 -0
  245. data/lib/arel/update_manager.rb +34 -0
  246. data/lib/arel/visitors.rb +20 -0
  247. data/lib/arel/visitors/depth_first.rb +204 -0
  248. data/lib/arel/visitors/dot.rb +297 -0
  249. data/lib/arel/visitors/ibm_db.rb +34 -0
  250. data/lib/arel/visitors/informix.rb +62 -0
  251. data/lib/arel/visitors/mssql.rb +157 -0
  252. data/lib/arel/visitors/mysql.rb +83 -0
  253. data/lib/arel/visitors/oracle.rb +159 -0
  254. data/lib/arel/visitors/oracle12.rb +66 -0
  255. data/lib/arel/visitors/postgresql.rb +110 -0
  256. data/lib/arel/visitors/sqlite.rb +39 -0
  257. data/lib/arel/visitors/to_sql.rb +889 -0
  258. data/lib/arel/visitors/visitor.rb +46 -0
  259. data/lib/arel/visitors/where_sql.rb +23 -0
  260. data/lib/arel/window_predications.rb +9 -0
  261. data/lib/rails/generators/active_record/migration.rb +14 -1
  262. data/lib/rails/generators/active_record/migration/migration_generator.rb +2 -5
  263. data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb.tt +1 -1
  264. data/lib/rails/generators/active_record/migration/templates/migration.rb.tt +4 -2
  265. data/lib/rails/generators/active_record/model/model_generator.rb +1 -0
  266. data/lib/rails/generators/active_record/model/templates/model.rb.tt +10 -1
  267. metadata +107 -25
  268. data/lib/active_record/collection_cache_key.rb +0 -53
@@ -251,25 +251,28 @@ module ActiveRecord
251
251
  end
252
252
  end
253
253
 
254
- attr = Relation::QueryAttribute.new(primary_key, primary_key_offset, klass.type_for_attribute(primary_key))
255
- batch_relation = relation.where(arel_attribute(primary_key).gt(Arel::Nodes::BindParam.new(attr)))
254
+ batch_relation = relation.where(
255
+ bind_attribute(primary_key, primary_key_offset) { |attr, bind| attr.gt(bind) }
256
+ )
256
257
  end
257
258
  end
258
259
 
259
260
  private
260
261
 
261
262
  def apply_limits(relation, start, finish)
262
- if start
263
- attr = Relation::QueryAttribute.new(primary_key, start, klass.type_for_attribute(primary_key))
264
- relation = relation.where(arel_attribute(primary_key).gteq(Arel::Nodes::BindParam.new(attr)))
265
- end
266
- if finish
267
- attr = Relation::QueryAttribute.new(primary_key, finish, klass.type_for_attribute(primary_key))
268
- relation = relation.where(arel_attribute(primary_key).lteq(Arel::Nodes::BindParam.new(attr)))
269
- end
263
+ relation = apply_start_limit(relation, start) if start
264
+ relation = apply_finish_limit(relation, finish) if finish
270
265
  relation
271
266
  end
272
267
 
268
+ def apply_start_limit(relation, start)
269
+ relation.where(bind_attribute(primary_key, start) { |attr, bind| attr.gteq(bind) })
270
+ end
271
+
272
+ def apply_finish_limit(relation, finish)
273
+ relation.where(bind_attribute(primary_key, finish) { |attr, bind| attr.lteq(bind) })
274
+ end
275
+
273
276
  def batch_order
274
277
  arel_attribute(primary_key).asc
275
278
  end
@@ -41,15 +41,13 @@ module ActiveRecord
41
41
  def count(column_name = nil)
42
42
  if block_given?
43
43
  unless column_name.nil?
44
- ActiveSupport::Deprecation.warn \
45
- "When `count' is called with a block, it ignores other arguments. " \
46
- "This behavior is now deprecated and will result in an ArgumentError in Rails 6.0."
44
+ raise ArgumentError, "Column name argument is not supported when a block is passed."
47
45
  end
48
46
 
49
- return super()
47
+ super()
48
+ else
49
+ calculate(:count, column_name)
50
50
  end
51
-
52
- calculate(:count, column_name)
53
51
  end
54
52
 
55
53
  # Calculates the average value on a given column. Returns +nil+ if there's
@@ -86,15 +84,13 @@ module ActiveRecord
86
84
  def sum(column_name = nil)
87
85
  if block_given?
88
86
  unless column_name.nil?
89
- ActiveSupport::Deprecation.warn \
90
- "When `sum' is called with a block, it ignores other arguments. " \
91
- "This behavior is now deprecated and will result in an ArgumentError in Rails 6.0."
87
+ raise ArgumentError, "Column name argument is not supported when a block is passed."
92
88
  end
93
89
 
94
- return super()
90
+ super()
91
+ else
92
+ calculate(:sum, column_name)
95
93
  end
96
-
97
- calculate(:sum, column_name)
98
94
  end
99
95
 
100
96
  # This calculates aggregate values in the given column. Methods for #count, #sum, #average,
@@ -133,11 +129,12 @@ module ActiveRecord
133
129
  relation = apply_join_dependency
134
130
 
135
131
  if operation.to_s.downcase == "count"
136
- relation.distinct!
137
- # PostgreSQL: ORDER BY expressions must appear in SELECT list when using DISTINCT
138
- if (column_name == :all || column_name.nil?) && select_values.empty?
139
- relation.order_values = []
132
+ unless distinct_value || distinct_select?(column_name || select_for_count)
133
+ relation.distinct!
134
+ relation.select_values = [ klass.primary_key || table[Arel.star] ]
140
135
  end
136
+ # PostgreSQL: ORDER BY expressions must appear in SELECT list when using DISTINCT
137
+ relation.order_values = []
141
138
  end
142
139
 
143
140
  relation.calculate(operation, column_name)
@@ -190,7 +187,7 @@ module ActiveRecord
190
187
  relation = apply_join_dependency
191
188
  relation.pluck(*column_names)
192
189
  else
193
- klass.enforce_raw_sql_whitelist(column_names)
190
+ klass.disallow_raw_sql!(column_names)
194
191
  relation = spawn
195
192
  relation.select_values = column_names
196
193
  result = skip_query_cache_if_necessary { klass.connection.select_all(relation.arel, nil) }
@@ -198,6 +195,24 @@ module ActiveRecord
198
195
  end
199
196
  end
200
197
 
198
+ # Pick the value(s) from the named column(s) in the current relation.
199
+ # This is short-hand for <tt>relation.limit(1).pluck(*column_names).first</tt>, and is primarily useful
200
+ # when you have a relation that's already narrowed down to a single row.
201
+ #
202
+ # Just like #pluck, #pick will only load the actual value, not the entire record object, so it's also
203
+ # more efficient. The value is, again like with pluck, typecast by the column type.
204
+ #
205
+ # Person.where(id: 1).pick(:name)
206
+ # # SELECT people.name FROM people WHERE id = 1 LIMIT 1
207
+ # # => 'David'
208
+ #
209
+ # Person.where(id: 1).pick(:name, :email_address)
210
+ # # SELECT people.name, people.email_address FROM people WHERE id = 1 LIMIT 1
211
+ # # => [ 'David', 'david@loudthinking.com' ]
212
+ def pick(*column_names)
213
+ limit(1).pluck(*column_names).first
214
+ end
215
+
201
216
  # Pluck all the ID's for the relation using the table's primary key
202
217
  #
203
218
  # Person.ids # SELECT people.id FROM people
@@ -245,10 +260,8 @@ module ActiveRecord
245
260
  def aggregate_column(column_name)
246
261
  return column_name if Arel::Expressions === column_name
247
262
 
248
- if @klass.has_attribute?(column_name) || @klass.attribute_alias?(column_name)
249
- @klass.arel_attribute(column_name)
250
- else
251
- Arel.sql(column_name == :all ? "*" : column_name.to_s)
263
+ arel_column(column_name.to_s) do |name|
264
+ Arel.sql(column_name == :all ? "*" : name)
252
265
  end
253
266
  end
254
267
 
@@ -293,25 +306,22 @@ module ActiveRecord
293
306
  end
294
307
 
295
308
  def execute_grouped_calculation(operation, column_name, distinct) #:nodoc:
296
- group_attrs = group_values
309
+ group_fields = group_values
297
310
 
298
- if group_attrs.first.respond_to?(:to_sym)
299
- association = @klass._reflect_on_association(group_attrs.first)
300
- associated = group_attrs.size == 1 && association && association.belongs_to? # only count belongs_to associations
301
- group_fields = Array(associated ? association.foreign_key : group_attrs)
302
- else
303
- group_fields = group_attrs
311
+ if group_fields.size == 1 && group_fields.first.respond_to?(:to_sym)
312
+ association = klass._reflect_on_association(group_fields.first)
313
+ associated = association && association.belongs_to? # only count belongs_to associations
314
+ group_fields = Array(association.foreign_key) if associated
304
315
  end
305
316
  group_fields = arel_columns(group_fields)
306
317
 
307
- group_aliases = group_fields.map { |field| column_alias_for(field) }
318
+ group_aliases = group_fields.map { |field|
319
+ field = connection.visitor.compile(field) if Arel.arel_node?(field)
320
+ column_alias_for(field.to_s.downcase)
321
+ }
308
322
  group_columns = group_aliases.zip(group_fields)
309
323
 
310
- if operation == "count" && column_name == :all
311
- aggregate_alias = "count_all"
312
- else
313
- aggregate_alias = column_alias_for([operation, column_name].join(" "))
314
- end
324
+ aggregate_alias = column_alias_for("#{operation} #{column_name.to_s.downcase}")
315
325
 
316
326
  select_values = [
317
327
  operation_over_aggregate_column(
@@ -356,25 +366,21 @@ module ActiveRecord
356
366
  end]
357
367
  end
358
368
 
359
- # Converts the given keys to the value that the database adapter returns as
369
+ # Converts the given field to the value that the database adapter returns as
360
370
  # a usable column name:
361
371
  #
362
372
  # column_alias_for("users.id") # => "users_id"
363
373
  # column_alias_for("sum(id)") # => "sum_id"
364
374
  # column_alias_for("count(distinct users.id)") # => "count_distinct_users_id"
365
375
  # column_alias_for("count(*)") # => "count_all"
366
- def column_alias_for(keys)
367
- if keys.respond_to? :name
368
- keys = "#{keys.relation.name}.#{keys.name}"
369
- end
370
-
371
- table_name = keys.to_s.downcase
372
- table_name.gsub!(/\*/, "all")
373
- table_name.gsub!(/\W+/, " ")
374
- table_name.strip!
375
- table_name.gsub!(/ +/, "_")
376
-
377
- @klass.connection.table_alias_for(table_name)
376
+ def column_alias_for(field)
377
+ column_alias = +field
378
+ column_alias.gsub!(/\*/, "all")
379
+ column_alias.gsub!(/\W+/, " ")
380
+ column_alias.strip!
381
+ column_alias.gsub!(/ +/, "_")
382
+
383
+ connection.table_alias_for(column_alias)
378
384
  end
379
385
 
380
386
  def type_for(field, &block)
@@ -386,7 +392,7 @@ module ActiveRecord
386
392
  case operation
387
393
  when "count" then value.to_i
388
394
  when "sum" then type.deserialize(value || 0)
389
- when "average" then value && value.respond_to?(:to_d) ? value.to_d : value
395
+ when "average" then value&.respond_to?(:to_d) ? value.to_d : value
390
396
  else type.deserialize(value)
391
397
  end
392
398
  end
@@ -402,16 +408,17 @@ module ActiveRecord
402
408
 
403
409
  def build_count_subquery(relation, column_name, distinct)
404
410
  if column_name == :all
411
+ column_alias = Arel.star
405
412
  relation.select_values = [ Arel.sql(FinderMethods::ONE_AS_ONE) ] unless distinct
406
413
  else
407
414
  column_alias = Arel.sql("count_column")
408
415
  relation.select_values = [ aggregate_column(column_name).as(column_alias) ]
409
416
  end
410
417
 
411
- subquery = relation.arel.as(Arel.sql("subquery_for_count"))
412
- select_value = operation_over_aggregate_column(column_alias || Arel.star, "count", false)
418
+ subquery_alias = Arel.sql("subquery_for_count")
419
+ select_value = operation_over_aggregate_column(column_alias, "count", false)
413
420
 
414
- Arel::SelectManager.new(subquery).project(select_value)
421
+ relation.build_subquery(subquery_alias, select_value)
415
422
  end
416
423
  end
417
424
  end
@@ -1,5 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require "mutex_m"
4
+
3
5
  module ActiveRecord
4
6
  module Delegation # :nodoc:
5
7
  module DelegateCache # :nodoc:
@@ -18,7 +20,7 @@ module ActiveRecord
18
20
  include ClassSpecificRelation
19
21
  }
20
22
  include_relation_methods(delegate)
21
- mangled_name = klass.name.gsub("::".freeze, "_".freeze)
23
+ mangled_name = klass.name.gsub("::", "_")
22
24
  const_set mangled_name, delegate
23
25
  private_constant mangled_name
24
26
 
@@ -31,35 +33,47 @@ module ActiveRecord
31
33
  super
32
34
  end
33
35
 
36
+ def generate_relation_method(method)
37
+ generated_relation_methods.generate_method(method)
38
+ end
39
+
34
40
  protected
35
41
  def include_relation_methods(delegate)
36
- superclass.include_relation_methods(delegate) unless base_class == self
42
+ superclass.include_relation_methods(delegate) unless base_class?
37
43
  delegate.include generated_relation_methods
38
44
  end
39
45
 
40
46
  private
41
47
  def generated_relation_methods
42
- @generated_relation_methods ||= Module.new.tap do |mod|
43
- mod_name = "GeneratedRelationMethods"
44
- const_set mod_name, mod
45
- private_constant mod_name
48
+ @generated_relation_methods ||= GeneratedRelationMethods.new.tap do |mod|
49
+ const_set(:GeneratedRelationMethods, mod)
50
+ private_constant :GeneratedRelationMethods
46
51
  end
47
52
  end
53
+ end
54
+
55
+ class GeneratedRelationMethods < Module # :nodoc:
56
+ include Mutex_m
57
+
58
+ def generate_method(method)
59
+ synchronize do
60
+ return if method_defined?(method)
48
61
 
49
- def generate_relation_method(method)
50
62
  if /\A[a-zA-Z_]\w*[!?]?\z/.match?(method)
51
- generated_relation_methods.module_eval <<-RUBY, __FILE__, __LINE__ + 1
63
+ module_eval <<-RUBY, __FILE__, __LINE__ + 1
52
64
  def #{method}(*args, &block)
53
65
  scoping { klass.#{method}(*args, &block) }
54
66
  end
55
67
  RUBY
56
68
  else
57
- generated_relation_methods.send(:define_method, method) do |*args, &block|
69
+ define_method(method) do |*args, &block|
58
70
  scoping { klass.public_send(method, *args, &block) }
59
71
  end
60
72
  end
61
73
  end
74
+ end
62
75
  end
76
+ private_constant :GeneratedRelationMethods
63
77
 
64
78
  extend ActiveSupport::Concern
65
79
 
@@ -68,7 +82,7 @@ module ActiveRecord
68
82
  # may vary depending on the klass of a relation, so we create a subclass of Relation
69
83
  # for each different klass, and the delegations are compiled into that subclass only.
70
84
 
71
- delegate :to_xml, :encode_with, :length, :each, :uniq, :join,
85
+ delegate :to_xml, :encode_with, :length, :each, :join,
72
86
  :[], :&, :|, :+, :-, :sample, :reverse, :rotate, :compact, :in_groups, :in_groups_of,
73
87
  :to_sentence, :to_formatted_s, :as_json,
74
88
  :shuffle, :split, :slice, :index, :rindex, to: :records
@@ -78,49 +92,18 @@ module ActiveRecord
78
92
  module ClassSpecificRelation # :nodoc:
79
93
  extend ActiveSupport::Concern
80
94
 
81
- included do
82
- @delegation_mutex = Mutex.new
83
- end
84
-
85
95
  module ClassMethods # :nodoc:
86
96
  def name
87
97
  superclass.name
88
98
  end
89
-
90
- def delegate_to_scoped_klass(method)
91
- @delegation_mutex.synchronize do
92
- return if method_defined?(method)
93
-
94
- if /\A[a-zA-Z_]\w*[!?]?\z/.match?(method)
95
- module_eval <<-RUBY, __FILE__, __LINE__ + 1
96
- def #{method}(*args, &block)
97
- scoping { @klass.#{method}(*args, &block) }
98
- end
99
- RUBY
100
- else
101
- define_method method do |*args, &block|
102
- scoping { @klass.public_send(method, *args, &block) }
103
- end
104
- end
105
- end
106
- end
107
99
  end
108
100
 
109
101
  private
110
102
 
111
103
  def method_missing(method, *args, &block)
112
104
  if @klass.respond_to?(method)
113
- self.class.delegate_to_scoped_klass(method)
105
+ @klass.generate_relation_method(method)
114
106
  scoping { @klass.public_send(method, *args, &block) }
115
- elsif @delegate_to_klass && @klass.respond_to?(method, true)
116
- ActiveSupport::Deprecation.warn \
117
- "Delegating missing #{method} method to #{@klass}. " \
118
- "Accessibility of private/protected class methods in :scope is deprecated and will be removed in Rails 6.0."
119
- @klass.send(method, *args, &block)
120
- elsif arel.respond_to?(method)
121
- ActiveSupport::Deprecation.warn \
122
- "Delegating #{method} to arel is deprecated and will be removed in Rails 6.0."
123
- arel.public_send(method, *args, &block)
124
107
  else
125
108
  super
126
109
  end
@@ -141,7 +124,7 @@ module ActiveRecord
141
124
 
142
125
  private
143
126
  def respond_to_missing?(method, _)
144
- super || @klass.respond_to?(method) || arel.respond_to?(method)
127
+ super || @klass.respond_to?(method)
145
128
  end
146
129
  end
147
130
  end
@@ -7,8 +7,8 @@ module ActiveRecord
7
7
  ONE_AS_ONE = "1 AS one"
8
8
 
9
9
  # Find by id - This can either be a specific id (1), a list of ids (1, 5, 6), or an array of ids ([5, 6, 10]).
10
- # If one or more records can not be found for the requested ids, then RecordNotFound will be raised. If the primary key
11
- # is an integer, find by id coerces its arguments using +to_i+.
10
+ # If one or more records cannot be found for the requested ids, then ActiveRecord::RecordNotFound will be raised.
11
+ # If the primary key is an integer, find by id coerces its arguments by using +to_i+.
12
12
  #
13
13
  # Person.find(1) # returns the object for ID = 1
14
14
  # Person.find("1") # returns the object for ID = 1
@@ -79,17 +79,12 @@ module ActiveRecord
79
79
  # Post.find_by "published_at < ?", 2.weeks.ago
80
80
  def find_by(arg, *args)
81
81
  where(arg, *args).take
82
- rescue ::RangeError
83
- nil
84
82
  end
85
83
 
86
84
  # Like #find_by, except that if no record is found, raises
87
85
  # an ActiveRecord::RecordNotFound error.
88
86
  def find_by!(arg, *args)
89
87
  where(arg, *args).take!
90
- rescue ::RangeError
91
- raise RecordNotFound.new("Couldn't find #{@klass.name} with an out of range value",
92
- @klass.name, @klass.primary_key)
93
88
  end
94
89
 
95
90
  # Gives a record (or N records if a parameter is supplied) without any implied
@@ -319,9 +314,7 @@ module ActiveRecord
319
314
 
320
315
  relation = construct_relation_for_exists(conditions)
321
316
 
322
- skip_query_cache_if_necessary { connection.select_one(relation.arel, "#{name} Exists") } ? true : false
323
- rescue ::RangeError
324
- false
317
+ skip_query_cache_if_necessary { connection.select_one(relation.arel, "#{name} Exists?") } ? true : false
325
318
  end
326
319
 
327
320
  # This method is called whenever no records are found with either a single
@@ -338,14 +331,14 @@ module ActiveRecord
338
331
  name = @klass.name
339
332
 
340
333
  if ids.nil?
341
- error = "Couldn't find #{name}".dup
334
+ error = +"Couldn't find #{name}"
342
335
  error << " with#{conditions}" if conditions
343
336
  raise RecordNotFound.new(error, name, key)
344
337
  elsif Array(ids).size == 1
345
338
  error = "Couldn't find #{name} with '#{key}'=#{ids}#{conditions}"
346
339
  raise RecordNotFound.new(error, name, key, ids)
347
340
  else
348
- error = "Couldn't find all #{name.pluralize} with '#{key}': ".dup
341
+ error = +"Couldn't find all #{name.pluralize} with '#{key}': "
349
342
  error << "(#{ids.join(", ")})#{conditions} (found #{result_size} results, but was looking for #{expected_size})."
350
343
  error << " Couldn't find #{name.pluralize(not_found_ids.size)} with #{key.to_s.pluralize(not_found_ids.size)} #{not_found_ids.join(', ')}." if not_found_ids
351
344
  raise RecordNotFound.new(error, name, key, ids)
@@ -359,8 +352,10 @@ module ActiveRecord
359
352
  end
360
353
 
361
354
  def construct_relation_for_exists(conditions)
355
+ conditions = sanitize_forbidden_attributes(conditions)
356
+
362
357
  if distinct_value && offset_value
363
- relation = limit(1)
358
+ relation = except(:order).limit!(1)
364
359
  else
365
360
  relation = except(:select, :distinct, :order)._select!(ONE_AS_ONE).limit!(1)
366
361
  end
@@ -375,15 +370,10 @@ module ActiveRecord
375
370
  relation
376
371
  end
377
372
 
378
- def construct_join_dependency
379
- including = eager_load_values + includes_values
380
- ActiveRecord::Associations::JoinDependency.new(
381
- klass, table, including
382
- )
383
- end
384
-
385
373
  def apply_join_dependency(eager_loading: group_values.empty?)
386
- join_dependency = construct_join_dependency
374
+ join_dependency = construct_join_dependency(
375
+ eager_load_values + includes_values, Arel::Nodes::OuterJoin
376
+ )
387
377
  relation = except(:includes, :eager_load, :preload).joins!(join_dependency)
388
378
 
389
379
  if eager_loading && !using_limitable_reflections?(join_dependency.reflections)
@@ -403,7 +393,7 @@ module ActiveRecord
403
393
 
404
394
  def limited_ids_for(relation)
405
395
  values = @klass.connection.columns_for_distinct(
406
- connection.column_name_from_arel_node(arel_attribute(primary_key)),
396
+ connection.visitor.compile(arel_attribute(primary_key)),
407
397
  relation.order_values
408
398
  )
409
399
 
@@ -437,9 +427,6 @@ module ActiveRecord
437
427
  else
438
428
  find_some(ids)
439
429
  end
440
- rescue ::RangeError
441
- error_message = "Couldn't find #{model_name} with an out of range ID"
442
- raise RecordNotFound.new(error_message, model_name, primary_key, ids)
443
430
  end
444
431
 
445
432
  def find_one(id)
@@ -555,8 +542,8 @@ module ActiveRecord
555
542
  end
556
543
 
557
544
  def ordered_relation
558
- if order_values.empty? && primary_key
559
- order(arel_attribute(primary_key).asc)
545
+ if order_values.empty? && (implicit_order_column || primary_key)
546
+ order(arel_attribute(implicit_order_column || primary_key).asc)
560
547
  else
561
548
  self
562
549
  end