activerecord 5.2.8.1 → 6.0.6.1

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 (294) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +938 -573
  3. data/MIT-LICENSE +3 -1
  4. data/README.rdoc +5 -3
  5. data/examples/performance.rb +1 -1
  6. data/lib/active_record/advisory_lock_base.rb +18 -0
  7. data/lib/active_record/aggregations.rb +4 -3
  8. data/lib/active_record/association_relation.rb +10 -8
  9. data/lib/active_record/associations/alias_tracker.rb +0 -1
  10. data/lib/active_record/associations/association.rb +55 -19
  11. data/lib/active_record/associations/association_scope.rb +11 -7
  12. data/lib/active_record/associations/belongs_to_association.rb +36 -42
  13. data/lib/active_record/associations/belongs_to_polymorphic_association.rb +0 -4
  14. data/lib/active_record/associations/builder/association.rb +14 -18
  15. data/lib/active_record/associations/builder/belongs_to.rb +19 -52
  16. data/lib/active_record/associations/builder/collection_association.rb +3 -13
  17. data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +17 -40
  18. data/lib/active_record/associations/builder/has_many.rb +2 -0
  19. data/lib/active_record/associations/builder/has_one.rb +35 -1
  20. data/lib/active_record/associations/builder/singular_association.rb +2 -0
  21. data/lib/active_record/associations/collection_association.rb +19 -23
  22. data/lib/active_record/associations/collection_proxy.rb +14 -17
  23. data/lib/active_record/associations/foreign_association.rb +7 -0
  24. data/lib/active_record/associations/has_many_association.rb +2 -11
  25. data/lib/active_record/associations/has_many_through_association.rb +14 -14
  26. data/lib/active_record/associations/has_one_association.rb +28 -30
  27. data/lib/active_record/associations/has_one_through_association.rb +5 -5
  28. data/lib/active_record/associations/join_dependency/join_association.rb +16 -10
  29. data/lib/active_record/associations/join_dependency/join_part.rb +4 -4
  30. data/lib/active_record/associations/join_dependency.rb +47 -30
  31. data/lib/active_record/associations/preloader/association.rb +61 -41
  32. data/lib/active_record/associations/preloader/through_association.rb +48 -39
  33. data/lib/active_record/associations/preloader.rb +44 -33
  34. data/lib/active_record/associations/singular_association.rb +2 -16
  35. data/lib/active_record/associations/through_association.rb +1 -1
  36. data/lib/active_record/associations.rb +21 -16
  37. data/lib/active_record/attribute_assignment.rb +7 -11
  38. data/lib/active_record/attribute_decorators.rb +0 -2
  39. data/lib/active_record/attribute_methods/before_type_cast.rb +4 -2
  40. data/lib/active_record/attribute_methods/dirty.rb +111 -40
  41. data/lib/active_record/attribute_methods/primary_key.rb +15 -24
  42. data/lib/active_record/attribute_methods/query.rb +2 -3
  43. data/lib/active_record/attribute_methods/read.rb +15 -54
  44. data/lib/active_record/attribute_methods/serialization.rb +1 -2
  45. data/lib/active_record/attribute_methods/time_zone_conversion.rb +1 -3
  46. data/lib/active_record/attribute_methods/write.rb +17 -25
  47. data/lib/active_record/attribute_methods.rb +28 -100
  48. data/lib/active_record/attributes.rb +13 -1
  49. data/lib/active_record/autosave_association.rb +12 -14
  50. data/lib/active_record/base.rb +2 -3
  51. data/lib/active_record/callbacks.rb +6 -21
  52. data/lib/active_record/coders/yaml_column.rb +15 -6
  53. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +109 -18
  54. data/lib/active_record/connection_adapters/abstract/database_limits.rb +17 -4
  55. data/lib/active_record/connection_adapters/abstract/database_statements.rb +102 -124
  56. data/lib/active_record/connection_adapters/abstract/query_cache.rb +18 -9
  57. data/lib/active_record/connection_adapters/abstract/quoting.rb +77 -17
  58. data/lib/active_record/connection_adapters/abstract/schema_creation.rb +20 -14
  59. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +105 -72
  60. data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +1 -3
  61. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +175 -79
  62. data/lib/active_record/connection_adapters/abstract/transaction.rb +96 -57
  63. data/lib/active_record/connection_adapters/abstract_adapter.rb +197 -43
  64. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +149 -217
  65. data/lib/active_record/connection_adapters/column.rb +17 -13
  66. data/lib/active_record/connection_adapters/connection_specification.rb +54 -45
  67. data/lib/active_record/connection_adapters/determine_if_preparable_visitor.rb +6 -10
  68. data/lib/active_record/connection_adapters/mysql/column.rb +1 -1
  69. data/lib/active_record/connection_adapters/mysql/database_statements.rb +70 -14
  70. data/lib/active_record/connection_adapters/mysql/explain_pretty_printer.rb +0 -1
  71. data/lib/active_record/connection_adapters/mysql/quoting.rb +44 -7
  72. data/lib/active_record/connection_adapters/mysql/schema_creation.rb +4 -6
  73. data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +40 -32
  74. data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +14 -6
  75. data/lib/active_record/connection_adapters/mysql/schema_statements.rb +139 -19
  76. data/lib/active_record/connection_adapters/mysql/type_metadata.rb +6 -10
  77. data/lib/active_record/connection_adapters/mysql2_adapter.rb +26 -10
  78. data/lib/active_record/connection_adapters/postgresql/column.rb +17 -31
  79. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +26 -1
  80. data/lib/active_record/connection_adapters/postgresql/oid/array.rb +1 -2
  81. data/lib/active_record/connection_adapters/postgresql/oid/bit.rb +1 -4
  82. data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +8 -0
  83. data/lib/active_record/connection_adapters/postgresql/oid/enum.rb +0 -1
  84. data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +1 -2
  85. data/lib/active_record/connection_adapters/postgresql/oid/legacy_point.rb +1 -2
  86. data/lib/active_record/connection_adapters/postgresql/oid/oid.rb +1 -1
  87. data/lib/active_record/connection_adapters/postgresql/oid/point.rb +1 -2
  88. data/lib/active_record/connection_adapters/postgresql/oid/range.rb +25 -7
  89. data/lib/active_record/connection_adapters/postgresql/oid/specialized_string.rb +1 -1
  90. data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +9 -7
  91. data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +5 -3
  92. data/lib/active_record/connection_adapters/postgresql/quoting.rb +44 -7
  93. data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +1 -1
  94. data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +14 -3
  95. data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +107 -91
  96. data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +0 -1
  97. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +63 -75
  98. data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +24 -27
  99. data/lib/active_record/connection_adapters/postgresql/utils.rb +0 -1
  100. data/lib/active_record/connection_adapters/postgresql_adapter.rb +168 -75
  101. data/lib/active_record/connection_adapters/schema_cache.rb +37 -14
  102. data/lib/active_record/connection_adapters/sql_type_metadata.rb +11 -8
  103. data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +119 -0
  104. data/lib/active_record/connection_adapters/sqlite3/quoting.rb +42 -7
  105. data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +43 -12
  106. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +137 -147
  107. data/lib/active_record/connection_adapters/statement_pool.rb +0 -1
  108. data/lib/active_record/connection_handling.rb +139 -26
  109. data/lib/active_record/core.rb +108 -67
  110. data/lib/active_record/counter_cache.rb +8 -30
  111. data/lib/active_record/database_configurations/database_config.rb +37 -0
  112. data/lib/active_record/database_configurations/hash_config.rb +50 -0
  113. data/lib/active_record/database_configurations/url_config.rb +78 -0
  114. data/lib/active_record/database_configurations.rb +233 -0
  115. data/lib/active_record/dynamic_matchers.rb +3 -4
  116. data/lib/active_record/enum.rb +44 -7
  117. data/lib/active_record/errors.rb +15 -7
  118. data/lib/active_record/explain.rb +1 -2
  119. data/lib/active_record/fixture_set/model_metadata.rb +33 -0
  120. data/lib/active_record/fixture_set/render_context.rb +17 -0
  121. data/lib/active_record/fixture_set/table_row.rb +152 -0
  122. data/lib/active_record/fixture_set/table_rows.rb +46 -0
  123. data/lib/active_record/fixtures.rb +144 -474
  124. data/lib/active_record/gem_version.rb +3 -3
  125. data/lib/active_record/inheritance.rb +13 -6
  126. data/lib/active_record/insert_all.rb +179 -0
  127. data/lib/active_record/integration.rb +68 -16
  128. data/lib/active_record/internal_metadata.rb +11 -3
  129. data/lib/active_record/locking/optimistic.rb +14 -7
  130. data/lib/active_record/locking/pessimistic.rb +3 -3
  131. data/lib/active_record/log_subscriber.rb +8 -27
  132. data/lib/active_record/middleware/database_selector/resolver/session.rb +45 -0
  133. data/lib/active_record/middleware/database_selector/resolver.rb +87 -0
  134. data/lib/active_record/middleware/database_selector.rb +74 -0
  135. data/lib/active_record/migration/command_recorder.rb +54 -22
  136. data/lib/active_record/migration/compatibility.rb +79 -52
  137. data/lib/active_record/migration/join_table.rb +0 -1
  138. data/lib/active_record/migration.rb +104 -85
  139. data/lib/active_record/model_schema.rb +62 -11
  140. data/lib/active_record/nested_attributes.rb +2 -4
  141. data/lib/active_record/no_touching.rb +9 -2
  142. data/lib/active_record/null_relation.rb +0 -1
  143. data/lib/active_record/persistence.rb +232 -29
  144. data/lib/active_record/query_cache.rb +11 -4
  145. data/lib/active_record/querying.rb +33 -21
  146. data/lib/active_record/railtie.rb +80 -61
  147. data/lib/active_record/railties/collection_cache_association_loading.rb +34 -0
  148. data/lib/active_record/railties/controller_runtime.rb +30 -35
  149. data/lib/active_record/railties/databases.rake +199 -46
  150. data/lib/active_record/reflection.rb +51 -51
  151. data/lib/active_record/relation/batches.rb +13 -11
  152. data/lib/active_record/relation/calculations.rb +55 -49
  153. data/lib/active_record/relation/delegation.rb +35 -50
  154. data/lib/active_record/relation/finder_methods.rb +23 -28
  155. data/lib/active_record/relation/from_clause.rb +4 -0
  156. data/lib/active_record/relation/merger.rb +12 -17
  157. data/lib/active_record/relation/predicate_builder/array_handler.rb +5 -4
  158. data/lib/active_record/relation/predicate_builder/association_query_value.rb +1 -4
  159. data/lib/active_record/relation/predicate_builder/base_handler.rb +1 -2
  160. data/lib/active_record/relation/predicate_builder/basic_object_handler.rb +1 -2
  161. data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +1 -4
  162. data/lib/active_record/relation/predicate_builder/range_handler.rb +3 -23
  163. data/lib/active_record/relation/predicate_builder.rb +5 -11
  164. data/lib/active_record/relation/query_attribute.rb +13 -8
  165. data/lib/active_record/relation/query_methods.rb +234 -69
  166. data/lib/active_record/relation/spawn_methods.rb +1 -2
  167. data/lib/active_record/relation/where_clause.rb +14 -11
  168. data/lib/active_record/relation/where_clause_factory.rb +1 -2
  169. data/lib/active_record/relation.rb +326 -81
  170. data/lib/active_record/result.rb +30 -12
  171. data/lib/active_record/sanitization.rb +32 -40
  172. data/lib/active_record/schema.rb +2 -11
  173. data/lib/active_record/schema_dumper.rb +22 -7
  174. data/lib/active_record/schema_migration.rb +6 -2
  175. data/lib/active_record/scoping/default.rb +4 -6
  176. data/lib/active_record/scoping/named.rb +25 -16
  177. data/lib/active_record/scoping.rb +8 -9
  178. data/lib/active_record/statement_cache.rb +30 -3
  179. data/lib/active_record/store.rb +87 -8
  180. data/lib/active_record/suppressor.rb +2 -2
  181. data/lib/active_record/table_metadata.rb +23 -15
  182. data/lib/active_record/tasks/database_tasks.rb +194 -25
  183. data/lib/active_record/tasks/mysql_database_tasks.rb +5 -6
  184. data/lib/active_record/tasks/postgresql_database_tasks.rb +5 -8
  185. data/lib/active_record/tasks/sqlite_database_tasks.rb +2 -9
  186. data/lib/active_record/test_databases.rb +23 -0
  187. data/lib/active_record/test_fixtures.rb +243 -0
  188. data/lib/active_record/timestamp.rb +39 -26
  189. data/lib/active_record/touch_later.rb +5 -4
  190. data/lib/active_record/transactions.rb +64 -73
  191. data/lib/active_record/translation.rb +1 -1
  192. data/lib/active_record/type/adapter_specific_registry.rb +3 -13
  193. data/lib/active_record/type/hash_lookup_type_map.rb +0 -1
  194. data/lib/active_record/type/serialized.rb +0 -1
  195. data/lib/active_record/type/time.rb +10 -0
  196. data/lib/active_record/type/type_map.rb +0 -1
  197. data/lib/active_record/type/unsigned_integer.rb +0 -1
  198. data/lib/active_record/type.rb +3 -5
  199. data/lib/active_record/type_caster/connection.rb +15 -14
  200. data/lib/active_record/type_caster/map.rb +1 -4
  201. data/lib/active_record/validations/associated.rb +0 -1
  202. data/lib/active_record/validations/uniqueness.rb +15 -27
  203. data/lib/active_record/validations.rb +3 -3
  204. data/lib/active_record.rb +10 -2
  205. data/lib/arel/alias_predication.rb +9 -0
  206. data/lib/arel/attributes/attribute.rb +37 -0
  207. data/lib/arel/attributes.rb +22 -0
  208. data/lib/arel/collectors/bind.rb +24 -0
  209. data/lib/arel/collectors/composite.rb +31 -0
  210. data/lib/arel/collectors/plain_string.rb +20 -0
  211. data/lib/arel/collectors/sql_string.rb +20 -0
  212. data/lib/arel/collectors/substitute_binds.rb +28 -0
  213. data/lib/arel/crud.rb +42 -0
  214. data/lib/arel/delete_manager.rb +18 -0
  215. data/lib/arel/errors.rb +9 -0
  216. data/lib/arel/expressions.rb +29 -0
  217. data/lib/arel/factory_methods.rb +49 -0
  218. data/lib/arel/insert_manager.rb +49 -0
  219. data/lib/arel/math.rb +45 -0
  220. data/lib/arel/nodes/and.rb +32 -0
  221. data/lib/arel/nodes/ascending.rb +23 -0
  222. data/lib/arel/nodes/binary.rb +52 -0
  223. data/lib/arel/nodes/bind_param.rb +36 -0
  224. data/lib/arel/nodes/case.rb +55 -0
  225. data/lib/arel/nodes/casted.rb +50 -0
  226. data/lib/arel/nodes/comment.rb +29 -0
  227. data/lib/arel/nodes/count.rb +12 -0
  228. data/lib/arel/nodes/delete_statement.rb +45 -0
  229. data/lib/arel/nodes/descending.rb +23 -0
  230. data/lib/arel/nodes/equality.rb +18 -0
  231. data/lib/arel/nodes/extract.rb +24 -0
  232. data/lib/arel/nodes/false.rb +16 -0
  233. data/lib/arel/nodes/full_outer_join.rb +8 -0
  234. data/lib/arel/nodes/function.rb +44 -0
  235. data/lib/arel/nodes/grouping.rb +8 -0
  236. data/lib/arel/nodes/in.rb +8 -0
  237. data/lib/arel/nodes/infix_operation.rb +80 -0
  238. data/lib/arel/nodes/inner_join.rb +8 -0
  239. data/lib/arel/nodes/insert_statement.rb +37 -0
  240. data/lib/arel/nodes/join_source.rb +20 -0
  241. data/lib/arel/nodes/matches.rb +18 -0
  242. data/lib/arel/nodes/named_function.rb +23 -0
  243. data/lib/arel/nodes/node.rb +50 -0
  244. data/lib/arel/nodes/node_expression.rb +13 -0
  245. data/lib/arel/nodes/outer_join.rb +8 -0
  246. data/lib/arel/nodes/over.rb +15 -0
  247. data/lib/arel/nodes/regexp.rb +16 -0
  248. data/lib/arel/nodes/right_outer_join.rb +8 -0
  249. data/lib/arel/nodes/select_core.rb +67 -0
  250. data/lib/arel/nodes/select_statement.rb +41 -0
  251. data/lib/arel/nodes/sql_literal.rb +16 -0
  252. data/lib/arel/nodes/string_join.rb +11 -0
  253. data/lib/arel/nodes/table_alias.rb +27 -0
  254. data/lib/arel/nodes/terminal.rb +16 -0
  255. data/lib/arel/nodes/true.rb +16 -0
  256. data/lib/arel/nodes/unary.rb +45 -0
  257. data/lib/arel/nodes/unary_operation.rb +20 -0
  258. data/lib/arel/nodes/unqualified_column.rb +22 -0
  259. data/lib/arel/nodes/update_statement.rb +41 -0
  260. data/lib/arel/nodes/values_list.rb +9 -0
  261. data/lib/arel/nodes/window.rb +126 -0
  262. data/lib/arel/nodes/with.rb +11 -0
  263. data/lib/arel/nodes.rb +68 -0
  264. data/lib/arel/order_predications.rb +13 -0
  265. data/lib/arel/predications.rb +256 -0
  266. data/lib/arel/select_manager.rb +271 -0
  267. data/lib/arel/table.rb +110 -0
  268. data/lib/arel/tree_manager.rb +72 -0
  269. data/lib/arel/update_manager.rb +34 -0
  270. data/lib/arel/visitors/depth_first.rb +203 -0
  271. data/lib/arel/visitors/dot.rb +296 -0
  272. data/lib/arel/visitors/ibm_db.rb +34 -0
  273. data/lib/arel/visitors/informix.rb +62 -0
  274. data/lib/arel/visitors/mssql.rb +156 -0
  275. data/lib/arel/visitors/mysql.rb +83 -0
  276. data/lib/arel/visitors/oracle.rb +158 -0
  277. data/lib/arel/visitors/oracle12.rb +65 -0
  278. data/lib/arel/visitors/postgresql.rb +109 -0
  279. data/lib/arel/visitors/sqlite.rb +38 -0
  280. data/lib/arel/visitors/to_sql.rb +888 -0
  281. data/lib/arel/visitors/visitor.rb +45 -0
  282. data/lib/arel/visitors/where_sql.rb +22 -0
  283. data/lib/arel/visitors.rb +20 -0
  284. data/lib/arel/window_predications.rb +9 -0
  285. data/lib/arel.rb +62 -0
  286. data/lib/rails/generators/active_record/application_record/application_record_generator.rb +0 -1
  287. data/lib/rails/generators/active_record/migration/migration_generator.rb +2 -5
  288. data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb.tt +1 -1
  289. data/lib/rails/generators/active_record/migration/templates/migration.rb.tt +4 -2
  290. data/lib/rails/generators/active_record/migration.rb +14 -2
  291. data/lib/rails/generators/active_record/model/model_generator.rb +1 -1
  292. data/lib/rails/generators/active_record/model/templates/model.rb.tt +10 -1
  293. metadata +113 -26
  294. 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,
