activerecord 6.1.0.rc2 → 6.1.3

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 (58) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +206 -19
  3. data/README.rdoc +1 -1
  4. data/lib/active_record/aggregations.rb +4 -4
  5. data/lib/active_record/association_relation.rb +10 -0
  6. data/lib/active_record/associations.rb +6 -2
  7. data/lib/active_record/associations/association.rb +7 -7
  8. data/lib/active_record/associations/association_scope.rb +7 -5
  9. data/lib/active_record/associations/belongs_to_association.rb +7 -3
  10. data/lib/active_record/associations/belongs_to_polymorphic_association.rb +7 -2
  11. data/lib/active_record/associations/builder/association.rb +23 -2
  12. data/lib/active_record/associations/builder/belongs_to.rb +2 -2
  13. data/lib/active_record/associations/has_many_association.rb +1 -1
  14. data/lib/active_record/associations/join_dependency.rb +2 -2
  15. data/lib/active_record/associations/join_dependency/join_association.rb +8 -7
  16. data/lib/active_record/attribute_methods.rb +13 -7
  17. data/lib/active_record/attributes.rb +1 -1
  18. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +4 -4
  19. data/lib/active_record/connection_adapters/abstract/database_statements.rb +1 -1
  20. data/lib/active_record/connection_adapters/abstract/query_cache.rb +1 -1
  21. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +4 -0
  22. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +7 -1
  23. data/lib/active_record/connection_adapters/abstract_adapter.rb +7 -8
  24. data/lib/active_record/connection_adapters/mysql/quoting.rb +17 -2
  25. data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +4 -1
  26. data/lib/active_record/connection_adapters/pool_config.rb +13 -3
  27. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +1 -1
  28. data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +8 -0
  29. data/lib/active_record/connection_adapters/postgresql/oid/money.rb +2 -2
  30. data/lib/active_record/connection_adapters/postgresql_adapter.rb +2 -8
  31. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +1 -1
  32. data/lib/active_record/connection_handling.rb +20 -12
  33. data/lib/active_record/core.rb +43 -32
  34. data/lib/active_record/database_configurations/url_config.rb +1 -1
  35. data/lib/active_record/enum.rb +58 -31
  36. data/lib/active_record/fixtures.rb +5 -2
  37. data/lib/active_record/gem_version.rb +2 -2
  38. data/lib/active_record/locking/optimistic.rb +14 -4
  39. data/lib/active_record/log_subscriber.rb +3 -2
  40. data/lib/active_record/migration.rb +1 -1
  41. data/lib/active_record/migration/compatibility.rb +2 -1
  42. data/lib/active_record/model_schema.rb +4 -4
  43. data/lib/active_record/railtie.rb +1 -1
  44. data/lib/active_record/railties/console_sandbox.rb +2 -4
  45. data/lib/active_record/railties/databases.rake +13 -7
  46. data/lib/active_record/reflection.rb +1 -1
  47. data/lib/active_record/relation.rb +1 -2
  48. data/lib/active_record/relation/finder_methods.rb +1 -1
  49. data/lib/active_record/relation/predicate_builder.rb +7 -8
  50. data/lib/active_record/relation/predicate_builder/association_query_value.rb +3 -3
  51. data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +9 -5
  52. data/lib/active_record/relation/query_methods.rb +9 -6
  53. data/lib/active_record/relation/where_clause.rb +5 -5
  54. data/lib/active_record/signed_id.rb +1 -1
  55. data/lib/active_record/table_metadata.rb +6 -3
  56. data/lib/active_record/tasks/database_tasks.rb +1 -0
  57. data/lib/active_record/transactions.rb +4 -2
  58. metadata +15 -15
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: b093236482caac43173dfffd7096282d55d6fc0099ed9f6e684b84efabfbb466
4
- data.tar.gz: ef623a179fbabb3fd9aa544baf87da3bf342cca09dd6a2bf9bd3f4d2435410a8
3
+ metadata.gz: 6cdd6094f92ff2d3eef67e5ab7f2a8e2a327fbdffaa1f20182fb5bdb7c803685
4
+ data.tar.gz: 197e68aa68f0946e9fcd55c7f0c2f41c237777c893b20a3a00affddbcaa1f367
5
5
  SHA512:
