activerecord 5.2.7 → 6.0.0.beta1

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of activerecord might be problematic. Click here for more details.

Files changed (241) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +299 -778
  3. data/MIT-LICENSE +3 -1
  4. data/README.rdoc +1 -1
  5. data/examples/performance.rb +1 -1
  6. data/lib/active_record/aggregations.rb +4 -2
  7. data/lib/active_record/associations/association.rb +35 -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/belongs_to.rb +14 -50
  12. data/lib/active_record/associations/builder/collection_association.rb +3 -3
  13. data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +17 -38
  14. data/lib/active_record/associations/collection_association.rb +11 -25
  15. data/lib/active_record/associations/collection_proxy.rb +32 -6
  16. data/lib/active_record/associations/foreign_association.rb +7 -0
  17. data/lib/active_record/associations/has_many_association.rb +1 -1
  18. data/lib/active_record/associations/has_many_through_association.rb +25 -18
  19. data/lib/active_record/associations/has_one_association.rb +28 -30
  20. data/lib/active_record/associations/has_one_through_association.rb +5 -5
  21. data/lib/active_record/associations/join_dependency/join_association.rb +11 -26
  22. data/lib/active_record/associations/join_dependency/join_part.rb +2 -2
  23. data/lib/active_record/associations/join_dependency.rb +15 -20
  24. data/lib/active_record/associations/preloader/association.rb +1 -2
  25. data/lib/active_record/associations/preloader.rb +32 -29
  26. data/lib/active_record/associations/singular_association.rb +2 -16
  27. data/lib/active_record/associations.rb +16 -12
  28. data/lib/active_record/attribute_assignment.rb +7 -10
  29. data/lib/active_record/attribute_methods/dirty.rb +64 -26
  30. data/lib/active_record/attribute_methods/primary_key.rb +8 -7
  31. data/lib/active_record/attribute_methods/read.rb +16 -48
  32. data/lib/active_record/attribute_methods/serialization.rb +1 -1
  33. data/lib/active_record/attribute_methods/time_zone_conversion.rb +1 -1
  34. data/lib/active_record/attribute_methods/write.rb +15 -16
  35. data/lib/active_record/attribute_methods.rb +34 -56
  36. data/lib/active_record/autosave_association.rb +7 -21
  37. data/lib/active_record/base.rb +2 -2
  38. data/lib/active_record/callbacks.rb +3 -17
  39. data/lib/active_record/collection_cache_key.rb +1 -1
  40. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +13 -36
  41. data/lib/active_record/connection_adapters/abstract/database_limits.rb +9 -0
  42. data/lib/active_record/connection_adapters/abstract/database_statements.rb +25 -84
  43. data/lib/active_record/connection_adapters/abstract/query_cache.rb +17 -14
  44. data/lib/active_record/connection_adapters/abstract/quoting.rb +5 -11
  45. data/lib/active_record/connection_adapters/abstract/schema_creation.rb +15 -11
  46. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +30 -13
  47. data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +0 -2
  48. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +41 -27
  49. data/lib/active_record/connection_adapters/abstract/transaction.rb +81 -52
  50. data/lib/active_record/connection_adapters/abstract_adapter.rb +95 -31
  51. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +65 -90
  52. data/lib/active_record/connection_adapters/connection_specification.rb +52 -42
  53. data/lib/active_record/connection_adapters/determine_if_preparable_visitor.rb +5 -9
  54. data/lib/active_record/connection_adapters/mysql/database_statements.rb +29 -7
  55. data/lib/active_record/connection_adapters/mysql/quoting.rb +1 -1
  56. data/lib/active_record/connection_adapters/mysql/schema_creation.rb +3 -4
  57. data/lib/active_record/connection_adapters/mysql/schema_statements.rb +65 -10
  58. data/lib/active_record/connection_adapters/mysql2_adapter.rb +8 -4
  59. data/lib/active_record/connection_adapters/postgresql/column.rb +1 -2
  60. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +16 -1
  61. data/lib/active_record/connection_adapters/postgresql/oid/array.rb +1 -1
  62. data/lib/active_record/connection_adapters/postgresql/oid/bit.rb +1 -4
  63. data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +1 -1
  64. data/lib/active_record/connection_adapters/postgresql/oid/legacy_point.rb +1 -1
  65. data/lib/active_record/connection_adapters/postgresql/oid/money.rb +2 -2
  66. data/lib/active_record/connection_adapters/postgresql/oid/point.rb +1 -1
  67. data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +9 -7
  68. data/lib/active_record/connection_adapters/postgresql/quoting.rb +4 -4
  69. data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +11 -36
  70. data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +9 -2
  71. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +38 -20
  72. data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +2 -1
  73. data/lib/active_record/connection_adapters/postgresql_adapter.rb +75 -56
  74. data/lib/active_record/connection_adapters/schema_cache.rb +5 -0
  75. data/lib/active_record/connection_adapters/sqlite3/quoting.rb +5 -5
  76. data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +14 -9
  77. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +95 -62
  78. data/lib/active_record/connection_handling.rb +132 -26
  79. data/lib/active_record/core.rb +76 -43
  80. data/lib/active_record/counter_cache.rb +4 -29
  81. data/lib/active_record/database_configurations/database_config.rb +37 -0
  82. data/lib/active_record/database_configurations/hash_config.rb +50 -0
  83. data/lib/active_record/database_configurations/url_config.rb +74 -0
  84. data/lib/active_record/database_configurations.rb +184 -0
  85. data/lib/active_record/enum.rb +22 -7
  86. data/lib/active_record/errors.rb +24 -21
  87. data/lib/active_record/explain.rb +1 -1
  88. data/lib/active_record/fixture_set/model_metadata.rb +33 -0
  89. data/lib/active_record/fixture_set/render_context.rb +17 -0
  90. data/lib/active_record/fixture_set/table_row.rb +153 -0
  91. data/lib/active_record/fixture_set/table_rows.rb +47 -0
  92. data/lib/active_record/fixtures.rb +140 -472
  93. data/lib/active_record/gem_version.rb +4 -4
  94. data/lib/active_record/inheritance.rb +12 -2
  95. data/lib/active_record/integration.rb +56 -16
  96. data/lib/active_record/internal_metadata.rb +5 -1
  97. data/lib/active_record/locking/optimistic.rb +2 -2
  98. data/lib/active_record/locking/pessimistic.rb +3 -3
  99. data/lib/active_record/log_subscriber.rb +7 -26
  100. data/lib/active_record/migration/command_recorder.rb +35 -5
  101. data/lib/active_record/migration/compatibility.rb +34 -16
  102. data/lib/active_record/migration.rb +38 -37
  103. data/lib/active_record/model_schema.rb +30 -9
  104. data/lib/active_record/nested_attributes.rb +2 -2
  105. data/lib/active_record/no_touching.rb +7 -0
  106. data/lib/active_record/persistence.rb +18 -7
  107. data/lib/active_record/query_cache.rb +11 -4
  108. data/lib/active_record/querying.rb +19 -11
  109. data/lib/active_record/railtie.rb +71 -42
  110. data/lib/active_record/railties/collection_cache_association_loading.rb +34 -0
  111. data/lib/active_record/railties/controller_runtime.rb +30 -35
  112. data/lib/active_record/railties/databases.rake +94 -43
  113. data/lib/active_record/reflection.rb +60 -44
  114. data/lib/active_record/relation/batches.rb +13 -10
  115. data/lib/active_record/relation/calculations.rb +38 -28
  116. data/lib/active_record/relation/delegation.rb +4 -13
  117. data/lib/active_record/relation/finder_methods.rb +12 -25
  118. data/lib/active_record/relation/merger.rb +2 -6
  119. data/lib/active_record/relation/predicate_builder/array_handler.rb +5 -4
  120. data/lib/active_record/relation/predicate_builder/association_query_value.rb +1 -4
  121. data/lib/active_record/relation/predicate_builder/base_handler.rb +1 -2
  122. data/lib/active_record/relation/predicate_builder/basic_object_handler.rb +1 -2
  123. data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +1 -4
  124. data/lib/active_record/relation/predicate_builder/range_handler.rb +3 -23
  125. data/lib/active_record/relation/predicate_builder.rb +4 -6
  126. data/lib/active_record/relation/query_attribute.rb +15 -12
  127. data/lib/active_record/relation/query_methods.rb +29 -52
  128. data/lib/active_record/relation/where_clause.rb +4 -0
  129. data/lib/active_record/relation/where_clause_factory.rb +1 -2
  130. data/lib/active_record/relation.rb +150 -69
  131. data/lib/active_record/result.rb +30 -11
  132. data/lib/active_record/sanitization.rb +2 -39
  133. data/lib/active_record/schema.rb +1 -10
  134. data/lib/active_record/schema_dumper.rb +12 -6
  135. data/lib/active_record/schema_migration.rb +4 -0
  136. data/lib/active_record/scoping/default.rb +10 -3
  137. data/lib/active_record/scoping/named.rb +10 -14
  138. data/lib/active_record/scoping.rb +9 -8
  139. data/lib/active_record/statement_cache.rb +32 -5
  140. data/lib/active_record/store.rb +39 -8
  141. data/lib/active_record/table_metadata.rb +1 -4
  142. data/lib/active_record/tasks/database_tasks.rb +89 -23
  143. data/lib/active_record/tasks/mysql_database_tasks.rb +2 -4
  144. data/lib/active_record/tasks/postgresql_database_tasks.rb +5 -7
  145. data/lib/active_record/tasks/sqlite_database_tasks.rb +2 -8
  146. data/lib/active_record/test_databases.rb +38 -0
  147. data/lib/active_record/test_fixtures.rb +224 -0
  148. data/lib/active_record/timestamp.rb +4 -6
  149. data/lib/active_record/transactions.rb +3 -22
  150. data/lib/active_record/translation.rb +1 -1
  151. data/lib/active_record/type/adapter_specific_registry.rb +1 -8
  152. data/lib/active_record/type.rb +3 -4
  153. data/lib/active_record/type_caster/connection.rb +1 -6
  154. data/lib/active_record/type_caster/map.rb +1 -4
  155. data/lib/active_record/validations/uniqueness.rb +13 -25
  156. data/lib/active_record.rb +2 -1
  157. data/lib/arel/alias_predication.rb +9 -0
  158. data/lib/arel/attributes/attribute.rb +37 -0
  159. data/lib/arel/attributes.rb +22 -0
  160. data/lib/arel/collectors/bind.rb +24 -0
  161. data/lib/arel/collectors/composite.rb +31 -0
  162. data/lib/arel/collectors/plain_string.rb +20 -0
  163. data/lib/arel/collectors/sql_string.rb +20 -0
  164. data/lib/arel/collectors/substitute_binds.rb +28 -0
  165. data/lib/arel/crud.rb +42 -0
  166. data/lib/arel/delete_manager.rb +18 -0
  167. data/lib/arel/errors.rb +9 -0
  168. data/lib/arel/expressions.rb +29 -0
  169. data/lib/arel/factory_methods.rb +49 -0
  170. data/lib/arel/insert_manager.rb +49 -0
  171. data/lib/arel/math.rb +45 -0
  172. data/lib/arel/nodes/and.rb +32 -0
  173. data/lib/arel/nodes/ascending.rb +23 -0
  174. data/lib/arel/nodes/binary.rb +52 -0
  175. data/lib/arel/nodes/bind_param.rb +36 -0
  176. data/lib/arel/nodes/case.rb +55 -0
  177. data/lib/arel/nodes/casted.rb +50 -0
  178. data/lib/arel/nodes/count.rb +12 -0
  179. data/lib/arel/nodes/delete_statement.rb +45 -0
  180. data/lib/arel/nodes/descending.rb +23 -0
  181. data/lib/arel/nodes/equality.rb +18 -0
  182. data/lib/arel/nodes/extract.rb +24 -0
  183. data/lib/arel/nodes/false.rb +16 -0
  184. data/lib/arel/nodes/full_outer_join.rb +8 -0
  185. data/lib/arel/nodes/function.rb +44 -0
  186. data/lib/arel/nodes/grouping.rb +8 -0
  187. data/lib/arel/nodes/in.rb +8 -0
  188. data/lib/arel/nodes/infix_operation.rb +80 -0
  189. data/lib/arel/nodes/inner_join.rb +8 -0
  190. data/lib/arel/nodes/insert_statement.rb +37 -0
  191. data/lib/arel/nodes/join_source.rb +20 -0
  192. data/lib/arel/nodes/matches.rb +18 -0
  193. data/lib/arel/nodes/named_function.rb +23 -0
  194. data/lib/arel/nodes/node.rb +50 -0
  195. data/lib/arel/nodes/node_expression.rb +13 -0
  196. data/lib/arel/nodes/outer_join.rb +8 -0
  197. data/lib/arel/nodes/over.rb +15 -0
  198. data/lib/arel/nodes/regexp.rb +16 -0
  199. data/lib/arel/nodes/right_outer_join.rb +8 -0
  200. data/lib/arel/nodes/select_core.rb +63 -0
  201. data/lib/arel/nodes/select_statement.rb +41 -0
  202. data/lib/arel/nodes/sql_literal.rb +16 -0
  203. data/lib/arel/nodes/string_join.rb +11 -0
  204. data/lib/arel/nodes/table_alias.rb +27 -0
  205. data/lib/arel/nodes/terminal.rb +16 -0
  206. data/lib/arel/nodes/true.rb +16 -0
  207. data/lib/arel/nodes/unary.rb +44 -0
  208. data/lib/arel/nodes/unary_operation.rb +20 -0
  209. data/lib/arel/nodes/unqualified_column.rb +22 -0
  210. data/lib/arel/nodes/update_statement.rb +41 -0
  211. data/lib/arel/nodes/values.rb +16 -0
  212. data/lib/arel/nodes/values_list.rb +24 -0
  213. data/lib/arel/nodes/window.rb +126 -0
  214. data/lib/arel/nodes/with.rb +11 -0
  215. data/lib/arel/nodes.rb +67 -0
  216. data/lib/arel/order_predications.rb +13 -0
  217. data/lib/arel/predications.rb +257 -0
  218. data/lib/arel/select_manager.rb +271 -0
  219. data/lib/arel/table.rb +110 -0
  220. data/lib/arel/tree_manager.rb +72 -0
  221. data/lib/arel/update_manager.rb +34 -0
  222. data/lib/arel/visitors/depth_first.rb +199 -0
  223. data/lib/arel/visitors/dot.rb +292 -0
  224. data/lib/arel/visitors/ibm_db.rb +21 -0
  225. data/lib/arel/visitors/informix.rb +56 -0
  226. data/lib/arel/visitors/mssql.rb +143 -0
  227. data/lib/arel/visitors/mysql.rb +83 -0
  228. data/lib/arel/visitors/oracle.rb +159 -0
  229. data/lib/arel/visitors/oracle12.rb +67 -0
  230. data/lib/arel/visitors/postgresql.rb +116 -0
  231. data/lib/arel/visitors/sqlite.rb +39 -0
  232. data/lib/arel/visitors/to_sql.rb +913 -0
  233. data/lib/arel/visitors/visitor.rb +42 -0
  234. data/lib/arel/visitors/where_sql.rb +23 -0
  235. data/lib/arel/visitors.rb +20 -0
  236. data/lib/arel/window_predications.rb +9 -0
  237. data/lib/arel.rb +44 -0
  238. data/lib/rails/generators/active_record/migration/migration_generator.rb +2 -5
  239. data/lib/rails/generators/active_record/migration.rb +14 -1
  240. data/lib/rails/generators/active_record/model/model_generator.rb +1 -0
  241. metadata +104 -26