@@ -138,7 +134,7 @@ module ActiveRecord
138
134
  relation.select_values = [ klass.primary_key || table[Arel.star] ]
139
135
  end
140
136
  # PostgreSQL: ORDER BY expressions must appear in SELECT list when using DISTINCT
141
- relation.order_values = []
137
+ relation.order_values = [] if group_values.empty?
142
138
  end
143
139
 
144
140
  relation.calculate(operation, column_name)
@@ -176,7 +172,7 @@ module ActiveRecord
176
172
  # # SELECT people.id FROM people WHERE people.age = 21 LIMIT 5
177
173
  # # => [2, 3]
178
174
  #
179
- # Person.pluck('DATEDIFF(updated_at, created_at)')
175
+ # Person.pluck(Arel.sql('DATEDIFF(updated_at, created_at)'))
180
176
  # # SELECT DATEDIFF(updated_at, created_at) FROM people
181
177
  # # => ['0', '27761', '173']
182
178
  #
@@ -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,8 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require "mutex_m"
4
+ require "active_support/core_ext/module/delegation"
5
+
3
6
  module ActiveRecord
4
7
  module Delegation # :nodoc:
5
8
  module DelegateCache # :nodoc:
@@ -18,7 +21,7 @@ module ActiveRecord
18
21
  include ClassSpecificRelation