6
- metadata.gz: 3ba3873e17ac4ad32e19d81a7669b24024195986c8cbbf9eb54ae9ecf798d9f82369594051712609458bf84f4bb58228c0dfcef9ce21cb8926dd07dd898efaba
7
- data.tar.gz: 8fadd55a99b48ba91ec273fc76d24d3257d67c89999fde3851547b29711244b649edccbeb9c4ff9ba326348a61be4da361fd49f35dcd55109c19ada385f47de6
6
+ metadata.gz: 4b9b18c89048afe658359cd16b4c13c3a1eb87c8dacae3beeaf99338e2e441f64fd96bf569697cd581ea35f3068f33ee7872f733570f621a774c92b04253dc5e
7
+ data.tar.gz: 4d47d251881e21878596707b1d759f40b8b83a02e759cb1af79d8293498251a6ff3f5b11e4ecdc004ac282c6fc84437bcc60469bf0ed0a880aae1e820e20d4a1
data/CHANGELOG.md CHANGED
@@ -1,4 +1,194 @@
1
- ## Rails 6.1.0.rc2 (December 01, 2020) ##
1
+ ## Rails 6.1.3 (February 17, 2021) ##
2
+
3
+ * Fix the MySQL adapter to always set the right collation and charset
4
+ to the connection session.
5
+
6
+ *Rafael Mendonça França*
7
+
8
+ * Fix MySQL adapter handling of time objects when prepared statements
9
+ are enabled.
10
+
11
+ *Rafael Mendonça França*
12
+
13
+ * Fix scoping in enum fields using conditions that would generate
14
+ an `IN` clause.
15
+
16
+ *Ryuta Kamizono*
17
+
18
+ * Skip optimised #exist? query when #include? is called on a relation
19
+ with a having clause
20
+
21
+ Relations that have aliased select values AND a having clause that
22
+ references an aliased select value would generate an error when
23
+ #include? was called, due to an optimisation that would generate
24
+ call #exists? on the relation instead, which effectively alters
25
+ the select values of the query (and thus removes the aliased select
26
+ values), but leaves the having clause intact. Because the having
27
+ clause is then referencing an aliased column that is no longer
28
+ present in the simplified query, an ActiveRecord::InvalidStatement
29
+ error was raised.
30
+
31
+ An sample query affected by this problem:
32
+
33
+ ```ruby
34
+ Author.select('COUNT(*) as total_posts', 'authors.*')
35
+ .joins(:posts)
36
+ .group(:id)
37
+ .having('total_posts > 2')
38
+ .include?(Author.first)
39
+ ```
40
+
41
+ This change adds an addition check to the condition that skips the
42
+ simplified #exists? query, which simply checks for the presence of
43
+ a having clause.
44
+
45
+ Fixes #41417
46
+
47
+ *Michael Smart*
48
+
49
+ * Increment postgres prepared statement counter before making a prepared statement, so if the statement is aborted
50
+ without Rails knowledge (e.g., if app gets kill -9d during long-running query or due to Rack::Timeout), app won't end
51
+ up in perpetual crash state for being inconsistent with Postgres.
52
+
53
+ *wbharding*, *Martin Tepper*
54
+
55
+
56
+ ## Rails 6.1.2.1 (February 10, 2021) ##
57
+
58
+ * Fix possible DoS vector in PostgreSQL money type
59
+
60
+ Carefully crafted input can cause a DoS via the regular expressions used
61
+ for validating the money format in the PostgreSQL adapter. This patch
62
+ fixes the regexp.
63
+
64
+ Thanks to @dee-see from Hackerone for this patch!
65
+
66
+ [CVE-2021-22880]
67
+
68
+ *Aaron Patterson*
69
+
70
+
71
+ ## Rails 6.1.2 (February 09, 2021) ##
72
+
73
+ * Fix timestamp type for sqlite3.
74
+
75
+ *Eileen M. Uchitelle*
76
+
77
+ * Make destroy async transactional.
78
+
79
+ An active record rollback could occur while enqueuing a job. In this
80
+ case the job would enqueue even though the database deletion
81
+ rolledback putting things in a funky state.
82
+
83
+ Now the jobs are only enqueued until after the db transaction has been committed.
84
+
85
+ *Cory Gwin*
86
+
87
+ * Fix malformed packet error in MySQL statement for connection configuration.
88
+
89
+ *robinroestenburg*
90
+
91
+ * Connection specification now passes the "url" key as a configuration for the
92
+ adapter if the "url" protocol is "jdbc", "http", or "https". Previously only
93
+ urls with the "jdbc" prefix were passed to the Active Record Adapter, others
94
+ are assumed to be adapter specification urls.
95
+
96
+ Fixes #41137.
97
+
98
+ *Jonathan Bracy*
99
+
100
+ * Fix granular connection swapping when there are multiple abstract classes.
101
+
102
+ *Eileen M. Uchitelle*
103
+
104
+ * Fix `find_by` with custom primary key for belongs_to association.
105
+
106
+ *Ryuta Kamizono*
107
+
108
+ * Add support for `rails console --sandbox` for multiple database applications.
109
+
110
+ *alpaca-tc*
111
+
112
+ * Fix `where` on polymorphic association with empty array.
113
+
114
+ *Ryuta Kamizono*
115
+
116
+ * Fix preventing writes for `ApplicationRecord`.
117
+
118
+ *Eileen M. Uchitelle*
119
+
120
+
121
+ ## Rails 6.1.1 (January 07, 2021) ##
122
+
123
+ * Fix fixtures loading when strict loading is enabled for the association.
124
+
125
+ *Alex Ghiculescu*
126
+
127
+ * Fix `where` with custom primary key for belongs_to association.
128
+
129
+ *Ryuta Kamizono*
130
+
131
+ * Fix `where` with aliased associations.
132
+
133
+ *Ryuta Kamizono*
134
+
135
+ * Fix `composed_of` with symbol mapping.
136
+
137
+ *Ryuta Kamizono*
138
+
139
+ * Don't skip money's type cast for pluck and calculations.
140
+
141
+ *Ryuta Kamizono*
142
+
143
+ * Fix `where` on polymorphic association with non Active Record object.
144
+
145
+ *Ryuta Kamizono*
146
+
147
+ * Make sure `db:prepare` works even the schema file doesn't exist.
148
+
149
+ *Rafael Mendonça França*
150
+
151
+ * Fix complicated `has_many :through` with nested where condition.
152
+
153
+ *Ryuta Kamizono*
154
+
155
+ * Handle STI models for `has_many dependent: :destroy_async`.
156
+
157
+ *Muhammad Usman*
158
+
159
+ * Restore possibility of passing `false` to :polymorphic option of `belongs_to`.
160
+
161
+ Previously, passing `false` would trigger the option validation logic
162
+ to throw an error saying :polymorphic would not be a valid option.
163
+
164
+ *glaszig*
165
+
166
+ * Allow adding nonnamed expression indexes to be revertible.
167
+
168
+ Fixes #40732.
169
+
170
+ Previously, the following code would raise an error, when executed while rolling back,
171
+ and the index name should be specified explicitly. Now, the index name is inferred
172
+ automatically.
173
+
174
+ ```ruby
175
+ add_index(:items, "to_tsvector('english', description)")
176
+ ```
177
+
178
+ *fatkodima*
179
+
180
+
181
+ ## Rails 6.1.0 (December 09, 2020) ##
182
+
183
+ * Only warn about negative enums if a positive form that would cause conflicts exists.
184
+
185
+ Fixes #39065.
186
+
187
+ *Alex Ghiculescu*
188
+
189
+ * Change `attribute_for_inspect` to take `filter_attributes` in consideration.
190
+
191
+ *Rafael Mendonça França*
2
192
 