@@ -9,6 +9,7 @@ module ActiveRecord
9
9
 
10
10
  SINGLE_VALUE_METHODS = [:limit, :offset, :lock, :readonly, :reordering,
11
11
  :reverse_order, :distinct, :create_with, :skip_query_cache]
12
+
12
13
  CLAUSE_METHODS = [:where, :having, :from]
13
14
  INVALID_METHODS_FOR_DELETE_ALL = [:distinct, :group, :having]
14
15
 
@@ -18,6 +19,7 @@ module ActiveRecord
18
19
  include FinderMethods, Calculations, SpawnMethods, QueryMethods, Batches, Explain, Delegation
19
20
 
20
21
  attr_reader :table, :klass, :loaded, :predicate_builder
22
+ attr_accessor :skip_preloading_value
21
23
  alias :model :klass
22
24
  alias :loaded? :loaded
23
25
  alias :locked? :lock_value
@@ -41,6 +43,17 @@ module ActiveRecord
41
43
  klass.arel_attribute(name, table)
42
44
  end
43
45
 
46
+ def bind_attribute(name, value) # :nodoc:
47
+ if reflection = klass._reflect_on_association(name)
48
+ name = reflection.foreign_key
49
+ value = value.read_attribute(reflection.klass.primary_key) unless value.nil?
50
+ end
51
+
52
+ attr = arel_attribute(name)
53
+ bind = predicate_builder.build_bind_attribute(attr.name, value)
54
+ yield attr, bind
55
+ end
56
+
44
57
  # Initializes new record from relation while maintaining the current
