activerecord 6.1.0 → 6.1.3.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 (55) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +200 -15
  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 +1 -1
  15. data/lib/active_record/associations/join_dependency/join_association.rb +8 -7
  16. data/lib/active_record/attributes.rb +1 -1
  17. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +4 -4
  18. data/lib/active_record/connection_adapters/abstract/database_statements.rb +1 -1
  19. data/lib/active_record/connection_adapters/abstract/query_cache.rb +1 -1
  20. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +4 -0
  21. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +7 -1
  22. data/lib/active_record/connection_adapters/abstract_adapter.rb +7 -8
  23. data/lib/active_record/connection_adapters/mysql/quoting.rb +17 -2
  24. data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +4 -1
  25. data/lib/active_record/connection_adapters/pool_config.rb +13 -3
  26. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +1 -1
  27. data/lib/active_record/connection_adapters/postgresql/oid/money.rb +2 -2
  28. data/lib/active_record/connection_adapters/postgresql_adapter.rb +2 -8
  29. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +1 -1
  30. data/lib/active_record/connection_handling.rb +20 -12
  31. data/lib/active_record/core.rb +42 -24
  32. data/lib/active_record/database_configurations/url_config.rb +1 -1
  33. data/lib/active_record/enum.rb +48 -28
  34. data/lib/active_record/fixtures.rb +5 -2
  35. data/lib/active_record/gem_version.rb +2 -2
  36. data/lib/active_record/locking/optimistic.rb +14 -4
  37. data/lib/active_record/log_subscriber.rb +3 -2
  38. data/lib/active_record/migration.rb +1 -1
  39. data/lib/active_record/migration/compatibility.rb +2 -1
  40. data/lib/active_record/model_schema.rb +4 -4
  41. data/lib/active_record/railties/console_sandbox.rb +2 -4
  42. data/lib/active_record/railties/databases.rake +13 -7
  43. data/lib/active_record/reflection.rb +1 -1
  44. data/lib/active_record/relation.rb +1 -2
  45. data/lib/active_record/relation/finder_methods.rb +1 -1
  46. data/lib/active_record/relation/predicate_builder.rb +5 -6
  47. data/lib/active_record/relation/predicate_builder/association_query_value.rb +3 -3
  48. data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +9 -5
  49. data/lib/active_record/relation/query_methods.rb +8 -5
  50. data/lib/active_record/relation/where_clause.rb +5 -5
  51. data/lib/active_record/signed_id.rb +1 -1
  52. data/lib/active_record/table_metadata.rb +6 -3
  53. data/lib/active_record/tasks/database_tasks.rb +1 -0
  54. data/lib/active_record/transactions.rb +4 -2
  55. metadata +10 -10
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 418812373f3ff5fd16133fe0928b94b80b78b8a366abfc23a205fcb2ccc5a3e3
4
- data.tar.gz: 70db1902a8fc82b1c46f8a7731ffb358357bc8cac29564a57881a732dbd2a65a
3
+ metadata.gz: a6a73442f7b3996c8742fbdaddb78012145e7321e67873b9b3326bd7deb3d0ee
4
+ data.tar.gz: c1ddaf64625c98f4467998f98978232f9c17c245ba0650b7cee93c9d53e88be3
5
5
  SHA512:
6
- metadata.gz: 31ae64f629cb62f63bc37c74a888d557f9f0b102d401f2f9cf62c7d31655d99e5161ae9bc7f8be874c7a9cf27ec879dde3c04075df5cb2b5868891c0db144a50
7
- data.tar.gz: cfc9585f3a6f53187707a9d96503269e3d4b1c5f1fe8c5f4db3bdefe8ce636042b6cf1fe9fb233491d1e8197f52293a7018a2f9925f1e34644ad1e30b134d59f
6
+ metadata.gz: 4b90ced681f18f7685128f85d8be8c68cca244991999d4d05ec76b54513a34a3fab490798e9dd95e853a87550151e03b873007f57380b0baf39ea1bf93539351
7
+ data.tar.gz: 6e7e52edeb4a03f2088ee50a3823fe1dd07eacdfb4fd7ff4dde7ee2984e92385f0f3d8d91f7598a76082986720e5967ca99c395ce20f9fd7c4a9531642ae8701
data/CHANGELOG.md CHANGED
@@ -1,3 +1,188 @@
1
+ ## Rails 6.1.3.1 (March 26, 2021) ##
2
+
3
+ * No changes.
4
+
5
+
6
+ ## Rails 6.1.3 (February 17, 2021) ##
7
+
8
+ * Fix the MySQL adapter to always set the right collation and charset
9
+ to the connection session.
10
+
11
+ *Rafael Mendonça França*
12
+
13
+ * Fix MySQL adapter handling of time objects when prepared statements
14
+ are enabled.
15
+
16
+ *Rafael Mendonça França*
17
+
18
+ * Fix scoping in enum fields using conditions that would generate
19
+ an `IN` clause.
20
+
21
+ *Ryuta Kamizono*
22
+
23
+ * Skip optimised #exist? query when #include? is called on a relation
24
+ with a having clause
25
+
26
+ Relations that have aliased select values AND a having clause that
27
+ references an aliased select value would generate an error when
28
+ #include? was called, due to an optimisation that would generate
29
+ call #exists? on the relation instead, which effectively alters
30
+ the select values of the query (and thus removes the aliased select
31
+ values), but leaves the having clause intact. Because the having
32
+ clause is then referencing an aliased column that is no longer
33
+ present in the simplified query, an ActiveRecord::InvalidStatement
34
+ error was raised.
35
+
36
+ An sample query affected by this problem:
37
+
38
+ ```ruby
39
+ Author.select('COUNT(*) as total_posts', 'authors.*')
40
+ .joins(:posts)
41
+ .group(:id)
42
+ .having('total_posts > 2')
43
+ .include?(Author.first)
44
+ ```
45
+
46
+ This change adds an addition check to the condition that skips the
47
+ simplified #exists? query, which simply checks for the presence of
48
+ a having clause.
49
+
50
+ Fixes #41417
51
+
52
+ *Michael Smart*
53
+
54
+ * Increment postgres prepared statement counter before making a prepared statement, so if the statement is aborted
55
+ without Rails knowledge (e.g., if app gets kill -9d during long-running query or due to Rack::Timeout), app won't end
56
+ up in perpetual crash state for being inconsistent with Postgres.
57
+
58
+ *wbharding*, *Martin Tepper*
59
+
60
+
61
+ ## Rails 6.1.2.1 (February 10, 2021) ##
62
+
63
+ * Fix possible DoS vector in PostgreSQL money type
64
+
65
+ Carefully crafted input can cause a DoS via the regular expressions used
66
+ for validating the money format in the PostgreSQL adapter. This patch
67
+ fixes the regexp.
68
+
69
+ Thanks to @dee-see from Hackerone for this patch!
70
+
71
+ [CVE-2021-22880]
72
+
73
+ *Aaron Patterson*
74
+
75
+
76
+ ## Rails 6.1.2 (February 09, 2021) ##
77
+
78
+ * Fix timestamp type for sqlite3.
79
+
80
+ *Eileen M. Uchitelle*
81
+
82
+ * Make destroy async transactional.
83
+
84
+ An active record rollback could occur while enqueuing a job. In this
85
+ case the job would enqueue even though the database deletion
86
+ rolledback putting things in a funky state.
87
+
88
+ Now the jobs are only enqueued until after the db transaction has been committed.
89
+
90
+ *Cory Gwin*
91
+
92
+ * Fix malformed packet error in MySQL statement for connection configuration.
93
+
94
+ *robinroestenburg*
95
+
96
+ * Connection specification now passes the "url" key as a configuration for the
97
+ adapter if the "url" protocol is "jdbc", "http", or "https". Previously only
98
+ urls with the "jdbc" prefix were passed to the Active Record Adapter, others
99
+ are assumed to be adapter specification urls.
100
+
101
+ Fixes #41137.
102
+
103
+ *Jonathan Bracy*
104
+
105
+ * Fix granular connection swapping when there are multiple abstract classes.
106
+
107
+ *Eileen M. Uchitelle*
108
+
109
+ * Fix `find_by` with custom primary key for belongs_to association.
110
+
111
+ *Ryuta Kamizono*
112
+
113
+ * Add support for `rails console --sandbox` for multiple database applications.
114
+
115
+ *alpaca-tc*
116
+
117
+ * Fix `where` on polymorphic association with empty array.
118
+
119
+ *Ryuta Kamizono*
120
+
121
+ * Fix preventing writes for `ApplicationRecord`.
122
+
123
+ *Eileen M. Uchitelle*
124
+
125
+
126
+ ## Rails 6.1.1 (January 07, 2021) ##
127
+
128
+ * Fix fixtures loading when strict loading is enabled for the association.
129
+
130
+ *Alex Ghiculescu*
131
+
132
+ * Fix `where` with custom primary key for belongs_to association.
133
+
134
+ *Ryuta Kamizono*
135
+
136
+ * Fix `where` with aliased associations.
137
+
138
+ *Ryuta Kamizono*
139
+
140
+ * Fix `composed_of` with symbol mapping.
141
+
142
+ *Ryuta Kamizono*
143
+
144
+ * Don't skip money's type cast for pluck and calculations.
145
+
146
+ *Ryuta Kamizono*
147
+
148
+ * Fix `where` on polymorphic association with non Active Record object.
149
+
150
+ *Ryuta Kamizono*
151
+
152
+ * Make sure `db:prepare` works even the schema file doesn't exist.
153
+
154
+ *Rafael Mendonça França*
155
+
156
+ * Fix complicated `has_many :through` with nested where condition.
157
+
158
+ *Ryuta Kamizono*
159
+
160
+ * Handle STI models for `has_many dependent: :destroy_async`.
161
+
162
+ *Muhammad Usman*
163
+
164
+ * Restore possibility of passing `false` to :polymorphic option of `belongs_to`.
165
+
166
+ Previously, passing `false` would trigger the option validation logic
167
+ to throw an error saying :polymorphic would not be a valid option.
168
+
169
+ *glaszig*
170
+
171
+ * Allow adding nonnamed expression indexes to be revertible.
172
+
173
+ Fixes #40732.
174
+
175
+ Previously, the following code would raise an error, when executed while rolling back,
176
+ and the index name should be specified explicitly. Now, the index name is inferred
177
+ automatically.
178
+
179
+ ```ruby
180
+ add_index(:items, "to_tsvector('english', description)")
181
+ ```
182
+
183
+ *fatkodima*
184
+
185
+
1
186
  ## Rails 6.1.0 (December 09, 2020) ##
