activerecord 5.2.6 → 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 +609 -622
  3. data/MIT-LICENSE +3 -1
  4. data/README.rdoc +4 -2
  5. data/examples/performance.rb +1 -1
  6. data/lib/active_record/aggregations.rb +4 -2
  7. data/lib/active_record/associations/association.rb +52 -19
  8. data/lib/active_record/associations/association_scope.rb +4 -6
  9. data/lib/active_record/associations/belongs_to_association.rb +36 -42
  10. data/lib/active_record/associations/belongs_to_polymorphic_association.rb +0 -4
  11. data/lib/active_record/associations/builder/association.rb +14 -18
  12. data/lib/active_record/associations/builder/belongs_to.rb +19 -52
  13. data/lib/active_record/associations/builder/collection_association.rb +3 -13
  14. data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +17 -38
  15. data/lib/active_record/associations/builder/has_many.rb +2 -0
  16. data/lib/active_record/associations/builder/has_one.rb +35 -1
  17. data/lib/active_record/associations/builder/singular_association.rb +2 -0
  18. data/lib/active_record/associations/collection_association.rb +6 -21
  19. data/lib/active_record/associations/collection_proxy.rb +12 -15
  20. data/lib/active_record/associations/foreign_association.rb +7 -0
  21. data/lib/active_record/associations/has_many_association.rb +2 -10
  22. data/lib/active_record/associations/has_many_through_association.rb +14 -14
  23. data/lib/active_record/associations/has_one_association.rb +28 -30
  24. data/lib/active_record/associations/has_one_through_association.rb +5 -5
  25. data/lib/active_record/associations/join_dependency/join_association.rb +9 -10
  26. data/lib/active_record/associations/join_dependency/join_part.rb +2 -2
  27. data/lib/active_record/associations/join_dependency.rb +24 -28
  28. data/lib/active_record/associations/preloader/association.rb +38 -36
  29. data/lib/active_record/associations/preloader/through_association.rb +48 -39
  30. data/lib/active_record/associations/preloader.rb +40 -32
  31. data/lib/active_record/associations/singular_association.rb +2 -16
  32. data/lib/active_record/associations.rb +19 -14
  33. data/lib/active_record/attribute_assignment.rb +7 -10
  34. data/lib/active_record/attribute_methods/before_type_cast.rb +4 -1
  35. data/lib/active_record/attribute_methods/dirty.rb +111 -40
  36. data/lib/active_record/attribute_methods/primary_key.rb +15 -22
  37. data/lib/active_record/attribute_methods/query.rb +2 -3
  38. data/lib/active_record/attribute_methods/read.rb +15 -53
  39. data/lib/active_record/attribute_methods/serialization.rb +1 -1
  40. data/lib/active_record/attribute_methods/time_zone_conversion.rb +1 -1
  41. data/lib/active_record/attribute_methods/write.rb +17 -24
  42. data/lib/active_record/attribute_methods.rb +28 -100
  43. data/lib/active_record/attributes.rb +13 -0
  44. data/lib/active_record/autosave_association.rb +5 -9
  45. data/lib/active_record/base.rb +2 -3
  46. data/lib/active_record/callbacks.rb +5 -19
  47. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +94 -16
  48. data/lib/active_record/connection_adapters/abstract/database_limits.rb +17 -4
  49. data/lib/active_record/connection_adapters/abstract/database_statements.rb +95 -123
  50. data/lib/active_record/connection_adapters/abstract/query_cache.rb +17 -8
  51. data/lib/active_record/connection_adapters/abstract/quoting.rb +68 -17
  52. data/lib/active_record/connection_adapters/abstract/schema_creation.rb +19 -12
  53. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +76 -48
  54. data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +1 -3
  55. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +132 -53
  56. data/lib/active_record/connection_adapters/abstract/transaction.rb +96 -56
  57. data/lib/active_record/connection_adapters/abstract_adapter.rb +180 -47
  58. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +128 -194
  59. data/lib/active_record/connection_adapters/column.rb +17 -13
  60. data/lib/active_record/connection_adapters/connection_specification.rb +52 -42
  61. data/lib/active_record/connection_adapters/determine_if_preparable_visitor.rb +6 -10
  62. data/lib/active_record/connection_adapters/mysql/database_statements.rb +73 -13
  63. data/lib/active_record/connection_adapters/mysql/quoting.rb +44 -7
  64. data/lib/active_record/connection_adapters/mysql/schema_creation.rb +3 -4
  65. data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +40 -32
  66. data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +14 -6
  67. data/lib/active_record/connection_adapters/mysql/schema_statements.rb +129 -13
  68. data/lib/active_record/connection_adapters/mysql/type_metadata.rb +6 -10
  69. data/lib/active_record/connection_adapters/mysql2_adapter.rb +26 -9
  70. data/lib/active_record/connection_adapters/postgresql/column.rb +17 -31
  71. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +20 -1
  72. data/lib/active_record/connection_adapters/postgresql/oid/array.rb +1 -1
  73. data/lib/active_record/connection_adapters/postgresql/oid/bit.rb +1 -4
  74. data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +1 -1
  75. data/lib/active_record/connection_adapters/postgresql/oid/legacy_point.rb +1 -1
  76. data/lib/active_record/connection_adapters/postgresql/oid/money.rb +2 -2
  77. data/lib/active_record/connection_adapters/postgresql/oid/point.rb +1 -1
  78. data/lib/active_record/connection_adapters/postgresql/oid/range.rb +1 -1
  79. data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +9 -7
  80. data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +6 -3
  81. data/lib/active_record/connection_adapters/postgresql/quoting.rb +44 -7
  82. data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +12 -1
  83. data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +107 -91
  84. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +55 -53
  85. data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +24 -27
  86. data/lib/active_record/connection_adapters/postgresql_adapter.rb +160 -74
  87. data/lib/active_record/connection_adapters/schema_cache.rb +37 -14
  88. data/lib/active_record/connection_adapters/sql_type_metadata.rb +11 -8
  89. data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +118 -0
  90. data/lib/active_record/connection_adapters/sqlite3/quoting.rb +42 -6
  91. data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +42 -11
  92. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +125 -141
  93. data/lib/active_record/connection_handling.rb +149 -27
  94. data/lib/active_record/core.rb +100 -60
  95. data/lib/active_record/counter_cache.rb +4 -29
  96. data/lib/active_record/database_configurations/database_config.rb +37 -0
  97. data/lib/active_record/database_configurations/hash_config.rb +50 -0
  98. data/lib/active_record/database_configurations/url_config.rb +79 -0
  99. data/lib/active_record/database_configurations.rb +233 -0
  100. data/lib/active_record/dynamic_matchers.rb +1 -1
  101. data/lib/active_record/enum.rb +37 -7
  102. data/lib/active_record/errors.rb +15 -7
  103. data/lib/active_record/explain.rb +1 -1
  104. data/lib/active_record/fixture_set/model_metadata.rb +33 -0
  105. data/lib/active_record/fixture_set/render_context.rb +17 -0
  106. data/lib/active_record/fixture_set/table_row.rb +153 -0
  107. data/lib/active_record/fixture_set/table_rows.rb +47 -0
  108. data/lib/active_record/fixtures.rb +145 -472
  109. data/lib/active_record/gem_version.rb +3 -3
  110. data/lib/active_record/inheritance.rb +13 -3
  111. data/lib/active_record/insert_all.rb +179 -0
  112. data/lib/active_record/integration.rb +68 -16
  113. data/lib/active_record/internal_metadata.rb +10 -2
  114. data/lib/active_record/locking/optimistic.rb +5 -6
  115. data/lib/active_record/locking/pessimistic.rb +3 -3
  116. data/lib/active_record/log_subscriber.rb +7 -26
  117. data/lib/active_record/middleware/database_selector/resolver/session.rb +45 -0
  118. data/lib/active_record/middleware/database_selector/resolver.rb +92 -0
  119. data/lib/active_record/middleware/database_selector.rb +75 -0
  120. data/lib/active_record/migration/command_recorder.rb +50 -6
  121. data/lib/active_record/migration/compatibility.rb +76 -49
  122. data/lib/active_record/migration.rb +100 -81
  123. data/lib/active_record/model_schema.rb +30 -9
  124. data/lib/active_record/nested_attributes.rb +2 -2
  125. data/lib/active_record/no_touching.rb +7 -0
  126. data/lib/active_record/persistence.rb +228 -24
  127. data/lib/active_record/query_cache.rb +11 -4
  128. data/lib/active_record/querying.rb +32 -20
  129. data/lib/active_record/railtie.rb +80 -43
  130. data/lib/active_record/railties/collection_cache_association_loading.rb +34 -0
  131. data/lib/active_record/railties/controller_runtime.rb +30 -35
  132. data/lib/active_record/railties/databases.rake +196 -46
  133. data/lib/active_record/reflection.rb +32 -30
  134. data/lib/active_record/relation/batches.rb +13 -10
  135. data/lib/active_record/relation/calculations.rb +53 -47
  136. data/lib/active_record/relation/delegation.rb +26 -43
  137. data/lib/active_record/relation/finder_methods.rb +13 -26
  138. data/lib/active_record/relation/merger.rb +11 -20
  139. data/lib/active_record/relation/predicate_builder/array_handler.rb +5 -4
  140. data/lib/active_record/relation/predicate_builder/association_query_value.rb +1 -4
  141. data/lib/active_record/relation/predicate_builder/base_handler.rb +1 -2
  142. data/lib/active_record/relation/predicate_builder/basic_object_handler.rb +1 -2
  143. data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +1 -4
  144. data/lib/active_record/relation/predicate_builder/range_handler.rb +3 -23
  145. data/lib/active_record/relation/predicate_builder.rb +4 -6
  146. data/lib/active_record/relation/query_attribute.rb +13 -8
  147. data/lib/active_record/relation/query_methods.rb +189 -63
  148. data/lib/active_record/relation/spawn_methods.rb +1 -1
  149. data/lib/active_record/relation/where_clause.rb +14 -10
  150. data/lib/active_record/relation/where_clause_factory.rb +1 -2
  151. data/lib/active_record/relation.rb +310 -80
  152. data/lib/active_record/result.rb +30 -11
  153. data/lib/active_record/sanitization.rb +32 -40
  154. data/lib/active_record/schema.rb +2 -11
  155. data/lib/active_record/schema_dumper.rb +22 -7
  156. data/lib/active_record/schema_migration.rb +5 -1
  157. data/lib/active_record/scoping/default.rb +4 -5
  158. data/lib/active_record/scoping/named.rb +19 -15
  159. data/lib/active_record/scoping.rb +8 -8
  160. data/lib/active_record/statement_cache.rb +30 -3
  161. data/lib/active_record/store.rb +87 -8
  162. data/lib/active_record/table_metadata.rb +10 -17
  163. data/lib/active_record/tasks/database_tasks.rb +194 -25
  164. data/lib/active_record/tasks/mysql_database_tasks.rb +5 -5
  165. data/lib/active_record/tasks/postgresql_database_tasks.rb +5 -7
  166. data/lib/active_record/tasks/sqlite_database_tasks.rb +2 -8
  167. data/lib/active_record/test_databases.rb +23 -0
  168. data/lib/active_record/test_fixtures.rb +224 -0
  169. data/lib/active_record/timestamp.rb +39 -25
  170. data/lib/active_record/touch_later.rb +4 -2
  171. data/lib/active_record/transactions.rb +57 -66
  172. data/lib/active_record/translation.rb +1 -1
  173. data/lib/active_record/type/adapter_specific_registry.rb +1 -8
  174. data/lib/active_record/type.rb +3 -4
  175. data/lib/active_record/type_caster/connection.rb +15 -14
  176. data/lib/active_record/type_caster/map.rb +1 -4
  177. data/lib/active_record/validations/uniqueness.rb +15 -27
  178. data/lib/active_record/validations.rb +1 -0
  179. data/lib/active_record.rb +9 -2
  180. data/lib/arel/alias_predication.rb +9 -0
  181. data/lib/arel/attributes/attribute.rb +37 -0
  182. data/lib/arel/attributes.rb +22 -0
  183. data/lib/arel/collectors/bind.rb +24 -0
  184. data/lib/arel/collectors/composite.rb +31 -0
  185. data/lib/arel/collectors/plain_string.rb +20 -0
  186. data/lib/arel/collectors/sql_string.rb +20 -0
  187. data/lib/arel/collectors/substitute_binds.rb +28 -0
  188. data/lib/arel/crud.rb +42 -0
  189. data/lib/arel/delete_manager.rb +18 -0
  190. data/lib/arel/errors.rb +9 -0
  191. data/lib/arel/expressions.rb +29 -0
  192. data/lib/arel/factory_methods.rb +49 -0
  193. data/lib/arel/insert_manager.rb +49 -0
  194. data/lib/arel/math.rb +45 -0
  195. data/lib/arel/nodes/and.rb +32 -0
  196. data/lib/arel/nodes/ascending.rb +23 -0
  197. data/lib/arel/nodes/binary.rb +52 -0
  198. data/lib/arel/nodes/bind_param.rb +36 -0
  199. data/lib/arel/nodes/case.rb +55 -0
  200. data/lib/arel/nodes/casted.rb +50 -0
  201. data/lib/arel/nodes/comment.rb +29 -0
  202. data/lib/arel/nodes/count.rb +12 -0
  203. data/lib/arel/nodes/delete_statement.rb +45 -0
  204. data/lib/arel/nodes/descending.rb +23 -0
  205. data/lib/arel/nodes/equality.rb +18 -0
  206. data/lib/arel/nodes/extract.rb +24 -0
  207. data/lib/arel/nodes/false.rb +16 -0
  208. data/lib/arel/nodes/full_outer_join.rb +8 -0
  209. data/lib/arel/nodes/function.rb +44 -0
  210. data/lib/arel/nodes/grouping.rb +8 -0
  211. data/lib/arel/nodes/in.rb +8 -0
  212. data/lib/arel/nodes/infix_operation.rb +80 -0
  213. data/lib/arel/nodes/inner_join.rb +8 -0
  214. data/lib/arel/nodes/insert_statement.rb +37 -0
  215. data/lib/arel/nodes/join_source.rb +20 -0
  216. data/lib/arel/nodes/matches.rb +18 -0
  217. data/lib/arel/nodes/named_function.rb +23 -0
  218. data/lib/arel/nodes/node.rb +50 -0
  219. data/lib/arel/nodes/node_expression.rb +13 -0
  220. data/lib/arel/nodes/outer_join.rb +8 -0
  221. data/lib/arel/nodes/over.rb +15 -0
  222. data/lib/arel/nodes/regexp.rb +16 -0
  223. data/lib/arel/nodes/right_outer_join.rb +8 -0
  224. data/lib/arel/nodes/select_core.rb +67 -0
  225. data/lib/arel/nodes/select_statement.rb +41 -0
  226. data/lib/arel/nodes/sql_literal.rb +16 -0
  227. data/lib/arel/nodes/string_join.rb +11 -0
  228. data/lib/arel/nodes/table_alias.rb +27 -0
  229. data/lib/arel/nodes/terminal.rb +16 -0
  230. data/lib/arel/nodes/true.rb +16 -0
  231. data/lib/arel/nodes/unary.rb +45 -0
  232. data/lib/arel/nodes/unary_operation.rb +20 -0
  233. data/lib/arel/nodes/unqualified_column.rb +22 -0
  234. data/lib/arel/nodes/update_statement.rb +41 -0
  235. data/lib/arel/nodes/values_list.rb +9 -0
  236. data/lib/arel/nodes/window.rb +126 -0
  237. data/lib/arel/nodes/with.rb +11 -0
  238. data/lib/arel/nodes.rb +68 -0
  239. data/lib/arel/order_predications.rb +13 -0
  240. data/lib/arel/predications.rb +257 -0
  241. data/lib/arel/select_manager.rb +271 -0
  242. data/lib/arel/table.rb +110 -0
  243. data/lib/arel/tree_manager.rb +72 -0
  244. data/lib/arel/update_manager.rb +34 -0
  245. data/lib/arel/visitors/depth_first.rb +204 -0
  246. data/lib/arel/visitors/dot.rb +297 -0
  247. data/lib/arel/visitors/ibm_db.rb +34 -0
  248. data/lib/arel/visitors/informix.rb +62 -0
  249. data/lib/arel/visitors/mssql.rb +157 -0
  250. data/lib/arel/visitors/mysql.rb +83 -0
  251. data/lib/arel/visitors/oracle.rb +159 -0
  252. data/lib/arel/visitors/oracle12.rb +66 -0
  253. data/lib/arel/visitors/postgresql.rb +110 -0
  254. data/lib/arel/visitors/sqlite.rb +39 -0
  255. data/lib/arel/visitors/to_sql.rb +889 -0
  256. data/lib/arel/visitors/visitor.rb +46 -0
  257. data/lib/arel/visitors/where_sql.rb +23 -0
  258. data/lib/arel/visitors.rb +20 -0
  259. data/lib/arel/window_predications.rb +9 -0
  260. data/lib/arel.rb +51 -0
  261. data/lib/rails/generators/active_record/migration/migration_generator.rb +2 -5
  262. data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb.tt +1 -1
  263. data/lib/rails/generators/active_record/migration/templates/migration.rb.tt +4 -2
  264. data/lib/rails/generators/active_record/migration.rb +14 -1
  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 +108 -26
  268. data/lib/active_record/collection_cache_key.rb +0 -53