45
58
  # scope.
46
59
  #
@@ -54,7 +67,7 @@ module ActiveRecord
54
67
  # user = users.new { |user| user.name = 'Oscar' }
55
68
  # user.name # => Oscar
56
69
  def new(attributes = nil, &block)
57
- scoping { klass.new(values_for_create(attributes), &block) }
70
+ scoping { klass.new(attributes, &block) }
58
71
  end
59
72
 
60
73
  alias build new
@@ -79,11 +92,7 @@ module ActiveRecord
79
92
  # users.create(name: nil) # validation on name
80
93
  # # => #<User id: nil, name: nil, ...>
81
94
  def create(attributes = nil, &block)
82
- if attributes.is_a?(Array)
83
- attributes.collect { |attr| create(attr, &block) }
84
- else
85
- scoping { klass.create(values_for_create(attributes), &block) }
86
- end
95
+ scoping { klass.create(attributes, &block) }
87
96
  end
88
97
 
89
98
  # Similar to #create, but calls
@@ -93,11 +102,7 @@ module ActiveRecord
93
102
  # Expects arguments in the same format as
94
103
  # {ActiveRecord::Base.create!}[rdoc-ref:Persistence::ClassMethods#create!].
95
104
  def create!(attributes = nil, &block)
96
- if attributes.is_a?(Array)
97
- attributes.collect { |attr| create!(attr, &block) }
98
- else
99
- scoping { klass.create!(values_for_create(attributes), &block) }
100
- end
105
+ scoping { klass.create!(attributes, &block) }
101
106
  end