3
193
  * Fix odd behavior of inverse_of with multiple belongs_to to same class.
4
194
 
@@ -22,30 +212,27 @@
22
212
 
23
213
  *Sean Doyle*
24
214
 
25
-
26
- ## Rails 6.1.0.rc1 (November 02, 2020) ##
27
-
28
215
  * Add `connected_to_many` API.
29
216
 
30
217
  This API allows applications to connect to multiple databases at once without switching all of them or implementing a deeply nested stack.
31
218
 
32
219
  Before:
33
220
 
34
- AnimalsRecord.connected_to(role: :reading) do
35
- MealsRecord.connected_to(role: :reading) do
36
- Dog.first # read from animals replica
37
- Dinner.first # read from meals replica
38
- Person.first # read from primary writer
221
+ AnimalsRecord.connected_to(role: :reading) do
222
+ MealsRecord.connected_to(role: :reading) do
223
+ Dog.first # read from animals replica
224
+ Dinner.first # read from meals replica
225
+ Person.first # read from primary writer
226
+ end
39
227
  end
40
- end
41
228
 
42
229
  After:
43
230
 
44
- ActiveRecord::Base.connected_to_many([AnimalsRecord, MealsRecord], role: :reading) do
45
- Dog.first # read from animals replica
46
- Dinner.first # read from meals replica
47
- Person.first # read from primary writer
48
- end
231
+ ActiveRecord::Base.connected_to_many([AnimalsRecord, MealsRecord], role: :reading) do
232
+ Dog.first # read from animals replica
233
+ Dinner.first # read from meals replica
234
+ Person.first # read from primary writer
235
+ end
49
236
 