@@ -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,
@@ -191,7 +187,7 @@ module ActiveRecord
191
187
  relation = apply_join_dependency
192
188
  relation.pluck(*column_names)
193
189
  else
194
- klass.enforce_raw_sql_whitelist(column_names)
190
+ klass.disallow_raw_sql!(column_names)
195
191
  relation = spawn
196
192
  relation.select_values = column_names
197
193
  result = skip_query_cache_if_necessary { klass.connection.select_all(relation.arel, nil) }
@@ -199,6 +195,24 @@ module ActiveRecord
199
195
  end
200
196
  end
201
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
+
202
216
  # Pluck all the ID's for the relation using the table's primary key
203
217
  #
204
218
  # Person.ids # SELECT people.id FROM people
@@ -246,10 +260,8 @@ module ActiveRecord
246
260
  def aggregate_column(column_name)
247
261
  return column_name if Arel::Expressions === column_name
248
262
 
249
- if @klass.has_attribute?(column_name) || @klass.attribute_alias?(column_name)
250
- @klass.arel_attribute(column_name)
251
- else
252
- 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)
253
265
  end
254
266
  end
255
267
 
@@ -294,25 +306,22 @@ module ActiveRecord
294
306
  end
295
307
 
296
308
  def execute_grouped_calculation(operation, column_name, distinct) #:nodoc:
297
- group_attrs = group_values
309
+ group_fields = group_values
298
310
 
299
- if group_attrs.first.respond_to?(:to_sym)
300
- association = @klass._reflect_on_association(group_attrs.first)
301
- associated = group_attrs.size == 1 && association && association.belongs_to? # only count belongs_to associations
302
- group_fields = Array(associated ? association.foreign_key : group_attrs)
303
- else
304
- 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
305
315
  end
306
316
  group_fields = arel_columns(group_fields)
307
317
 
308
- 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
+ }
309
322
  group_columns = group_aliases.zip(group_fields)
310
323
 
311
- if operation == "count" && column_name == :all
312
- aggregate_alias = "count_all"
313
- else
314
- aggregate_alias = column_alias_for([operation, column_name].join(" "))
315
- end
324
+ aggregate_alias = column_alias_for("#{operation} #{column_name.to_s.downcase}")
316
325
 
317
326
  select_values = [
318
327
  operation_over_aggregate_column(
@@ -357,25 +366,21 @@ module ActiveRecord
357
366
  end]
358
367
  end
359
368
 
360
- # 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
361
370
  # a usable column name:
362
371
  #
363
372
  # column_alias_for("users.id") # => "users_id"
364
373
  # column_alias_for("sum(id)") # => "sum_id"
365
374
  # column_alias_for("count(distinct users.id)") # => "count_distinct_users_id"
366
375
  # column_alias_for("count(*)") # => "count_all"
367
- def column_alias_for(keys)
368
- if keys.respond_to? :name
369
- keys = "#{keys.relation.name}.#{keys.name}"
370
- end
371
-
372
- table_name = keys.to_s.downcase
373
- table_name.gsub!(/\*/, "all")
374
- table_name.gsub!(/\W+/, " ")
375
- table_name.strip!
376
- table_name.gsub!(/ +/, "_")
377
-
378
- @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)
379
384
  end