102
107
 
103
108
  def first_or_create(attributes = nil, &block) # :nodoc:
@@ -143,23 +148,12 @@ module ActiveRecord
143
148
  # failed due to validation errors it won't be persisted, you get what
144
149
  # #create returns in such situation.
145
150
  #
146
- # Please note *this method is not atomic*, it runs first a SELECT, and if
151
+ # Please note <b>this method is not atomic</b>, it runs first a SELECT, and if
147
152
  # there are no results an INSERT is attempted. If there are other threads
148
153
  # or processes there is a race condition between both calls and it could
149
154
  # be the case that you end up with two similar records.
150
155
  #
151
- # Whether that is a problem or not depends on the logic of the
152
- # application, but in the particular case in which rows have a UNIQUE
153
- # constraint an exception may be raised, just retry:
154
- #
155
- # begin
156
- # CreditAccount.transaction(requires_new: true) do
157
- # CreditAccount.find_or_create_by(user_id: user.id)
158
- # end
159
- # rescue ActiveRecord::RecordNotUnique
160
- # retry
161
- # end
162
- #
156
+ # If this might be a problem for your application, please see #create_or_find_by.
163
157
  def find_or_create_by(attributes, &block)
164
158
  find_by(attributes) || create(attributes, &block)
165
159
  end
@@ -171,6 +165,47 @@ module ActiveRecord
171
165
  find_by(attributes) || create!(attributes, &block)
172
166
  end
173
167
 
168
+ # Attempts to create a record with the given attributes in a table that has a unique constraint
169
+ # on one or several of its columns. If a row already exists with one or several of these
170
+ # unique constraints, the exception such an insertion would normally raise is caught,
171
+ # and the existing record with those attributes is found using #find_by!.
172
+ #
173
+ # This is similar to #find_or_create_by, but avoids the problem of stale reads between the SELECT
174
+ # and the INSERT, as that method needs to first query the table, then attempt to insert a row
175
+ # if none is found.
176
+ #
177
+ # There are several drawbacks to #create_or_find_by, though:
178
+ #
179
+ # * The underlying table must have the relevant columns defined with unique constraints.
180
+ # * A unique constraint violation may be triggered by only one, or at least less than all,
181
+ # of the given attributes. This means that the subsequent #find_by! may fail to find a
182
+ # matching record, which will then raise an <tt>ActiveRecord::RecordNotFound</tt> exception,
183
+ # rather than a record with the given attributes.
184
+ # * While we avoid the race condition between SELECT -> INSERT from #find_or_create_by,
185
+ # we actually have another race condition between INSERT -> SELECT, which can be triggered
186
+ # if a DELETE between those two statements is run by another client. But for most applications,
187
+ # that's a significantly less likely condition to hit.
188
+ # * It relies on exception handling to handle control flow, which may be marginally slower.
189
+ #
190
+ # This method will return a record if all given attributes are covered by unique constraints
191
+ # (unless the INSERT -> DELETE -> SELECT race condition is triggered), but if creation was attempted
192
+ # and failed due to validation errors it won't be persisted, you get what #create returns in
193
+ # such situation.
194
+ def create_or_find_by(attributes, &block)
195
+ transaction(requires_new: true) { create(attributes, &block) }
196
+ rescue ActiveRecord::RecordNotUnique
197
+ find_by!(attributes)
198
+ end
199
+
200
+ # Like #create_or_find_by, but calls
201
+ # {create!}[rdoc-ref:Persistence::ClassMethods#create!] so an exception
202
+ # is raised if the created record is invalid.
203
+ def create_or_find_by!(attributes, &block)
204
+ transaction(requires_new: true) { create!(attributes, &block) }
205
+ rescue ActiveRecord::RecordNotUnique
206
+ find_by!(attributes)
207
+ end
208
+
174
209
  # Like #find_or_create_by, but calls {new}[rdoc-ref:Core#new]