50
237
  *Eileen M. Uchitelle*, *John Crepezzi*
51
238
 
@@ -163,13 +350,13 @@
163
350
 
164
351
  Before:
165
352
 
166
- User.where.not(name: "Jon", role: "admin")
167
- # SELECT * FROM users WHERE name != 'Jon' AND role != 'admin'
353
+ User.where.not(name: "Jon", role: "admin")
354
+ # SELECT * FROM users WHERE name != 'Jon' AND role != 'admin'
168
355
 
169
356
  After:
170
357
 
171
- User.where.not(name: "Jon", role: "admin")
172
- # SELECT * FROM users WHERE NOT (name == 'Jon' AND role == 'admin')
358
+ User.where.not(name: "Jon", role: "admin")
359
+ # SELECT * FROM users WHERE NOT (name == 'Jon' AND role == 'admin')
173
360
 
174
361
  *Rafael Mendonça França*
175
362
 
data/README.rdoc CHANGED
@@ -194,7 +194,7 @@ The latest version of Active Record can be installed with RubyGems:
194
194
 
195
195
  Source code can be downloaded as part of the Rails project on GitHub:
196
196
 
197
- * https://github.com/rails/rails/tree/master/activerecord
197
+ * https://github.com/rails/rails/tree/main/activerecord
198
198
 
199
199
 
200
200
  == License
@@ -244,8 +244,8 @@ module ActiveRecord
244
244
  private
245
245
  def reader_method(name, class_name, mapping, allow_nil, constructor)
246
246
  define_method(name) do
247
- if @aggregation_cache[name].nil? && (!allow_nil || mapping.any? { |key, _| !_read_attribute(key).nil? })
248
- attrs = mapping.collect { |key, _| _read_attribute(key) }
247
+ if @aggregation_cache[name].nil? && (!allow_nil || mapping.any? { |key, _| !read_attribute(key).nil? })
248
+ attrs = mapping.collect { |key, _| read_attribute(key) }
249
249
  object = constructor.respond_to?(:call) ?
250
250
  constructor.call(*attrs) :
251
251
  class_name.constantize.send(constructor, *attrs)
@@ -271,10 +271,10 @@ module ActiveRecord
271
271
  end
272
272
 
273
273
  if part.nil? && allow_nil
274
- mapping.each { |key, _| self[key] = nil }
274
+ mapping.each { |key, _| write_attribute(key, nil) }
275
275
  @aggregation_cache[name] = nil
276
276
  else