19
22
  }
20
23
  include_relation_methods(delegate)
21
- mangled_name = klass.name.gsub("::".freeze, "_".freeze)
24
+ mangled_name = klass.name.gsub("::", "_")
22
25
  const_set mangled_name, delegate
23
26
  private_constant mangled_name
24
27
 
@@ -31,35 +34,49 @@ module ActiveRecord
31
34
  super
32
35
  end
33
36
 
37
+ def generate_relation_method(method)
38
+ generated_relation_methods.generate_method(method)
39
+ end
40
+
34
41
  protected
35
42
  def include_relation_methods(delegate)
36
- superclass.include_relation_methods(delegate) unless base_class == self
43
+ superclass.include_relation_methods(delegate) unless base_class?
37
44
  delegate.include generated_relation_methods
38
45
  end
39
46
 
40
47
  private
41
48
  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
49
+ @generated_relation_methods ||= GeneratedRelationMethods.new.tap do |mod|
50
+ const_set(:GeneratedRelationMethods, mod)
51
+ private_constant :GeneratedRelationMethods
46
52
  end
47
53
  end
54
+ end
48
55
 
49
- def generate_relation_method(method)
50
- if /\A[a-zA-Z_]\w*[!?]?\z/.match?(method)
51
- generated_relation_methods.module_eval <<-RUBY, __FILE__, __LINE__ + 1
52
- def #{method}(*args, &block)
53
- scoping { klass.#{method}(*args, &block) }
56
+ class GeneratedRelationMethods < Module # :nodoc:
57
+ include Mutex_m
58
+
59
+ def generate_method(method)
60
+ synchronize do
61
+ return if method_defined?(method)
62
+
63
+ if /\A[a-zA-Z_]\w*[!?]?\z/.match?(method) && !DELEGATION_RESERVED_METHOD_NAMES.include?(method.to_s)
64
+ definition = RUBY_VERSION >= "2.7" ? "..." : "*args, &block"
65
+ module_eval <<-RUBY, __FILE__, __LINE__ + 1
66
+ def #{method}(#{definition})
67
+ scoping { klass.#{method}(#{definition}) }
54
68
  end
55
69
  RUBY
56
70
  else
57
- generated_relation_methods.send(:define_method, method) do |*args, &block|
71
+ define_method(method) do |*args, &block|
58
72
  scoping { klass.public_send(method, *args, &block) }
59
73
  end
74
+ ruby2_keywords(method) if respond_to?(:ruby2_keywords, true)
60
75
  end
61
76
  end
77
+ end
62
78
  end
79
+ private_constant :GeneratedRelationMethods
63
80
 
64
81
  extend ActiveSupport::Concern
65
82
 
@@ -68,7 +85,7 @@ module ActiveRecord
68
85
  # may vary depending on the klass of a relation, so we create a subclass of Relation
69
86
  # for each different klass, and the delegations are compiled into that subclass only.
70
87
 
71
- delegate :to_xml, :encode_with, :length, :each, :uniq, :join,
88
+ delegate :to_xml, :encode_with, :length, :each, :join,
72
89
  :[], :&, :|, :+, :-, :sample, :reverse, :rotate, :compact, :in_groups, :in_groups_of,
73
90
  :to_sentence, :to_formatted_s, :as_json,
74
91
  :shuffle, :split, :slice, :index, :rindex, to: :records
@@ -78,62 +95,30 @@ module ActiveRecord
78
95
  module ClassSpecificRelation # :nodoc:
79
96
  extend ActiveSupport::Concern
80
97
 
81
- included do
82
- @delegation_mutex = Mutex.new
83
- end
84
-
85
98
  module ClassMethods # :nodoc:
86
99
  def name
87
100
  superclass.name
88
101
  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
102
  end
108
103
 
109
104
  private
110
-
111
105
  def method_missing(method, *args, &block)
112
106
  if @klass.respond_to?(method)
113
- self.class.delegate_to_scoped_klass(method)
107
+ @klass.generate_relation_method(method)
114
108
  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
109
  else
125
110
  super
126
111
  end
127
112
  end
113
+ ruby2_keywords(:method_missing) if respond_to?(:ruby2_keywords, true)
128
114
  end
129
115
 
130
116
  module ClassMethods # :nodoc:
131
- def create(klass, *args)
132
- relation_class_for(klass).new(klass, *args)
117
+ def create(klass, *args, **kwargs)
118
+ relation_class_for(klass).new(klass, *args, **kwargs)
133
119
  end
134
120
 
135
121
  private
136
-
137
122
  def relation_class_for(klass)
138
123
  klass.relation_delegate_class(self)
139
124
  end
@@ -141,7 +126,7 @@ module ActiveRecord
141
126
 
142
127
  private
143
128
  def respond_to_missing?(method, _)
144
- super || @klass.respond_to?(method) || arel.respond_to?(method)
129
+ super || @klass.respond_to?(method)
145
130
  end
146
131
  end
147
132
  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)
@@ -353,12 +346,13 @@ module ActiveRecord
353
346
  end
354
347
 
355
348
  private
356
-
357
349
  def offset_index
358
350
  offset_value || 0
359
351
  end
360
352
 
361
353
  def construct_relation_for_exists(conditions)
354
+ conditions = sanitize_forbidden_attributes(conditions)
355
+
362
356
  if distinct_value && offset_value
363
357
  relation = except(:order).limit!(1)
364
358
  else
@@ -375,18 +369,22 @@ module ActiveRecord
375
369
  relation
376
370
  end
377
371
 
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
372
  def apply_join_dependency(eager_loading: group_values.empty?)
386
- join_dependency = construct_join_dependency
373
+ join_dependency = construct_join_dependency(
374
+ eager_load_values | includes_values, Arel::Nodes::OuterJoin
375
+ )
387
376
  relation = except(:includes, :eager_load, :preload).joins!(join_dependency)
388
377
 
389
- if eager_loading && !using_limitable_reflections?(join_dependency.reflections)
378
+ if eager_loading && !(
379
+ using_limitable_reflections?(join_dependency.reflections) &&
380
+ using_limitable_reflections?(
381
+ construct_join_dependency(
382
+ select_association_list(joins_values).concat(
383
+ select_association_list(left_outer_joins_values)
384
+ ), nil
385
+ ).reflections
386
+ )
387
+ )
390
388
  if has_limit_or_offset?
391
389
  limited_ids = limited_ids_for(relation)
392
390
  limited_ids.empty? ? relation.none! : relation.where!(primary_key => limited_ids)
@@ -403,7 +401,7 @@ module ActiveRecord
403
401
 
404
402
  def limited_ids_for(relation)
405
403
  values = @klass.connection.columns_for_distinct(
406
- connection.column_name_from_arel_node(arel_attribute(primary_key)),
404
+ connection.visitor.compile(arel_attribute(primary_key)),
407
405
  relation.order_values
408
406
  )
409
407
 
@@ -437,9 +435,6 @@ module ActiveRecord
437
435
  else
438
436
  find_some(ids)
439
437
  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
438
  end
444
439
 
445
440
  def find_one(id)
@@ -555,8 +550,8 @@ module ActiveRecord
555
550
  end
556
551
 
557
552
  def ordered_relation
558
- if order_values.empty? && primary_key
559
- order(arel_attribute(primary_key).asc)
553
+ if order_values.empty? && (implicit_order_column || primary_key)
554
+ order(arel_attribute(implicit_order_column || primary_key).asc)
560
555
  else
561
556
  self
562
557
  end
@@ -18,6 +18,10 @@ module ActiveRecord
18
18
  value.nil?
19
19
  end
20
20
 
21
+ def ==(other)
22
+ self.class == other.class && value == other.value && name == other.name
23
+ end
24
+
21
25
  def self.empty
22
26
  @empty ||= new(nil, nil)
23
27
  end
@@ -89,7 +89,6 @@ module ActiveRecord
89
89
  end
90
90
 
91
91
  private
92
-
93
92
  def merge_preloads
94
93
  return if other.preload_values.empty? && other.includes_values.empty?
95
94
 
@@ -117,18 +116,16 @@ module ActiveRecord
117
116
  if other.klass == relation.klass
118
117
  relation.joins!(*other.joins_values)
119
118
  else
120
- joins_dependency = other.joins_values.map do |join|
119
+ associations, others = other.joins_values.partition do |join|
121
120
  case join
122
- when Hash, Symbol, Array
123
- ActiveRecord::Associations::JoinDependency.new(
124
- other.klass, other.table, join
125
- )
126
- else
127
- join
121
+ when Hash, Symbol, Array; true
128
122
  end
129
123
  end
130
124
 
131
- relation.joins!(*joins_dependency)
125
+ join_dependency = other.construct_join_dependency(
126
+ associations, Arel::Nodes::InnerJoin
127
+ )
128
+ relation.joins!(join_dependency, *others)
132
129
  end
133
130
  end
134
131
 
@@ -138,18 +135,16 @@ module ActiveRecord
138
135
  if other.klass == relation.klass
139
136
  relation.left_outer_joins!(*other.left_outer_joins_values)
140
137
  else
141
- joins_dependency = other.left_outer_joins_values.map do |join|
138
+ associations, others = other.left_outer_joins_values.partition do |join|
142
139
  case join
143
- when Hash, Symbol, Array
144
- ActiveRecord::Associations::JoinDependency.new(
145
- other.klass, other.table, join
146
- )
147
- else
148
- join
140
+ when Hash, Symbol, Array; true
149
141
  end
150
142
  end
151
143
 
152
- relation.left_outer_joins!(*joins_dependency)
144
+ join_dependency = other.construct_join_dependency(
145
+ associations, Arel::Nodes::OuterJoin
146
+ )
147
+ relation.left_outer_joins!(join_dependency, *others)
153
148
  end
154
149
  end
155
150
 
@@ -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|