2
187
 
3
188
  * Only warn about negative enums if a positive form that would cause conflicts exists.
@@ -38,21 +223,21 @@
38
223
 
39
224
  Before:
40
225
 
41
- AnimalsRecord.connected_to(role: :reading) do
42
- MealsRecord.connected_to(role: :reading) do
43
- Dog.first # read from animals replica
44
- Dinner.first # read from meals replica
45
- Person.first # read from primary writer
226
+ AnimalsRecord.connected_to(role: :reading) do
227
+ MealsRecord.connected_to(role: :reading) do
228
+ Dog.first # read from animals replica
229
+ Dinner.first # read from meals replica
230
+ Person.first # read from primary writer
231
+ end
46
232
  end
47
- end
48
233
 
49
234
  After:
50
235
 
51
- ActiveRecord::Base.connected_to_many([AnimalsRecord, MealsRecord], role: :reading) do
52
- Dog.first # read from animals replica
53
- Dinner.first # read from meals replica
54
- Person.first # read from primary writer
55
- end
236
+ ActiveRecord::Base.connected_to_many([AnimalsRecord, MealsRecord], role: :reading) do
237
+ Dog.first # read from animals replica
238
+ Dinner.first # read from meals replica
239
+ Person.first # read from primary writer
240
+ end
56
241
 
57
242
  *Eileen M. Uchitelle*, *John Crepezzi*
58
243
 
@@ -170,13 +355,13 @@
170
355
 
171
356
  Before:
172
357
 
173
- User.where.not(name: "Jon", role: "admin")
174
- # SELECT * FROM users WHERE name != 'Jon' AND role != 'admin'
358
+ User.where.not(name: "Jon", role: "admin")
359
+ # SELECT * FROM users WHERE name != 'Jon' AND role != 'admin'
175
360
 
176
361
  After:
177
362
 
178
- User.where.not(name: "Jon", role: "admin")
179
- # SELECT * FROM users WHERE NOT (name == 'Jon' AND role == 'admin')
363
+ User.where.not(name: "Jon", role: "admin")
364
+ # SELECT * FROM users WHERE NOT (name == 'Jon' AND role == 'admin')
180
365
 
181
366
  *Rafael Mendonça França*
182
367
 
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? && owner.validation_context.nil?
215
- Base.strict_loading_violation!(owner: owner.class, association: klass)
216
- end
217
-
218
- if reflection.strict_loading? && owner.validation_context.nil?
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