277
- mapping.each { |key, value| self[key] = part.send(value) }
277
+ mapping.each { |key, value| write_attribute(key, part.send(value)) }
278
278
  @aggregation_cache[name] = part.freeze
279
279
  end
280
280
  end
@@ -27,6 +27,16 @@ module ActiveRecord
27
27
  RUBY
28
28
  end
29
29
 
30
+ def build(attributes = nil, &block)
31
+ if attributes.is_a?(Array)
32
+ attributes.collect { |attr| build(attr, &block) }
33
+ else
34
+ block = current_scope_restoring_block(&block)
35
+ scoping { _new(attributes, &block) }
36
+ end
37
+ end
38
+ alias new build
39
+
30
40
  private
31
41
  def _new(attributes, &block)
32
42
  @association.build(attributes, &block)
@@ -1371,7 +1371,9 @@ module ActiveRecord
1371
1371
  #
1372
1372
  # * <tt>nil</tt> do nothing (default).
1373
1373
  # * <tt>:destroy</tt> causes all the associated objects to also be destroyed.
1374
- # * <tt>:destroy_async</tt> destroys all the associated objects in a background job.
1374
+ # * <tt>:destroy_async</tt> destroys all the associated objects in a background job. <b>WARNING:</b> Do not use
1375
+ # this option if the association is backed by foreign key constraints in your database. The foreign key
1376
+ # constraint actions will occur inside the same transaction that deletes its owner.
1375
1377
  # * <tt>:delete_all</tt> causes all the associated objects to be deleted directly from the database (so callbacks will not be executed).
1376
1378
  # * <tt>:nullify</tt> causes the foreign keys to be set to +NULL+. Polymorphic type will also be nullified
1377
1379
  # on polymorphic associations. Callbacks are not executed.
@@ -1523,7 +1525,9 @@ module ActiveRecord
1523
1525
  #
1524
1526
  # * <tt>nil</tt> do nothing (default).
1525
1527
  # * <tt>:destroy</tt> causes the associated object to also be destroyed
1526
- # * <tt>:destroy_async</tt> causes all the associated object to be destroyed in a background job.
1528
+ # * <tt>:destroy_async</tt> causes the associated object to be destroyed in a background job. <b>WARNING:</b> Do not use
1529
+ # this option if the association is backed by foreign key constraints in your database. The foreign key
1530
+ # constraint actions will occur inside the same transaction that deletes its owner.
1527
1531
  # * <tt>:delete</tt> causes the associated object to be deleted directly from the database (so callbacks will not execute)
1528
1532
  # * <tt>:nullify</tt> causes the foreign key to be set to +NULL+. Polymorphic type column is also nullified
1529
1533
  # on polymorphic associations. Callbacks are not executed.
@@ -211,12 +211,8 @@ module ActiveRecord
211
211
 
212
212
  private
213
213
  def find_target
214
- if owner.strict_loading?
215
- Base.strict_loading_violation!(owner: owner.class, association: klass)
216
- end
217
-
218
- if reflection.strict_loading?
219
- Base.strict_loading_violation!(owner: owner.class, association: reflection.name)
214
+ if (owner.strict_loading? || reflection.strict_loading?) && owner.validation_context.nil?
215
+ Base.strict_loading_violation!(owner: owner.class, reflection: reflection)
220
216
  end
221
217
 
222
218
  scope = self.scope
@@ -331,7 +327,11 @@ module ActiveRecord
331
327
  end
332
328
 
333
329
  def enqueue_destroy_association(options)
334
- owner.class.destroy_association_async_job&.perform_later(**options)
330
+ job_class = owner.class.destroy_association_async_job
331
+
332
+ if job_class
333
+ owner._after_commit_jobs.push([job_class, options])
334
+ end
335
335
  end
336
336
 
337
337
  def inversable?(record)
@@ -131,11 +131,13 @@ module ActiveRecord
131
131
  if scope_chain_item == chain_head.scope
132
132
  scope.merge! item.except(:where, :includes, :unscope, :order)
133
133
  elsif !item.references_values.empty?