380
385
 
381
386
  def type_for(field, &block)
@@ -387,7 +392,7 @@ module ActiveRecord
387
392
  case operation
388
393
  when "count" then value.to_i
389
394
  when "sum" then type.deserialize(value || 0)
390
- 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
391
396
  else type.deserialize(value)
392
397
  end
393
398
  end
@@ -403,16 +408,17 @@ module ActiveRecord
403
408
 
404
409
  def build_count_subquery(relation, column_name, distinct)
405
410
  if column_name == :all
411
+ column_alias = Arel.star
406
412
  relation.select_values = [ Arel.sql(FinderMethods::ONE_AS_ONE) ] unless distinct
407
413
  else
408
414
  column_alias = Arel.sql("count_column")
409
415
  relation.select_values = [ aggregate_column(column_name).as(column_alias) ]
410
416
  end
411
417
 
412
- subquery = relation.arel.as(Arel.sql("subquery_for_count"))
413
- 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)
414
420
 
415
- Arel::SelectManager.new(subquery).project(select_value)
421
+ relation.build_subquery(subquery_alias, select_value)
416
422
  end
417
423
  end
418
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,6 +352,8 @@ 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
358
  relation = except(:order).limit!(1)
364
359
  else
@@ -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
@@ -117,18 +117,16 @@ module ActiveRecord
117
117
  if other.klass == relation.klass