175
210
  # instead of {create}[rdoc-ref:Persistence::ClassMethods#create].
176
211
  def find_or_initialize_by(attributes, &block)
@@ -185,7 +220,7 @@ module ActiveRecord
185
220
  # are needed by the next ones when eager loading is going on.
186
221
  #
187
222
  # Please see further details in the
188
- # {Active Record Query Interface guide}[http://guides.rubyonrails.org/active_record_querying.html#running-explain].
223
+ # {Active Record Query Interface guide}[https://guides.rubyonrails.org/active_record_querying.html#running-explain].
189
224
  def explain
190
225
  exec_explain(collecting_queries_for_explain { exec_queries })
191
226
  end
@@ -277,10 +312,7 @@ module ActiveRecord
277
312
  # Please check unscoped if you want to remove all previous scopes (including
278
313
  # the default_scope) during the execution of a block.
279
314
  def scoping
280
- previous, klass.current_scope = klass.current_scope(true), self unless @delegate_to_klass
281
- yield
282
- ensure
283
- klass.current_scope = previous unless @delegate_to_klass
315
+ @delegate_to_klass ? yield : klass._scoping(self) { yield }
284
316
  end
285
317
 
286
318
  def _exec_scope(*args, &block) # :nodoc:
@@ -321,17 +353,17 @@ module ActiveRecord
321
353
  end
322
354
 
323
355
  stmt = Arel::UpdateManager.new
324
-
325
- stmt.set Arel.sql(@klass.sanitize_sql_for_assignment(updates))
326
- stmt.table(table)
327
-
328
- if has_join_values? || offset_value
329
- @klass.connection.join_to_update(stmt, arel, arel_attribute(primary_key))
356
+ stmt.table(arel.join_sources.empty? ? table : arel.source)
357
+ stmt.key = arel_attribute(primary_key)
358
+ stmt.take(arel.limit)
359
+ stmt.offset(arel.offset)
360
+ stmt.order(*arel.orders)
361
+ stmt.wheres = arel.constraints
362
+
363
+ if updates.is_a?(Hash)
364
+ stmt.set _substitute_values(updates)
330
365
  else
331
- stmt.key = arel_attribute(primary_key)
332
- stmt.take(arel.limit)
333
- stmt.order(*arel.orders)
334
- stmt.wheres = arel.constraints
366
+ stmt.set Arel.sql(klass.sanitize_sql_for_assignment(updates, table.name))
335
367
  end
336
368
 
337
369
  @klass.connection.update stmt, "#{@klass} Update All"
@@ -345,6 +377,59 @@ module ActiveRecord
345
377
  end
346
378
  end
347
379
 
380
+ def update_counters(counters) # :nodoc:
381
+ touch = counters.delete(:touch)
382
+
383
+ updates = {}
384
+ counters.each do |counter_name, value|
385
+ attr = arel_attribute(counter_name)
386
+ bind = predicate_builder.build_bind_attribute(attr.name, value.abs)
387
+ expr = table.coalesce(Arel::Nodes::UnqualifiedColumn.new(attr), 0)
388
+ expr = value < 0 ? expr - bind : expr + bind
389
+ updates[counter_name] = expr.expr
390
+ end
391
+
392
+ if touch
393
+ names = touch if touch != true
394
+ touch_updates = klass.touch_attributes_with_time(*names)
395
+ updates.merge!(touch_updates) unless touch_updates.empty?
396
+ end
397
+
398
+ update_all updates
399
+ end
400
+
401
+ # Touches all records in the current relation without instantiating records first with the updated_at/on attributes
402
+ # set to the current time or the time specified.
403
+ # This method can be passed attribute names and an optional time argument.
404
+ # If attribute names are passed, they are updated along with updated_at/on attributes.
405
+ # If no time argument is passed, the current time is used as default.
406
+ #
407
+ # === Examples
408
+ #
409
+ # # Touch all records
410
+ # Person.all.touch_all
411
+ # # => "UPDATE \"people\" SET \"updated_at\" = '2018-01-04 22:55:23.132670'"
412
+ #
413
+ # # Touch multiple records with a custom attribute
414
+ # Person.all.touch_all(:created_at)
415
+ # # => "UPDATE \"people\" SET \"updated_at\" = '2018-01-04 22:55:23.132670', \"created_at\" = '2018-01-04 22:55:23.132670'"
416
+ #
417
+ # # Touch multiple records with a specified time
418
+ # Person.all.touch_all(time: Time.new(2020, 5, 16, 0, 0, 0))
419
+ # # => "UPDATE \"people\" SET \"updated_at\" = '2020-05-16 00:00:00'"
420
+ #
421
+ # # Touch records with scope
422
+ # Person.where(name: 'David').touch_all
423
+ # # => "UPDATE \"people\" SET \"updated_at\" = '2018-01-04 22:55:23.132670' WHERE \"people\".\"name\" = 'David'"
424
+ def touch_all(*names, time: nil)
425
+ if klass.locking_enabled?
426
+ names << { time: time }
427
+ update_counters(klass.locking_column => 1, touch: names)
428
+ else
429
+ update_all klass.touch_attributes_with_time(*names, time: time)
430
+ end
431
+ end
432
+
348
433
  # Destroys the records by instantiating each