134
- join_dependency = item.construct_join_dependency(
135
- item.eager_load_values | item.includes_values, Arel::Nodes::OuterJoin
136
- )
137
- scope.joins!(*item.joins_values, join_dependency)
138
- scope.left_outer_joins!(*item.left_outer_joins_values)
134
+ scope.merge! item.only(:joins, :left_outer_joins)
135
+
136
+ associations = item.eager_load_values | item.includes_values
137
+
138
+ unless associations.empty?
139
+ scope.joins! item.construct_join_dependency(associations, Arel::Nodes::OuterJoin)
140
+ end
139
141
  end
140
142
 
141
143
  reflection.all_includes do
@@ -80,7 +80,7 @@ module ActiveRecord
80
80
  @updated = true
81
81
  end
82
82
 
83
- replace_keys(record)
83
+ replace_keys(record, force: true)
84
84
 
85
85
  self.target = record
86
86
  end
@@ -108,8 +108,12 @@ module ActiveRecord
108
108
  reflection.counter_cache_column && owner.persisted?
109
109
  end
110
110
 
111
- def replace_keys(record)
112
- owner[reflection.foreign_key] = record ? record._read_attribute(primary_key(record.class)) : nil
111
+ def replace_keys(record, force: false)
112
+ target_key = record ? record._read_attribute(primary_key(record.class)) : nil
113
+
114
+ if force || owner[reflection.foreign_key] != target_key
115
+ owner[reflection.foreign_key] = target_key
116
+ end
113
117
  end
114
118
 
115
119
  def primary_key(klass)
@@ -14,9 +14,14 @@ module ActiveRecord
14
14
  end
15
15
 
16
16
  private
17
- def replace_keys(record)
17
+ def replace_keys(record, force: false)
18
18
  super
19
- owner[reflection.foreign_type] = record ? record.class.polymorphic_name : nil
19
+
20
+ target_type = record ? record.class.polymorphic_name : nil
21
+
22
+ if force || owner[reflection.foreign_type] != target_type
23
+ owner[reflection.foreign_type] = target_type
24
+ end
20
25
  end
21
26
 
22
27
  def inverse_reflection_for(record)
@@ -76,6 +76,7 @@ module ActiveRecord::Associations::Builder # :nodoc:
76
76
  if dependent = reflection.options[:dependent]
77
77
  check_dependent_options(dependent, model)
78
78
  add_destroy_callbacks(model, reflection)
79
+ add_after_commit_jobs_callback(model, dependent)
79
80
  end
80
81
 
81
82
  Association.extensions.each do |extension|
@@ -132,11 +133,31 @@ module ActiveRecord::Associations::Builder # :nodoc:
132
133
 
133
134
  def self.add_destroy_callbacks(model, reflection)
134
135
  name = reflection.name
135
- model.before_destroy lambda { |o| o.association(name).handle_dependency }
136
+ model.before_destroy(->(o) { o.association(name).handle_dependency })
137
+ end
138
+
139
+ def self.add_after_commit_jobs_callback(model, dependent)
140
+ if dependent == :destroy_async
141
+ mixin = model.generated_association_methods
142
+
143
+ unless mixin.method_defined?(:_after_commit_jobs)
144
+ model.after_commit(-> do
145
+ _after_commit_jobs.each do |job_class, job_arguments|
146
+ job_class.perform_later(**job_arguments)
147
+ end
148
+ end)
149
+
150
+ mixin.class_eval <<-CODE, __FILE__, __LINE__ + 1
151
+ def _after_commit_jobs
152
+ @_after_commit_jobs ||= []
153
+ end
154
+ CODE
155
+ end
156
+ end
136
157
  end
137
158
 
138
159
  private_class_method :build_scope, :macro, :valid_options, :validate_options, :define_extensions,
139
160
  :define_callbacks, :define_accessors, :define_readers, :define_writers, :define_validations,
140
- :valid_dependent_options, :check_dependent_options, :add_destroy_callbacks
161
+ :valid_dependent_options, :check_dependent_options, :add_destroy_callbacks, :add_after_commit_jobs_callback
141
162
  end
142
163
  end