118
118
  relation.joins!(*other.joins_values)
119
119
  else
120
- joins_dependency = other.joins_values.map do |join|
120
+ associations, others = other.joins_values.partition do |join|
121
121
  case join
122
- when Hash, Symbol, Array
123
- ActiveRecord::Associations::JoinDependency.new(
124
- other.klass, other.table, join
125
- )
126
- else
127
- join
122
+ when Hash, Symbol, Array; true
128
123
  end
129
124
  end
130
125
 
131
- relation.joins!(*joins_dependency)
126
+ join_dependency = other.construct_join_dependency(
127
+ associations, Arel::Nodes::InnerJoin
128
+ )
129
+ relation.joins!(join_dependency, *others)
132
130
  end
133
131
  end
134
132
 
@@ -138,18 +136,11 @@ module ActiveRecord
138
136
  if other.klass == relation.klass
139
137
  relation.left_outer_joins!(*other.left_outer_joins_values)
140
138
  else
141
- joins_dependency = other.left_outer_joins_values.map do |join|
142
- case join
143
- when Hash, Symbol, Array
144
- ActiveRecord::Associations::JoinDependency.new(
145
- other.klass, other.table, join
146
- )
147
- else
148
- join
149
- end
150
- end
151
-
152
- relation.left_outer_joins!(*joins_dependency)
139
+ associations = other.left_outer_joins_values
140
+ join_dependency = other.construct_join_dependency(
141
+ associations, Arel::Nodes::OuterJoin
142
+ )
143
+ relation.joins!(join_dependency)
153
144
  end