349
434
  # record and calling its {#destroy}[rdoc-ref:Persistence#destroy] method.
350
435
  # Each object's callbacks are executed (including <tt>:dependent</tt> association options).
@@ -398,13 +483,12 @@ module ActiveRecord
398
483
  end
399
484
 
400
485
  stmt = Arel::DeleteManager.new
401
- stmt.from(table)
402
-
403
- if has_join_values? || has_limit_or_offset?
404
- @klass.connection.join_to_delete(stmt, arel, arel_attribute(primary_key))
405
- else
406
- stmt.wheres = arel.constraints
407
- end
486
+ stmt.from(arel.join_sources.empty? ? table : arel.source)
487
+ stmt.key = arel_attribute(primary_key)
488
+ stmt.take(arel.limit)
489
+ stmt.offset(arel.offset)
490
+ stmt.order(*arel.orders)
491
+ stmt.wheres = arel.constraints
408
492
 
409
493
  affected = @klass.connection.delete(stmt, "#{@klass} Destroy")
410
494
 
@@ -530,6 +614,16 @@ module ActiveRecord
530
614
  ActiveRecord::Associations::AliasTracker.create(connection, table.name, joins)
531
615
  end
532
616
 
617
+ def preload_associations(records) # :nodoc:
618
+ preload = preload_values
619
+ preload += includes_values unless eager_loading?
620
+ preloader = nil
621
+ preload.each do |associations|
622
+ preloader ||= build_preloader
623
+ preloader.preload records, associations
624
+ end
625
+ end
626
+
533
627
  protected
534
628
 
535
629
  def load_records(records)
@@ -538,9 +632,15 @@ module ActiveRecord
538
632
  end
539
633
 
540
634
  private
541
-
542
- def has_join_values?
543
- joins_values.any? || left_outer_joins_values.any?
635
+ def _substitute_values(values)
636
+ values.map do |name, value|
637
+ attr = arel_attribute(name)
638
+ unless Arel.arel_node?(value)
639
+ type = klass.type_for_attribute(attr.name)
640
+ value = predicate_builder.build_bind_attribute(attr.name, type.cast(value))
641
+ end
642
+ [attr, value]
643
+ end
544
644
  end
545
645
 
546
646
  def exec_queries(&block)
@@ -560,13 +660,7 @@ module ActiveRecord
560
660
  klass.find_by_sql(arel, &block).freeze
561
661
  end
562
662
 
563
- preload = preload_values
564
- preload += includes_values unless eager_loading?
565
- preloader = nil
566
- preload.each do |associations|
567
- preloader ||= build_preloader
568
- preloader.preload @records, associations
569
- end
663
+ preload_associations(@records) unless skip_preloading_value
570
664
 
571
665
  @records.each(&:readonly!) if readonly_value
572
666
 
@@ -612,18 +706,5 @@ module ActiveRecord
612
706
  # ignore raw_sql_ that is used by Oracle adapter as alias for limit/offset subqueries
613
707
  string.scan(/([a-zA-Z_][.\w]+).?\./).flatten.map(&:downcase).uniq - ["raw_sql_"]
614
708
  end
615
-
616
- def values_for_create(attributes = nil)
617
- result = attributes ? where_values_hash.merge!(attributes) : where_values_hash
618
-
619
- # NOTE: if there are same keys in both create_with and result, create_with should be used.
620
- # This is to make sure nested attributes don't get passed to the klass.new,
621
- # while keeping the precedence of the duplicate keys in create_with.
622
- create_with_value.stringify_keys.each do |k, v|
623
- result[k] = v if result.key?(k)
624
- end
625
-
626
- result
627
- end
628
709
  end
629
710
  end
@@ -21,7 +21,7 @@ module ActiveRecord
21
21
  # ]
22
22
  #
23
23
  # # Get an array of hashes representing the result (column => value):
24
- # result.to_hash
24
+ # result.to_a
25
25
  # # => [{"id" => 1, "title" => "title_1", "body" => "body_1"},
26
26
  # {"id" => 2, "title" => "title_2", "body" => "body_2"},
27
27
  # ...
@@ -43,6 +43,11 @@ module ActiveRecord
43
43
  @column_types = column_types
44
44
  end
45
45
 
46
+ # Returns true if this result set includes the column named +name+
47
+ def includes_column?(name)
48
+ @columns.include? name
49
+ end
50
+
46
51
  # Returns the number of elements in the rows array.
47
52
  def length
48
53
  @rows.length
@@ -60,9 +65,12 @@ module ActiveRecord
60
65
  end
61
66
  end
62
67
 
63
- # Returns an array of hashes representing each row record.
64
68
  def to_hash
65
- hash_rows
69
+ ActiveSupport::Deprecation.warn(<<-MSG.squish)
70
+ `ActiveRecord::Result#to_hash` has been renamed to `to_a`.
71
+ `to_hash` is deprecated and will be removed in Rails 6.1.
72
+ MSG
73
+ to_a
66
74
  end
67
75
 
68
76
  alias :map! :map
@@ -78,6 +86,8 @@ module ActiveRecord
78
86
  hash_rows
79
87
  end
80
88
 
89
+ alias :to_a :to_ary
90
+
81
91
  def [](idx)
82
92
  hash_rows[idx]
83
93
  end
@@ -97,12 +107,21 @@ module ActiveRecord
97
107
  end
98
108
 
99
109
  def cast_values(type_overrides = {}) # :nodoc:
100
- types = columns.map { |name| column_type(name, type_overrides) }
101
- result = rows.map do |values|
102
- types.zip(values).map { |type, value| type.deserialize(value) }
103
- end
110
+ if columns.one?
111
+ # Separated to avoid allocating an array per row
112
+
113
+ type = column_type(columns.first, type_overrides)
104
114
 