154
145
  end
155
146
 
@@ -1,5 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require "active_support/core_ext/array/extract"
4
+
3
5
  module ActiveRecord
4
6
  class PredicateBuilder
5
7
  class ArrayHandler # :nodoc:
@@ -11,8 +13,8 @@ module ActiveRecord
11
13
  return attribute.in([]) if value.empty?
12
14
 
13
15
  values = value.map { |x| x.is_a?(Base) ? x.id : x }
14
- nils, values = values.partition(&:nil?)
15
- ranges, values = values.partition { |v| v.is_a?(Range) }
16
+ nils = values.extract!(&:nil?)
17
+ ranges = values.extract! { |v| v.is_a?(Range) }
16
18
 
17
19
  values_predicate =
18
20
  case values.length
@@ -34,8 +36,7 @@ module ActiveRecord
34
36
  array_predicates.inject(&:or)
35
37
  end
36
38
 
37
- protected
38
-
39
+ private
39
40
  attr_reader :predicate_builder
40
41
 
41
42
  module NullPredicate # :nodoc:
@@ -12,12 +12,9 @@ module ActiveRecord
12
12
  [associated_table.association_join_foreign_key.to_s => ids]
13
13
  end
14
14
 
15
- # TODO Change this to private once we've dropped Ruby 2.2 support.
16
- # Workaround for Ruby 2.2 "private attribute?" warning.
17
- protected
15
+ private
18
16
  attr_reader :associated_table, :value
19
17
 
20
- private
21
18
  def ids
22
19
  case value
23
20
  when Relation
@@ -11,8 +11,7 @@ module ActiveRecord
11
11
  predicate_builder.build(attribute, value.id)
12
12
  end
13
13
 
14
- protected
15
-
14
+ private
16
15
  attr_reader :predicate_builder
17
16
  end
18
17
  end
@@ -12,8 +12,7 @@ module ActiveRecord
12
12
  attribute.eq(bind)
13
13
  end
14
14
 
15
- protected
16
-
15
+ private
17
16
  attr_reader :predicate_builder
18
17
  end
19
18
  end
@@ -17,12 +17,9 @@ module ActiveRecord
17
17
  end
18
18
  end
19
19
 
20
- # TODO Change this to private once we've dropped Ruby 2.2 support.
21
- # Workaround for Ruby 2.2 "private attribute?" warning.
22
- protected
20
+ private
23
21
  attr_reader :associated_table, :values
24
22
 
25
- private
26
23
  def type_to_ids_mapping
27
24
  default_hash = Hash.new { |hsh, key| hsh[key] = [] }
28
25
  values.each_with_object(default_hash) do |value, hash|
@@ -3,11 +3,7 @@
3
3
  module ActiveRecord
4
4
  class PredicateBuilder
5
5
  class RangeHandler # :nodoc:
6
- class RangeWithBinds < Struct.new(:begin, :end)
7
- def exclude_end?
8
- false
9
- end
10
- end
6
+ RangeWithBinds = Struct.new(:begin, :end, :exclude_end?)
11
7
 
12
8
  def initialize(predicate_builder)
13
9
  @predicate_builder = predicate_builder
@@ -16,26 +12,10 @@ module ActiveRecord
16
12
  def call(attribute, value)
17
13
  begin_bind = predicate_builder.build_bind_attribute(attribute.name, value.begin)
18
14
  end_bind = predicate_builder.build_bind_attribute(attribute.name, value.end)
19
-
20
- if begin_bind.value.infinity?
21
- if end_bind.value.infinity?
22
- attribute.not_in([])
23
- elsif value.exclude_end?
24
- attribute.lt(end_bind)
25
- else
26
- attribute.lteq(end_bind)
27
- end
28
- elsif end_bind.value.infinity?
29
- attribute.gteq(begin_bind)
30
- elsif value.exclude_end?
31
- attribute.gteq(begin_bind).and(attribute.lt(end_bind))
32
- else
33
- attribute.between(RangeWithBinds.new(begin_bind, end_bind))
34
- end
15
+ attribute.between(RangeWithBinds.new(begin_bind, end_bind, value.exclude_end?))
35
16
  end
36
17
 
37
- protected
38
-
18
+ private
39
19
  attr_reader :predicate_builder
40
20
  end
41
21
  end
@@ -27,7 +27,7 @@ module ActiveRecord
27
27
  key
28
28
  else
29
29
  key = key.to_s
30
- key.split(".".freeze).first if key.include?(".".freeze)
30
+ key.split(".").first if key.include?(".")
31
31
  end
32
32
  end.compact
33
33
  end
@@ -62,9 +62,6 @@ module ActiveRecord
62
62
  end
63
63
 
64
64
  protected
65
-
66
- attr_reader :table
67
-
68
65
  def expand_from_hash(attributes)
69
66
  return ["1=0"] if attributes.empty?
70
67
 
@@ -115,6 +112,7 @@ module ActiveRecord
115
112
  end
116
113
 
117
114
  private
115
+ attr_reader :table
118
116
 
119
117
  def associated_predicate_builder(association_name)
120
118
  self.class.new(table.associated_table(association_name))
@@ -122,11 +120,11 @@ module ActiveRecord
122
120
 
123
121
  def convert_dot_notation_to_hash(attributes)
124
122
  dot_notation = attributes.select do |k, v|
125
- k.include?(".".freeze) && !v.is_a?(Hash)
123
+ k.include?(".") && !v.is_a?(Hash)
126
124
  end
127
125
 
128
126
  dot_notation.each_key do |key|
129
- table_name, column_name = key.split(".".freeze)
127
+ table_name, column_name = key.split(".")
130
128
  value = attributes.delete(key)
131
129
  attributes[table_name] ||= {}
132
130