105
- columns.one? ? result.map!(&:first) : result
115
+ rows.map do |(value)|
116
+ type.deserialize(value)
117
+ end
118
+ else
119
+ types = columns.map { |name| column_type(name, type_overrides) }
120
+
121
+ rows.map do |values|
122
+ Array.new(values.size) { |i| types[i].deserialize(values[i]) }
123
+ end
124
+ end
106
125
  end
107
126
 
108
127
  def initialize_copy(other)
@@ -125,7 +144,9 @@ module ActiveRecord
125
144
  begin
126
145
  # We freeze the strings to prevent them getting duped when
127
146
  # used as keys in ActiveRecord::Base's @attributes hash
128
- columns = @columns.map { |c| c.dup.freeze }
147
+ columns = @columns.map(&:-@)
148
+ length = columns.length
149
+
129
150
  @rows.map { |row|
130
151
  # In the past we used Hash[columns.zip(row)]
131
152
  # though elegant, the verbose way is much more efficient
@@ -134,8 +155,6 @@ module ActiveRecord
134
155
  hash = {}
135
156
 
136
157
  index = 0
137
- length = columns.length
138
-
139
158
  while index < length
140
159
  hash[columns[index]] = row[index]
141
160
  index += 1
@@ -61,8 +61,8 @@ module ActiveRecord
61
61
  # # => "id ASC"
62
62
  def sanitize_sql_for_order(condition)
63
63
  if condition.is_a?(Array) && condition.first.to_s.include?("?")
64
- enforce_raw_sql_whitelist([condition.first],
65
- whitelist: AttributeMethods::ClassMethods::COLUMN_NAME_ORDER_WHITELIST
64
+ disallow_raw_sql!([condition.first],
65
+ permit: AttributeMethods::ClassMethods::COLUMN_NAME_WITH_ORDER
66
66
  )
67
67
 
68
68
  # Ensure we aren't dealing with a subclass of String that might
@@ -134,43 +134,6 @@ module ActiveRecord
134
134
  end
135
135
 
136
136
  private
137
- # Accepts a hash of SQL conditions and replaces those attributes
138
- # that correspond to a {#composed_of}[rdoc-ref:Aggregations::ClassMethods#composed_of]
139
- # relationship with their expanded aggregate attribute values.
140
- #
141
- # Given:
142
- #
143
- # class Person < ActiveRecord::Base
144
- # composed_of :address, class_name: "Address",
145
- # mapping: [%w(address_street street), %w(address_city city)]
146
- # end
147
- #
148
- # Then:
149
- #
150
- # { address: Address.new("813 abc st.", "chicago") }
151
- # # => { address_street: "813 abc st.", address_city: "chicago" }
152
- def expand_hash_conditions_for_aggregates(attrs) # :doc:
153
- expanded_attrs = {}
154
- attrs.each do |attr, value|
155
- if aggregation = reflect_on_aggregation(attr.to_sym)
156
- mapping = aggregation.mapping
157
- mapping.each do |field_attr, aggregate_attr|
158
- expanded_attrs[field_attr] = if value.is_a?(Array)
159
- value.map { |it| it.send(aggregate_attr) }
160
- elsif mapping.size == 1 && !value.respond_to?(aggregate_attr)
161
- value
162
- else
163
- value.send(aggregate_attr)
164
- end
165
- end
166
- else
167
- expanded_attrs[attr] = value
168
- end
169
- end
170
- expanded_attrs
171
- end
172
- deprecate :expand_hash_conditions_for_aggregates
173
-
174
137
  def replace_bind_variables(statement, values)
175
138
  raise_if_bind_arity_mismatch(statement, statement.count("?"), values.size)
176
139
  bound = values.dup
@@ -51,20 +51,11 @@ module ActiveRecord
51
51
 
52
52
  if info[:version].present?
53
53
  ActiveRecord::SchemaMigration.create_table
54
- connection.assume_migrated_upto_version(info[:version], migrations_paths)
54
+ connection.assume_migrated_upto_version(info[:version])
55
55
  end
56
56
 
57
57
  ActiveRecord::InternalMetadata.create_table
58
58
  ActiveRecord::InternalMetadata[:environment] = connection.migration_context.current_environment
59
59
  end
60
-
61
- private
62
- # Returns the migrations paths.
63
- #
64
- # ActiveRecord::Schema.new.migrations_paths
65
- # # => ["db/migrate"] # Rails migration path by default.
66
- def migrations_paths
67
- ActiveRecord::Migrator.migrations_paths
68
- end
69
60
  end
70
61
  end
@@ -17,6 +17,12 @@ module ActiveRecord
17
17
  # Only strings are accepted if ActiveRecord::Base.schema_format == :sql.
18
18
  cattr_accessor :ignore_tables, default: []
19
19
 
20
+ ##
21
+ # :singleton-method:
22
+ # Specify a custom regular expression matching foreign keys which name
23
+ # should not be dumped to db/schema.rb.
24
+ cattr_accessor :fk_ignore_pattern, default: /^fk_rails_[0-9a-f]{10}$/
25
+
20
26
  class << self
21
27
  def dump(connection = ActiveRecord::Base.connection, stream = STDOUT, config = ActiveRecord::Base)
22
28
  connection.create_schema_dumper(generate_options(config)).dump(stream)
@@ -65,11 +71,11 @@ module ActiveRecord
65
71
  # of editing this file, please use the migrations feature of Active Record to
66
72
  # incrementally modify your database, and then regenerate this schema definition.
67
73
  #
68
- # Note that this schema.rb definition is the authoritative source for your
69
- # database schema. If you need to create the application database on another
70
- # system, you should be using db:schema:load, not running all the migrations
71
- # from scratch. The latter is a flawed and unsustainable approach (the more migrations
72
- # you'll amass, the slower it'll run and the greater likelihood for issues).
74
+ # This file is the source Rails uses to define your schema when running `rails
75
+ # db:schema:load`. When creating a new database, `rails db:schema:load` tends to
76
+ # be faster and is potentially less error prone than running all of your
77
+ # migrations from scratch. Old migrations may fail to apply correctly if those
78
+ # migrations use external dependencies or application code.
73
79
  #
74
80
  # It's strongly recommended that you check this file into your version control system.
75
81
 
@@ -210,7 +216,7 @@ HEADER
210
216
  parts << "primary_key: #{foreign_key.primary_key.inspect}"
211
217
  end
212
218
 
213
- if foreign_key.name !~ /^fk_rails_[0-9a-f]{10}$/
219
+ if foreign_key.export_name_on_schema_dump?
214
220
  parts << "name: #{foreign_key.name.inspect}"
215
221
  end
216
222
 
@@ -10,6 +10,10 @@ module ActiveRecord
10
10
  # to be executed the next time.
11
11
  class SchemaMigration < ActiveRecord::Base # :nodoc:
12
12
  class << self
13
+ def _internal?
14
+ true
15
+ end
16
+
13
17
  def primary_key
14
18
  "version"
15
19
  end
@@ -31,7 +31,14 @@ module ActiveRecord
31
31
  # Post.limit(10) # Fires "SELECT * FROM posts LIMIT 10"
32
32
  # }
33
33
  def unscoped
34
- block_given? ? relation.scoping { yield } : relation
34
+ block_given? ? _scoping(relation) { yield } : relation
35
+ end
36
+
37
+ def _scoping(relation) # :nodoc:
38
+ previous, self.current_scope = current_scope(true), relation
39
+ yield
40
+ ensure
41
+ self.current_scope = previous
35
42
  end
36
43
 
37
44
  # Are there attributes associated with this scope?
@@ -86,8 +93,8 @@ module ActiveRecord
86
93
  # # Should return a scope, you can call 'super' here etc.
87
94
  # end
88
95
  # end
89
- def default_scope(scope = nil, &block) # :doc:
90
- scope = block if block_given?
96
+ def default_scope(scope = nil) # :doc:
97
+ scope = Proc.new if block_given?
91
98
 
92
99
  if scope.is_a?(Relation) || !scope.respond_to?(:call)
93
100
  raise ArgumentError,
@@ -24,13 +24,13 @@ module ActiveRecord
24
24
  # You can define a scope that applies to all finders using
25
25
  # {default_scope}[rdoc-ref:Scoping::Default::ClassMethods#default_scope].
26
26
  def all
27
- current_scope = self.current_scope
27
+ scope = current_scope
28
28
 
29
- if current_scope
30
- if self == current_scope.klass
31
- current_scope.clone
29
+ if scope
30
+ if self == scope.klass
31
+ scope.clone
32
32
  else
33
- relation.merge!(current_scope)
33
+ relation.merge!(scope)
34
34
  end
35
35
  else
36
36
  default_scoped
@@ -38,9 +38,7 @@ module ActiveRecord
38
38
  end
39
39
 
40
40
  def scope_for_association(scope = relation) # :nodoc:
41
- current_scope = self.current_scope
42
-
43
- if current_scope && current_scope.empty_scope?
41
+ if current_scope&.empty_scope?
44
42
  scope
45
43
  else
46
44
  default_scoped(scope)
@@ -181,16 +179,14 @@ module ActiveRecord
181
179
  extension = Module.new(&block) if block
182
180
 
183
181
  if body.respond_to?(:to_proc)
184
- singleton_class.send(:define_method, name) do |*args|
185
- scope = all
186
- scope = scope._exec_scope(*args, &body)
182
+ singleton_class.define_method(name) do |*args|
183
+ scope = all._exec_scope(*args, &body)
187
184
  scope = scope.extending(extension) if extension
188
185
  scope
189
186
  end
190
187
  else
191
- singleton_class.send(:define_method, name) do |*args|
192
- scope = all
193
- scope = scope.scoping { body.call(*args) || scope }
188
+ singleton_class.define_method(name) do |*args|
189
+ scope = body.call(*args) || all
194
190
  scope = scope.extending(extension) if extension
195
191
  scope
196
192
  end
@@ -12,14 +12,6 @@ module ActiveRecord
12
12
  end
13
13
 
14
14
  module ClassMethods # :nodoc:
15
- def current_scope(skip_inherited_scope = false)
16
- ScopeRegistry.value_for(:current_scope, self, skip_inherited_scope)
17
- end
18
-
19
- def current_scope=(scope)
20
- ScopeRegistry.set_value_for(:current_scope, self, scope)
21
- end
22
-
23
15
  # Collects attributes from scopes that should be applied when creating
24
16
  # an AR instance for the particular class this is called on.
25
17
  def scope_attributes
@@ -30,6 +22,15 @@ module ActiveRecord
30
22
  def scope_attributes?
31
23
  current_scope
32
24
  end
25
+
26
+ private
27
+ def current_scope(skip_inherited_scope = false)
28
+ ScopeRegistry.value_for(:current_scope, self, skip_inherited_scope)
29
+ end
30
+
31
+ def current_scope=(scope)
32
+ ScopeRegistry.set_value_for(:current_scope, self, scope)
33
+ end
33
34
  end
34
35
 
35
36
  def populate_with_current_scope_attributes # :nodoc: