activerecord 7.2.1.2 → 7.2.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +139 -0
- data/lib/active_record/associations/has_many_through_association.rb +7 -1
- data/lib/active_record/associations/join_dependency/join_association.rb +3 -2
- data/lib/active_record/associations/join_dependency.rb +4 -4
- data/lib/active_record/associations.rb +28 -16
- data/lib/active_record/attribute_assignment.rb +9 -1
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +4 -0
- data/lib/active_record/attributes.rb +1 -2
- data/lib/active_record/callbacks.rb +1 -1
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +26 -0
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +4 -2
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +1 -1
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +7 -3
- data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +2 -0
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +3 -3
- data/lib/active_record/core.rb +39 -7
- data/lib/active_record/database_configurations/connection_url_resolver.rb +1 -1
- data/lib/active_record/encryption/key_provider.rb +1 -1
- data/lib/active_record/encryption.rb +2 -0
- data/lib/active_record/enum.rb +7 -10
- data/lib/active_record/gem_version.rb +2 -2
- data/lib/active_record/marshalling.rb +4 -1
- data/lib/active_record/model_schema.rb +1 -2
- data/lib/active_record/nested_attributes.rb +13 -2
- data/lib/active_record/query_cache.rb +4 -5
- data/lib/active_record/query_logs.rb +1 -1
- data/lib/active_record/railtie.rb +7 -12
- data/lib/active_record/reflection.rb +5 -2
- data/lib/active_record/relation/calculations.rb +1 -1
- data/lib/active_record/relation/predicate_builder.rb +1 -1
- data/lib/active_record/relation/query_methods.rb +39 -24
- data/lib/active_record/tasks/database_tasks.rb +12 -1
- data/lib/active_record/testing/query_assertions.rb +2 -2
- data/lib/active_record/validations/uniqueness.rb +1 -0
- data/lib/arel/visitors/sqlite.rb +25 -0
- metadata +9 -9
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 857ca134ca542d7fc1a0a8950ec0c24b8c66594c5a34298ad717da73ba5877d6
|
4
|
+
data.tar.gz: 0bf2140eb0df1bcdc98976389822b5d4978d8ffc2a8d7a237ea855c24ff329b1
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 13574ac1dda8565be5e974d5799577feda4c5896aab0424afe49b05e9118a2aa9f07016e7fbc40c62360becc67ed9440e224e0db95dae93891fd5466c96f427e
|
7
|
+
data.tar.gz: 7741a92426fcd9be412d0279a7bd5b749ee316351e77c20f589cbd72798cac6e4c9645d96b12dab8f3d45f4fc6919a75272925147432ffc7a658ea5806979158
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,142 @@
|
|
1
|
+
## Rails 7.2.2 (October 30, 2024) ##
|
2
|
+
|
3
|
+
* Fix support for `query_cache: false` in `database.yml`.
|
4
|
+
|
5
|
+
`query_cache: false` would no longer entirely disable the Active Record query cache.
|
6
|
+
|
7
|
+
*zzak*
|
8
|
+
|
9
|
+
* Set `.attributes_for_inspect` to `:all` by default.
|
10
|
+
|
11
|
+
For new applications it is set to `[:id]` in config/environment/production.rb.
|
12
|
+
|
13
|
+
In the console all the attributes are always shown.
|
14
|
+
|
15
|
+
*Andrew Novoselac*
|
16
|
+
|
17
|
+
* `PG::UnableToSend: no connection to the server` is now retryable as a connection-related exception
|
18
|
+
|
19
|
+
*Kazuma Watanabe*
|
20
|
+
|
21
|
+
* Fix marshalling of unsaved associated records in 7.1 format.
|
22
|
+
|
23
|
+
The 7.1 format would only marshal associated records if the association was loaded.
|
24
|
+
But associations that would only contain unsaved records would be skipped.
|
25
|
+
|
26
|
+
*Jean Boussier*
|
27
|
+
|
28
|
+
* Fix incorrect SQL query when passing an empty hash to `ActiveRecord::Base.insert`.
|
29
|
+
|
30
|
+
*David Stosik*
|
31
|
+
|
32
|
+
* Allow to save records with polymorphic join tables that have `inverse_of`
|
33
|
+
specified.
|
34
|
+
|
35
|
+
*Markus Doits*
|
36
|
+
|
37
|
+
* Fix association scopes applying on the incorrect join when using a polymorphic `has_many through:`.
|
38
|
+
|
39
|
+
*Joshua Young*
|
40
|
+
|
41
|
+
* Fix `dependent: :destroy` for bi-directional has one through association.
|
42
|
+
|
43
|
+
Fixes #50948.
|
44
|
+
|
45
|
+
```ruby
|
46
|
+
class Left < ActiveRecord::Base
|
47
|
+
has_one :middle, dependent: :destroy
|
48
|
+
has_one :right, through: :middle
|
49
|
+
end
|
50
|
+
|
51
|
+
class Middle < ActiveRecord::Base
|
52
|
+
belongs_to :left, dependent: :destroy
|
53
|
+
belongs_to :right, dependent: :destroy
|
54
|
+
end
|
55
|
+
|
56
|
+
class Right < ActiveRecord::Base
|
57
|
+
has_one :middle, dependent: :destroy
|
58
|
+
has_one :left, through: :middle
|
59
|
+
end
|
60
|
+
```
|
61
|
+
In the above example `left.destroy` wouldn't destroy its associated `Right`
|
62
|
+
record.
|
63
|
+
|
64
|
+
*Andy Stewart*
|
65
|
+
|
66
|
+
* Properly handle lazily pinned connection pools.
|
67
|
+
|
68
|
+
Fixes #53147.
|
69
|
+
|
70
|
+
When using transactional fixtures with system tests to similar tools
|
71
|
+
such as capybara, it could happen that a connection end up pinned by the
|
72
|
+
server thread rather than the test thread, causing
|
73
|
+
`"Cannot expire connection, it is owned by a different thread"` errors.
|
74
|
+
|
75
|
+
*Jean Boussier*
|
76
|
+
|
77
|
+
* Fix `ActiveRecord::Base.with` to accept more than two sub queries.
|
78
|
+
|
79
|
+
Fixes #53110.
|
80
|
+
|
81
|
+
```ruby
|
82
|
+
User.with(foo: [User.select(:id), User.select(:id), User.select(:id)]).to_sql
|
83
|
+
undefined method `union' for an instance of Arel::Nodes::UnionAll (NoMethodError)
|
84
|
+
```
|
85
|
+
|
86
|
+
The above now works as expected.
|
87
|
+
|
88
|
+
*fatkodima*
|
89
|
+
|
90
|
+
* Properly release pinned connections with non joinable connections.
|
91
|
+
|
92
|
+
Fixes #52973
|
93
|
+
|
94
|
+
When running system tests with transactional fixtures on, it could happen that
|
95
|
+
the connection leased by the Puma thread wouldn't be properly released back to the pool,
|
96
|
+
causing "Cannot expire connection, it is owned by a different thread" errors in later tests.
|
97
|
+
|
98
|
+
*Jean Boussier*
|
99
|
+
|
100
|
+
* Make Float distinguish between `float4` and `float8` in PostgreSQL.
|
101
|
+
|
102
|
+
Fixes #52742
|
103
|
+
|
104
|
+
*Ryota Kitazawa*, *Takayuki Nagatomi*
|
105
|
+
|
106
|
+
* Fix an issue where `.left_outer_joins` used with multiple associations that have
|
107
|
+
the same child association but different parents does not join all parents.
|
108
|
+
|
109
|
+
Previously, using `.left_outer_joins` with the same child association would only join one of the parents.
|
110
|
+
|
111
|
+
Now it will correctly join both parents.
|
112
|
+
|
113
|
+
Fixes #41498.
|
114
|
+
|
115
|
+
*Garrett Blehm*
|
116
|
+
|
117
|
+
* Ensure `ActiveRecord::Encryption.config` is always ready before access.
|
118
|
+
|
119
|
+
Previously, `ActiveRecord::Encryption` configuration was deferred until `ActiveRecord::Base`
|
120
|
+
was loaded. Therefore, accessing `ActiveRecord::Encryption.config` properties before
|
121
|
+
`ActiveRecord::Base` was loaded would give incorrect results.
|
122
|
+
|
123
|
+
`ActiveRecord::Encryption` now has its own loading hook so that its configuration is set as
|
124
|
+
soon as needed.
|
125
|
+
|
126
|
+
When `ActiveRecord::Base` is loaded, even lazily, it in turn triggers the loading of
|
127
|
+
`ActiveRecord::Encryption`, thus preserving the original behavior of having its config ready
|
128
|
+
before any use of `ActiveRecord::Base`.
|
129
|
+
|
130
|
+
*Maxime Réty*
|
131
|
+
|
132
|
+
* Add `TimeZoneConverter#==` method, so objects will be properly compared by
|
133
|
+
their type, scale, limit & precision.
|
134
|
+
|
135
|
+
Address #52699.
|
136
|
+
|
137
|
+
*Ruy Rocha*
|
138
|
+
|
139
|
+
|
1
140
|
## Rails 7.2.1.2 (October 23, 2024) ##
|
2
141
|
|
3
142
|
* No changes.
|
@@ -93,7 +93,13 @@ module ActiveRecord
|
|
93
93
|
@through_scope = scope
|
94
94
|
record = super
|
95
95
|
|
96
|
-
inverse =
|
96
|
+
inverse =
|
97
|
+
if source_reflection.polymorphic?
|
98
|
+
source_reflection.polymorphic_inverse_of(record.class)
|
99
|
+
else
|
100
|
+
source_reflection.inverse_of
|
101
|
+
end
|
102
|
+
|
97
103
|
if inverse
|
98
104
|
if inverse.collection?
|
99
105
|
record.send(inverse.name) << build_through_record(record)
|
@@ -25,8 +25,9 @@ module ActiveRecord
|
|
25
25
|
joins = []
|
26
26
|
chain = []
|
27
27
|
|
28
|
-
reflection.chain
|
29
|
-
|
28
|
+
reflection_chain = reflection.chain
|
29
|
+
reflection_chain.each_with_index do |reflection, index|
|
30
|
+
table, terminated = yield reflection, reflection_chain[index..]
|
30
31
|
@table ||= table
|
31
32
|
|
32
33
|
if terminated
|
@@ -190,12 +190,12 @@ module ActiveRecord
|
|
190
190
|
def make_constraints(parent, child, join_type)
|
191
191
|
foreign_table = parent.table
|
192
192
|
foreign_klass = parent.base_klass
|
193
|
-
child.join_constraints(foreign_table, foreign_klass, join_type, alias_tracker) do |reflection|
|
194
|
-
table, terminated = @joined_tables[
|
193
|
+
child.join_constraints(foreign_table, foreign_klass, join_type, alias_tracker) do |reflection, remaining_reflection_chain|
|
194
|
+
table, terminated = @joined_tables[remaining_reflection_chain]
|
195
195
|
root = reflection == child.reflection
|
196
196
|
|
197
197
|
if table && (!root || !terminated)
|
198
|
-
@joined_tables[
|
198
|
+
@joined_tables[remaining_reflection_chain] = [table, root] if root
|
199
199
|
next table, true
|
200
200
|
end
|
201
201
|
|
@@ -206,7 +206,7 @@ module ActiveRecord
|
|
206
206
|
root ? name : "#{name}_join"
|
207
207
|
end
|
208
208
|
|
209
|
-
@joined_tables[
|
209
|
+
@joined_tables[remaining_reflection_chain] ||= [table, root] if join_type == Arel::Nodes::OuterJoin
|
210
210
|
table
|
211
211
|
end.concat child.children.flat_map { |c| make_constraints(child, c, join_type) }
|
212
212
|
end
|
@@ -537,7 +537,7 @@ module ActiveRecord
|
|
537
537
|
# @group.avatars << Avatar.new # this would work if User belonged_to Avatar rather than the other way around
|
538
538
|
# @group.avatars.delete(@group.avatars.last) # so would this
|
539
539
|
#
|
540
|
-
#
|
540
|
+
# === Setting Inverses
|
541
541
|
#
|
542
542
|
# If you are using a #belongs_to on the join model, it is a good idea to set the
|
543
543
|
# <tt>:inverse_of</tt> option on the #belongs_to, which will mean that the following example
|
@@ -1199,8 +1199,11 @@ module ActiveRecord
|
|
1199
1199
|
# If you are going to modify the association (rather than just read from it), then it is
|
1200
1200
|
# a good idea to set the <tt>:inverse_of</tt> option on the source association on the
|
1201
1201
|
# join model. This allows associated records to be built which will automatically create
|
1202
|
-
# the appropriate join model records when they are saved.
|
1203
|
-
#
|
1202
|
+
# the appropriate join model records when they are saved. See
|
1203
|
+
# {Association Join Models}[rdoc-ref:Associations::ClassMethods@Association+Join+Models]
|
1204
|
+
# and {Setting Inverses}[rdoc-ref:Associations::ClassMethods@Setting+Inverses] for
|
1205
|
+
# more detail.
|
1206
|
+
#
|
1204
1207
|
# [+:disable_joins+]
|
1205
1208
|
# Specifies whether joins should be skipped for an association. If set to true, two or more queries
|
1206
1209
|
# will be generated. Note that in some cases, if order or limit is applied, it will be done in-memory
|
@@ -1229,7 +1232,8 @@ module ActiveRecord
|
|
1229
1232
|
# [+:inverse_of+]
|
1230
1233
|
# Specifies the name of the #belongs_to association on the associated object
|
1231
1234
|
# that is the inverse of this #has_many association.
|
1232
|
-
# See
|
1235
|
+
# See {Bi-directional associations}[rdoc-ref:Associations::ClassMethods@Bi-directional+associations]
|
1236
|
+
# for more detail.
|
1233
1237
|
# [+:extend+]
|
1234
1238
|
# Specifies a module or array of modules that will be extended into the association object returned.
|
1235
1239
|
# Useful for defining methods on associations, especially when they should be shared between multiple
|
@@ -1270,10 +1274,12 @@ module ActiveRecord
|
|
1270
1274
|
Reflection.add_reflection self, name, reflection
|
1271
1275
|
end
|
1272
1276
|
|
1273
|
-
# Specifies a one-to-one association with another class. This method
|
1274
|
-
# if the other class contains the foreign key. If
|
1275
|
-
#
|
1276
|
-
#
|
1277
|
+
# Specifies a one-to-one association with another class. This method
|
1278
|
+
# should only be used if the other class contains the foreign key. If
|
1279
|
+
# the current class contains the foreign key, then you should use
|
1280
|
+
# #belongs_to instead. See {Is it a belongs_to or has_one
|
1281
|
+
# association?}[rdoc-ref:Associations::ClassMethods@Is+it+a+-23belongs_to+or+-23has_one+association-3F]
|
1282
|
+
# for more detail on when to use #has_one and when to use #belongs_to.
|
1277
1283
|
#
|
1278
1284
|
# The following methods for retrieval and query of a single associated object will be added:
|
1279
1285
|
#
|
@@ -1388,8 +1394,10 @@ module ActiveRecord
|
|
1388
1394
|
# If you are going to modify the association (rather than just read from it), then it is
|
1389
1395
|
# a good idea to set the <tt>:inverse_of</tt> option on the source association on the
|
1390
1396
|
# join model. This allows associated records to be built which will automatically create
|
1391
|
-
# the appropriate join model records when they are saved.
|
1392
|
-
#
|
1397
|
+
# the appropriate join model records when they are saved. See
|
1398
|
+
# {Association Join Models}[rdoc-ref:Associations::ClassMethods@Association+Join+Models]
|
1399
|
+
# and {Setting Inverses}[rdoc-ref:Associations::ClassMethods@Setting+Inverses] for
|
1400
|
+
# more detail.
|
1393
1401
|
# [+:disable_joins+]
|
1394
1402
|
# Specifies whether joins should be skipped for an association. If set to true, two or more queries
|
1395
1403
|
# will be generated. Note that in some cases, if order or limit is applied, it will be done in-memory
|
@@ -1427,7 +1435,8 @@ module ActiveRecord
|
|
1427
1435
|
# [+:inverse_of+]
|
1428
1436
|
# Specifies the name of the #belongs_to association on the associated object
|
1429
1437
|
# that is the inverse of this #has_one association.
|
1430
|
-
# See
|
1438
|
+
# See {Bi-directional associations}[rdoc-ref:Associations::ClassMethods@Bi-directional+associations]
|
1439
|
+
# for more detail.
|
1431
1440
|
# [+:required+]
|
1432
1441
|
# When set to +true+, the association will also have its presence validated.
|
1433
1442
|
# This will validate the association itself, not the id. You can use
|
@@ -1461,10 +1470,12 @@ module ActiveRecord
|
|
1461
1470
|
Reflection.add_reflection self, name, reflection
|
1462
1471
|
end
|
1463
1472
|
|
1464
|
-
# Specifies a one-to-one association with another class. This method
|
1465
|
-
# if this class contains the foreign key. If the
|
1466
|
-
# then you should use #has_one
|
1467
|
-
#
|
1473
|
+
# Specifies a one-to-one association with another class. This method
|
1474
|
+
# should only be used if this class contains the foreign key. If the
|
1475
|
+
# other class contains the foreign key, then you should use #has_one
|
1476
|
+
# instead. See {Is it a belongs_to or has_one
|
1477
|
+
# association?}[rdoc-ref:Associations::ClassMethods@Is+it+a+-23belongs_to+or+-23has_one+association-3F]
|
1478
|
+
# for more detail on when to use #has_one and when to use #belongs_to.
|
1468
1479
|
#
|
1469
1480
|
# Methods will be added for retrieval and query for a single associated object, for which
|
1470
1481
|
# this object holds an id:
|
@@ -1606,7 +1617,8 @@ module ActiveRecord
|
|
1606
1617
|
# [+:inverse_of+]
|
1607
1618
|
# Specifies the name of the #has_one or #has_many association on the associated
|
1608
1619
|
# object that is the inverse of this #belongs_to association.
|
1609
|
-
# See
|
1620
|
+
# See {Bi-directional associations}[rdoc-ref:Associations::ClassMethods@Bi-directional+associations]
|
1621
|
+
# for more detail.
|
1610
1622
|
# [+:optional+]
|
1611
1623
|
# When set to +true+, the association will not have its presence validated.
|
1612
1624
|
# [+:required+]
|
@@ -4,21 +4,29 @@ module ActiveRecord
|
|
4
4
|
module AttributeAssignment
|
5
5
|
private
|
6
6
|
def _assign_attributes(attributes)
|
7
|
-
multi_parameter_attributes = nil
|
7
|
+
multi_parameter_attributes = nested_parameter_attributes = nil
|
8
8
|
|
9
9
|
attributes.each do |k, v|
|
10
10
|
key = k.to_s
|
11
11
|
|
12
12
|
if key.include?("(")
|
13
13
|
(multi_parameter_attributes ||= {})[key] = v
|
14
|
+
elsif v.is_a?(Hash)
|
15
|
+
(nested_parameter_attributes ||= {})[key] = v
|
14
16
|
else
|
15
17
|
_assign_attribute(key, v)
|
16
18
|
end
|
17
19
|
end
|
18
20
|
|
21
|
+
assign_nested_parameter_attributes(nested_parameter_attributes) if nested_parameter_attributes
|
19
22
|
assign_multiparameter_attributes(multi_parameter_attributes) if multi_parameter_attributes
|
20
23
|
end
|
21
24
|
|
25
|
+
# Assign any deferred nested attributes after the base attributes have been set.
|
26
|
+
def assign_nested_parameter_attributes(pairs)
|
27
|
+
pairs.each { |k, v| _assign_attribute(k, v) }
|
28
|
+
end
|
29
|
+
|
22
30
|
# Instantiates objects for all attribute classes that needs more than one constructor parameter. This is done
|
23
31
|
# by calling new on the column type or aggregation type (through composed_of) object with these parameters.
|
24
32
|
# So having the pairs written_on(1) = "2004", written_on(2) = "6", written_on(3) = "24", will instantiate
|
@@ -212,8 +212,7 @@ module ActiveRecord
|
|
212
212
|
#--
|
213
213
|
# Implemented by ActiveModel::AttributeRegistration#attribute.
|
214
214
|
|
215
|
-
# This
|
216
|
-
# accepts type objects, and will do its work immediately instead of
|
215
|
+
# This API only accepts type objects, and will do its work immediately instead of
|
217
216
|
# waiting for the schema to load. While this method
|
218
217
|
# is provided so it can be used by plugin authors, application code
|
219
218
|
# should probably use ClassMethods#attribute.
|
@@ -418,7 +418,7 @@ module ActiveRecord
|
|
418
418
|
|
419
419
|
def destroy # :nodoc:
|
420
420
|
@_destroy_callback_already_called ||= false
|
421
|
-
return if @_destroy_callback_already_called
|
421
|
+
return true if @_destroy_callback_already_called
|
422
422
|
@_destroy_callback_already_called = true
|
423
423
|
_run_destroy_callbacks { super }
|
424
424
|
rescue RecordNotDestroyed => e
|
@@ -184,6 +184,31 @@ module ActiveRecord
|
|
184
184
|
end
|
185
185
|
end
|
186
186
|
|
187
|
+
module ExecutorHooks # :nodoc:
|
188
|
+
class << self
|
189
|
+
def run
|
190
|
+
# noop
|
191
|
+
end
|
192
|
+
|
193
|
+
def complete(_)
|
194
|
+
ActiveRecord::Base.connection_handler.each_connection_pool do |pool|
|
195
|
+
if (connection = pool.active_connection?)
|
196
|
+
transaction = connection.current_transaction
|
197
|
+
if transaction.closed? || !transaction.joinable?
|
198
|
+
pool.release_connection
|
199
|
+
end
|
200
|
+
end
|
201
|
+
end
|
202
|
+
end
|
203
|
+
end
|
204
|
+
end
|
205
|
+
|
206
|
+
class << self
|
207
|
+
def install_executor_hooks(executor = ActiveSupport::Executor)
|
208
|
+
executor.register_hook(ExecutorHooks)
|
209
|
+
end
|
210
|
+
end
|
211
|
+
|
187
212
|
include MonitorMixin
|
188
213
|
prepend QueryCache::ConnectionPoolConfiguration
|
189
214
|
include ConnectionAdapters::AbstractPool
|
@@ -333,6 +358,7 @@ module ActiveRecord
|
|
333
358
|
end
|
334
359
|
|
335
360
|
if @pinned_connection.nil?
|
361
|
+
connection.steal!
|
336
362
|
connection.lock_thread = nil
|
337
363
|
checkin(connection)
|
338
364
|
end
|
@@ -157,11 +157,13 @@ module ActiveRecord
|
|
157
157
|
end
|
158
158
|
|
159
159
|
def enable_query_cache!
|
160
|
-
query_cache.enabled
|
160
|
+
query_cache.enabled = true
|
161
|
+
query_cache.dirties = true
|
161
162
|
end
|
162
163
|
|
163
164
|
def disable_query_cache!
|
164
|
-
query_cache.enabled
|
165
|
+
query_cache.enabled = false
|
166
|
+
query_cache.dirties = true
|
165
167
|
end
|
166
168
|
|
167
169
|
def query_cache_enabled
|
@@ -682,7 +682,7 @@ module ActiveRecord
|
|
682
682
|
#
|
683
683
|
# If the options provided include an +if_exists+ key, it will be used to check if the
|
684
684
|
# column does not exist. This will silently ignore the migration rather than raising
|
685
|
-
# if the column was already
|
685
|
+
# if the column was already removed.
|
686
686
|
#
|
687
687
|
# remove_column(:suppliers, :qualification, if_exists: true)
|
688
688
|
def remove_column(table_name, column_name, type = nil, **options)
|
@@ -639,7 +639,7 @@ module ActiveRecord
|
|
639
639
|
end
|
640
640
|
|
641
641
|
def build_insert_sql(insert) # :nodoc:
|
642
|
-
no_op_column = quote_column_name(insert.keys.first)
|
642
|
+
no_op_column = quote_column_name(insert.keys.first) if insert.keys.first
|
643
643
|
|
644
644
|
# MySQL 8.0.19 replaces `VALUES(<expression>)` clauses with row and column alias names, see https://dev.mysql.com/worklog/task/?id=6312 .
|
645
645
|
# then MySQL 8.0.20 deprecates the `VALUES(<expression>)` see https://dev.mysql.com/worklog/task/?id=13325 .
|
@@ -648,7 +648,9 @@ module ActiveRecord
|
|
648
648
|
sql = +"INSERT #{insert.into} #{insert.values_list} AS #{values_alias}"
|
649
649
|
|
650
650
|
if insert.skip_duplicates?
|
651
|
-
|
651
|
+
if no_op_column
|
652
|
+
sql << " ON DUPLICATE KEY UPDATE #{no_op_column}=#{values_alias}.#{no_op_column}"
|
653
|
+
end
|
652
654
|
elsif insert.update_duplicates?
|
653
655
|
if insert.raw_update_sql?
|
654
656
|
sql = +"INSERT #{insert.into} #{insert.values_list} ON DUPLICATE KEY UPDATE #{insert.raw_update_sql}"
|
@@ -662,7 +664,9 @@ module ActiveRecord
|
|
662
664
|
sql = +"INSERT #{insert.into} #{insert.values_list}"
|
663
665
|
|
664
666
|
if insert.skip_duplicates?
|
665
|
-
|
667
|
+
if no_op_column
|
668
|
+
sql << " ON DUPLICATE KEY UPDATE #{no_op_column}=#{no_op_column}"
|
669
|
+
end
|
666
670
|
elsif insert.update_duplicates?
|
667
671
|
sql << " ON DUPLICATE KEY UPDATE "
|
668
672
|
if insert.raw_update_sql?
|
@@ -31,7 +31,7 @@ module ActiveRecord
|
|
31
31
|
# TODO: Remove when IPAddr#== compares IPAddr#prefix. See
|
32
32
|
# https://github.com/ruby/ipaddr/issues/21
|
33
33
|
def changed?(old_value, new_value, _new_value_before_type_cast)
|
34
|
-
|
34
|
+
!old_value.eql?(new_value) || !old_value.nil? && old_value.prefix != new_value.prefix
|
35
35
|
end
|
36
36
|
|
37
37
|
def cast_value(value)
|
@@ -255,6 +255,8 @@ module ActiveRecord
|
|
255
255
|
|
256
256
|
# Returns the sequence name for a table's primary key or some other specified key.
|
257
257
|
def default_sequence_name(table_name, pk = "id") # :nodoc:
|
258
|
+
return nil if pk.is_a?(Array)
|
259
|
+
|
258
260
|
result = serial_sequence(table_name, pk)
|
259
261
|
return nil unless result
|
260
262
|
Utils.extract_schema_qualified_name(result).to_s
|
@@ -652,8 +652,8 @@ module ActiveRecord
|
|
652
652
|
m.register_type "int4", Type::Integer.new(limit: 4)
|
653
653
|
m.register_type "int8", Type::Integer.new(limit: 8)
|
654
654
|
m.register_type "oid", OID::Oid.new
|
655
|
-
m.register_type "float4", Type::Float.new
|
656
|
-
m.
|
655
|
+
m.register_type "float4", Type::Float.new(limit: 24)
|
656
|
+
m.register_type "float8", Type::Float.new
|
657
657
|
m.register_type "text", Type::Text.new
|
658
658
|
register_class_with_limit m, "varchar", Type::String
|
659
659
|
m.alias_type "char", "varchar"
|
@@ -777,7 +777,7 @@ module ActiveRecord
|
|
777
777
|
|
778
778
|
case exception.result.try(:error_field, PG::PG_DIAG_SQLSTATE)
|
779
779
|
when nil
|
780
|
-
if exception.message.match?(/connection is closed/i)
|
780
|
+
if exception.message.match?(/connection is closed/i) || exception.message.match?(/no connection to the server/i)
|
781
781
|
ConnectionNotEstablished.new(exception, connection_pool: @pool)
|
782
782
|
elsif exception.is_a?(PG::ConnectionBad)
|
783
783
|
# libpq message style always ends with a newline; the pg gem's internal
|
data/lib/active_record/core.rb
CHANGED
@@ -102,8 +102,20 @@ module ActiveRecord
|
|
102
102
|
|
103
103
|
class_attribute :shard_selector, instance_accessor: false, default: nil
|
104
104
|
|
105
|
-
|
106
|
-
|
105
|
+
##
|
106
|
+
# :singleton-method:
|
107
|
+
#
|
108
|
+
# Specifies the attributes that will be included in the output of the
|
109
|
+
# #inspect method:
|
110
|
+
#
|
111
|
+
# Post.attributes_for_inspect = [:id, :title]
|
112
|
+
# Post.first.inspect #=> "#<Post id: 1, title: "Hello, World!">"
|
113
|
+
#
|
114
|
+
# When set to `:all` inspect will list all the record's attributes:
|
115
|
+
#
|
116
|
+
# Post.attributes_for_inspect = :all
|
117
|
+
# Post.first.inspect #=> "#<Post id: 1, title: "Hello, World!", published_at: "2023-10-23 14:28:11 +0000">"
|
118
|
+
class_attribute :attributes_for_inspect, instance_accessor: false, default: :all
|
107
119
|
|
108
120
|
def self.application_record_class? # :nodoc:
|
109
121
|
if ActiveRecord.application_record_class
|
@@ -349,7 +361,7 @@ module ActiveRecord
|
|
349
361
|
|
350
362
|
# Returns a string like 'Post(id:integer, title:string, body:text)'
|
351
363
|
def inspect # :nodoc:
|
352
|
-
if self == Base
|
364
|
+
if self == Base || singleton_class?
|
353
365
|
super
|
354
366
|
elsif abstract_class?
|
355
367
|
"#{super}(abstract)"
|
@@ -724,14 +736,28 @@ module ActiveRecord
|
|
724
736
|
self.class.connection_handler
|
725
737
|
end
|
726
738
|
|
727
|
-
# Returns the attributes
|
739
|
+
# Returns the attributes of the record as a nicely formatted string.
|
740
|
+
#
|
741
|
+
# Post.first.inspect
|
742
|
+
# #=> "#<Post id: 1, title: "Hello, World!", published_at: "2023-10-23 14:28:11 +0000">"
|
743
|
+
#
|
744
|
+
# The attributes can be limited by setting <tt>.attributes_for_inspect</tt>.
|
745
|
+
#
|
746
|
+
# Post.attributes_for_inspect = [:id, :title]
|
747
|
+
# Post.first.inspect
|
748
|
+
# #=> "#<Post id: 1, title: "Hello, World!">"
|
728
749
|
def inspect
|
729
750
|
inspect_with_attributes(attributes_for_inspect)
|
730
751
|
end
|
731
752
|
|
732
|
-
# Returns
|
753
|
+
# Returns all attributes of the record as a nicely formatted string,
|
754
|
+
# ignoring <tt>.attributes_for_inspect</tt>.
|
755
|
+
#
|
756
|
+
# Post.first.full_inspect
|
757
|
+
# #=> "#<Post id: 1, title: "Hello, World!", published_at: "2023-10-23 14:28:11 +0000">"
|
758
|
+
#
|
733
759
|
def full_inspect
|
734
|
-
inspect_with_attributes(
|
760
|
+
inspect_with_attributes(all_attributes_for_inspect)
|
735
761
|
end
|
736
762
|
|
737
763
|
# Takes a PP and prettily prints this record to it, allowing you to get a nice result from <tt>pp record</tt>
|
@@ -823,7 +849,13 @@ module ActiveRecord
|
|
823
849
|
end
|
824
850
|
|
825
851
|
def attributes_for_inspect
|
826
|
-
self.class.attributes_for_inspect == :all ?
|
852
|
+
self.class.attributes_for_inspect == :all ? all_attributes_for_inspect : self.class.attributes_for_inspect
|
853
|
+
end
|
854
|
+
|
855
|
+
def all_attributes_for_inspect
|
856
|
+
return [] unless @attributes
|
857
|
+
|
858
|
+
attribute_names
|
827
859
|
end
|
828
860
|
end
|
829
861
|
end
|
@@ -12,7 +12,7 @@ module ActiveRecord
|
|
12
12
|
@keys = Array(keys)
|
13
13
|
end
|
14
14
|
|
15
|
-
# Returns the
|
15
|
+
# Returns the last key in the list as the active key to perform encryptions
|
16
16
|
#
|
17
17
|
# When +ActiveRecord::Encryption.config.store_key_references+ is true, the key will include
|
18
18
|
# a public tag referencing the key itself. That key will be stored in the public
|
data/lib/active_record/enum.rb
CHANGED
@@ -167,15 +167,6 @@ module ActiveRecord
|
|
167
167
|
base.class_attribute(:defined_enums, instance_writer: false, default: {})
|
168
168
|
end
|
169
169
|
|
170
|
-
def load_schema! # :nodoc:
|
171
|
-
defined_enums.each_key do |name|
|
172
|
-
unless columns_hash.key?(resolve_attribute_name(name))
|
173
|
-
raise "Unknown enum attribute '#{name}' for #{self.name}. Enums must be" \
|
174
|
-
" backed by a database column."
|
175
|
-
end
|
176
|
-
end
|
177
|
-
end
|
178
|
-
|
179
170
|
class EnumType < Type::Value # :nodoc:
|
180
171
|
delegate :type, to: :subtype
|
181
172
|
|
@@ -264,7 +255,13 @@ module ActiveRecord
|
|
264
255
|
|
265
256
|
attribute(name, **options)
|
266
257
|
|
267
|
-
decorate_attributes([name]) do |
|
258
|
+
decorate_attributes([name]) do |_name, subtype|
|
259
|
+
if subtype == ActiveModel::Type.default_value
|
260
|
+
raise "Undeclared attribute type for enum '#{name}' in #{self.name}. Enums must be" \
|
261
|
+
" backed by a database column or declared with an explicit type" \
|
262
|
+
" via `attribute`."
|
263
|
+
end
|
264
|
+
|
268
265
|
subtype = subtype.subtype if EnumType === subtype
|
269
266
|
EnumType.new(name, enum_values, subtype, raise_on_invalid_values: !validate)
|
270
267
|
end
|
@@ -25,7 +25,10 @@ module ActiveRecord
|
|
25
25
|
payload = [attributes_for_database, new_record?]
|
26
26
|
|
27
27
|
cached_associations = self.class.reflect_on_all_associations.select do |reflection|
|
28
|
-
association_cached?(reflection.name)
|
28
|
+
if association_cached?(reflection.name)
|
29
|
+
association = association(reflection.name)
|
30
|
+
association.loaded? || association.target.present?
|
31
|
+
end
|
29
32
|
end
|
30
33
|
|
31
34
|
unless cached_associations.empty?
|
@@ -431,7 +431,6 @@ module ActiveRecord
|
|
431
431
|
end
|
432
432
|
|
433
433
|
def columns
|
434
|
-
load_schema unless @columns
|
435
434
|
@columns ||= columns_hash.values.freeze
|
436
435
|
end
|
437
436
|
|
@@ -595,7 +594,7 @@ module ActiveRecord
|
|
595
594
|
columns_hash = columns_hash.except(*ignored_columns) unless ignored_columns.empty?
|
596
595
|
@columns_hash = columns_hash.freeze
|
597
596
|
|
598
|
-
|
597
|
+
_default_attributes # Precompute to cache DB-dependent attribute types
|
599
598
|
end
|
600
599
|
|
601
600
|
# Guesses the table name, but does not decorate it with prefix and suffix information.
|
@@ -524,12 +524,12 @@ module ActiveRecord
|
|
524
524
|
unless reject_new_record?(association_name, attributes)
|
525
525
|
association.reader.build(attributes.except(*UNASSIGNABLE_KEYS))
|
526
526
|
end
|
527
|
-
elsif existing_record = existing_records
|
527
|
+
elsif existing_record = find_record_by_id(existing_records, attributes["id"])
|
528
528
|
unless call_reject_if(association_name, attributes)
|
529
529
|
# Make sure we are operating on the actual object which is in the association's
|
530
530
|
# proxy_target array (either by finding it, or adding it if not found)
|
531
531
|
# Take into account that the proxy_target may have changed due to callbacks
|
532
|
-
target_record = association.target
|
532
|
+
target_record = find_record_by_id(association.target, attributes["id"])
|
533
533
|
if target_record
|
534
534
|
existing_record = target_record
|
535
535
|
else
|
@@ -620,5 +620,16 @@ module ActiveRecord
|
|
620
620
|
raise RecordNotFound.new("Couldn't find #{model} with ID=#{record_id} for #{self.class.name} with ID=#{id}",
|
621
621
|
model, "id", record_id)
|
622
622
|
end
|
623
|
+
|
624
|
+
def find_record_by_id(records, id)
|
625
|
+
return if records.empty?
|
626
|
+
|
627
|
+
if records.first.class.composite_primary_key?
|
628
|
+
id = Array(id).map(&:to_s)
|
629
|
+
records.find { |record| Array(record.id).map(&:to_s) == id }
|
630
|
+
else
|
631
|
+
records.find { |record| record.id.to_s == id.to_s }
|
632
|
+
end
|
633
|
+
end
|
623
634
|
end
|
624
635
|
end
|
@@ -35,7 +35,10 @@ module ActiveRecord
|
|
35
35
|
end
|
36
36
|
|
37
37
|
def self.run
|
38
|
-
ActiveRecord::Base.connection_handler.each_connection_pool.reject(&:query_cache_enabled).each
|
38
|
+
ActiveRecord::Base.connection_handler.each_connection_pool.reject(&:query_cache_enabled).each do |pool|
|
39
|
+
next if pool.db_config&.query_cache == false
|
40
|
+
pool.enable_query_cache!
|
41
|
+
end
|
39
42
|
end
|
40
43
|
|
41
44
|
def self.complete(pools)
|
@@ -43,10 +46,6 @@ module ActiveRecord
|
|
43
46
|
pool.disable_query_cache!
|
44
47
|
pool.clear_query_cache
|
45
48
|
end
|
46
|
-
|
47
|
-
ActiveRecord::Base.connection_handler.each_connection_pool do |pool|
|
48
|
-
pool.release_connection if pool.active_connection? && !pool.lease_connection.transaction_open?
|
49
|
-
end
|
50
49
|
end
|
51
50
|
|
52
51
|
def self.install_executor_hooks(executor = ActiveSupport::Executor)
|
@@ -112,7 +112,7 @@ module ActiveRecord
|
|
112
112
|
if Thread.respond_to?(:each_caller_location)
|
113
113
|
def query_source_location # :nodoc:
|
114
114
|
Thread.each_caller_location do |location|
|
115
|
-
frame = LogSubscriber.backtrace_cleaner.clean_frame(location
|
115
|
+
frame = LogSubscriber.backtrace_cleaner.clean_frame(location)
|
116
116
|
return frame if frame
|
117
117
|
end
|
118
118
|
nil
|
@@ -69,6 +69,7 @@ module ActiveRecord
|
|
69
69
|
Rails.logger.broadcast_to(console)
|
70
70
|
end
|
71
71
|
ActiveRecord.verbose_query_logs = false
|
72
|
+
ActiveRecord::Base.attributes_for_inspect = :all
|
72
73
|
end
|
73
74
|
|
74
75
|
runner do
|
@@ -311,6 +312,7 @@ To keep using the current cache store, you can turn off cache versioning entirel
|
|
311
312
|
initializer "active_record.set_executor_hooks" do
|
312
313
|
ActiveRecord::QueryCache.install_executor_hooks
|
313
314
|
ActiveRecord::AsynchronousQueriesTracker.install_executor_hooks
|
315
|
+
ActiveRecord::ConnectionAdapters::ConnectionPool.install_executor_hooks
|
314
316
|
end
|
315
317
|
|
316
318
|
initializer "active_record.add_watchable_files" do |app|
|
@@ -356,16 +358,19 @@ To keep using the current cache store, you can turn off cache versioning entirel
|
|
356
358
|
end
|
357
359
|
|
358
360
|
initializer "active_record_encryption.configuration" do |app|
|
359
|
-
ActiveSupport.on_load(:
|
360
|
-
ActiveRecord::Encryption.configure
|
361
|
+
ActiveSupport.on_load(:active_record_encryption) do
|
362
|
+
ActiveRecord::Encryption.configure(
|
361
363
|
primary_key: app.credentials.dig(:active_record_encryption, :primary_key),
|
362
364
|
deterministic_key: app.credentials.dig(:active_record_encryption, :deterministic_key),
|
363
365
|
key_derivation_salt: app.credentials.dig(:active_record_encryption, :key_derivation_salt),
|
364
366
|
**app.config.active_record.encryption
|
367
|
+
)
|
365
368
|
|
366
369
|
auto_filtered_parameters = ActiveRecord::Encryption::AutoFilteredParameters.new(app)
|
367
370
|
auto_filtered_parameters.enable if ActiveRecord::Encryption.config.add_to_filter_parameters
|
371
|
+
end
|
368
372
|
|
373
|
+
ActiveSupport.on_load(:active_record) do
|
369
374
|
# Support extended queries for deterministic attributes and validations
|
370
375
|
if ActiveRecord::Encryption.config.extend_queries
|
371
376
|
ActiveRecord::Encryption::ExtendedDeterministicQueries.install_support
|
@@ -432,15 +437,5 @@ To keep using the current cache store, you can turn off cache versioning entirel
|
|
432
437
|
end
|
433
438
|
end
|
434
439
|
end
|
435
|
-
|
436
|
-
initializer "active_record.attributes_for_inspect" do |app|
|
437
|
-
ActiveSupport.on_load(:active_record) do
|
438
|
-
if app.config.consider_all_requests_local
|
439
|
-
if app.config.active_record.attributes_for_inspect.nil?
|
440
|
-
ActiveRecord::Base.attributes_for_inspect = :all
|
441
|
-
end
|
442
|
-
end
|
443
|
-
end
|
444
|
-
end
|
445
440
|
end
|
446
441
|
end
|
@@ -79,7 +79,7 @@ module ActiveRecord
|
|
79
79
|
normalized_reflections.stringify_keys
|
80
80
|
end
|
81
81
|
|
82
|
-
def normalized_reflections # :nodoc
|
82
|
+
def normalized_reflections # :nodoc:
|
83
83
|
@__reflections ||= begin
|
84
84
|
ref = {}
|
85
85
|
|
@@ -1239,7 +1239,10 @@ module ActiveRecord
|
|
1239
1239
|
end
|
1240
1240
|
|
1241
1241
|
def join_scopes(table, predicate_builder, klass = self.klass, record = nil) # :nodoc:
|
1242
|
-
scopes =
|
1242
|
+
scopes = super
|
1243
|
+
unless @previous_reflection.through_reflection?
|
1244
|
+
scopes += @previous_reflection.join_scopes(table, predicate_builder, klass, record)
|
1245
|
+
end
|
1243
1246
|
scopes << build_scope(table, predicate_builder, klass).instance_exec(record, &source_type_scope)
|
1244
1247
|
end
|
1245
1248
|
|
@@ -307,8 +307,8 @@ module ActiveRecord
|
|
307
307
|
relation.pluck(*column_names)
|
308
308
|
else
|
309
309
|
klass.disallow_raw_sql!(flattened_args(column_names))
|
310
|
-
columns = arel_columns(column_names)
|
311
310
|
relation = spawn
|
311
|
+
columns = relation.arel_columns(column_names)
|
312
312
|
relation.select_values = columns
|
313
313
|
result = skip_query_cache_if_necessary do
|
314
314
|
if where_clause.contradiction?
|
@@ -142,7 +142,7 @@ module ActiveRecord
|
|
142
142
|
queries.first
|
143
143
|
else
|
144
144
|
queries.map! { |query| query.reduce(&:and) }
|
145
|
-
queries =
|
145
|
+
queries = Arel::Nodes::Or.new(queries)
|
146
146
|
Arel::Nodes::Grouping.new(queries)
|
147
147
|
end
|
148
148
|
end
|
@@ -1636,6 +1636,26 @@ module ActiveRecord
|
|
1636
1636
|
self
|
1637
1637
|
end
|
1638
1638
|
|
1639
|
+
protected
|
1640
|
+
def arel_columns(columns)
|
1641
|
+
columns.flat_map do |field|
|
1642
|
+
case field
|
1643
|
+
when Symbol
|
1644
|
+
arel_column(field.to_s) do |attr_name|
|
1645
|
+
adapter_class.quote_table_name(attr_name)
|
1646
|
+
end
|
1647
|
+
when String
|
1648
|
+
arel_column(field, &:itself)
|
1649
|
+
when Proc
|
1650
|
+
field.call
|
1651
|
+
when Hash
|
1652
|
+
arel_columns_from_hash(field)
|
1653
|
+
else
|
1654
|
+
field
|
1655
|
+
end
|
1656
|
+
end
|
1657
|
+
end
|
1658
|
+
|
1639
1659
|
private
|
1640
1660
|
def async
|
1641
1661
|
spawn.async!
|
@@ -1890,12 +1910,26 @@ module ActiveRecord
|
|
1890
1910
|
end
|
1891
1911
|
end
|
1892
1912
|
|
1893
|
-
def build_with_expression_from_value(value)
|
1913
|
+
def build_with_expression_from_value(value, nested = false)
|
1894
1914
|
case value
|
1895
1915
|
when Arel::Nodes::SqlLiteral then Arel::Nodes::Grouping.new(value)
|
1896
|
-
when ActiveRecord::Relation
|
1916
|
+
when ActiveRecord::Relation
|
1917
|
+
if nested
|
1918
|
+
value.arel.ast
|
1919
|
+
else
|
1920
|
+
value.arel
|
1921
|
+
end
|
1897
1922
|
when Arel::SelectManager then value
|
1898
|
-
when Array
|
1923
|
+
when Array
|
1924
|
+
return build_with_expression_from_value(value.first, false) if value.size == 1
|
1925
|
+
|
1926
|
+
parts = value.map do |query|
|
1927
|
+
build_with_expression_from_value(query, true)
|
1928
|
+
end
|
1929
|
+
|
1930
|
+
parts.reduce do |result, value|
|
1931
|
+
Arel::Nodes::UnionAll.new(result, value)
|
1932
|
+
end
|
1899
1933
|
else
|
1900
1934
|
raise ArgumentError, "Unsupported argument type: `#{value}` #{value.class}"
|
1901
1935
|
end
|
@@ -1909,33 +1943,14 @@ module ActiveRecord
|
|
1909
1943
|
).join_sources.first
|
1910
1944
|
end
|
1911
1945
|
|
1912
|
-
def arel_columns(columns)
|
1913
|
-
columns.flat_map do |field|
|
1914
|
-
case field
|
1915
|
-
when Symbol
|
1916
|
-
arel_column(field.to_s) do |attr_name|
|
1917
|
-
adapter_class.quote_table_name(attr_name)
|
1918
|
-
end
|
1919
|
-
when String
|
1920
|
-
arel_column(field, &:itself)
|
1921
|
-
when Proc
|
1922
|
-
field.call
|
1923
|
-
when Hash
|
1924
|
-
arel_columns_from_hash(field)
|
1925
|
-
else
|
1926
|
-
field
|
1927
|
-
end
|
1928
|
-
end
|
1929
|
-
end
|
1930
|
-
|
1931
1946
|
def arel_column(field)
|
1932
1947
|
field = klass.attribute_aliases[field] || field
|
1933
1948
|
from = from_clause.name || from_clause.value
|
1934
1949
|
|
1935
1950
|
if klass.columns_hash.key?(field) && (!from || table_name_matches?(from))
|
1936
1951
|
table[field]
|
1937
|
-
elsif
|
1938
|
-
table,
|
1952
|
+
elsif /\A(?<table>(?:\w+\.)?\w+)\.(?<column>\w+)\z/ =~ field
|
1953
|
+
self.references_values |= [Arel.sql(table, retryable: true)]
|
1939
1954
|
predicate_builder.resolve_arel_attribute(table, column) do
|
1940
1955
|
lookup_table_klass_from_join_dependencies(table)
|
1941
1956
|
end
|
@@ -175,6 +175,7 @@ module ActiveRecord
|
|
175
175
|
|
176
176
|
def prepare_all
|
177
177
|
seed = false
|
178
|
+
dump_db_configs = []
|
178
179
|
|
179
180
|
each_current_configuration(env) do |db_config|
|
180
181
|
with_temporary_pool(db_config) do
|
@@ -197,15 +198,25 @@ module ActiveRecord
|
|
197
198
|
|
198
199
|
each_current_environment(env) do |environment|
|
199
200
|
db_configs_with_versions(environment).sort.each do |version, db_configs|
|
201
|
+
dump_db_configs |= db_configs
|
202
|
+
|
200
203
|
db_configs.each do |db_config|
|
201
204
|
with_temporary_pool(db_config) do
|
202
205
|
migrate(version)
|
203
|
-
dump_schema(db_config) if ActiveRecord.dump_schema_after_migration
|
204
206
|
end
|
205
207
|
end
|
206
208
|
end
|
207
209
|
end
|
208
210
|
|
211
|
+
# Dump schema for databases that were migrated.
|
212
|
+
if ActiveRecord.dump_schema_after_migration
|
213
|
+
dump_db_configs.each do |db_config|
|
214
|
+
with_temporary_pool(db_config) do
|
215
|
+
dump_schema(db_config)
|
216
|
+
end
|
217
|
+
end
|
218
|
+
end
|
219
|
+
|
209
220
|
load_seed if seed
|
210
221
|
end
|
211
222
|
|
@@ -52,7 +52,7 @@ module ActiveRecord
|
|
52
52
|
# assert_queries_match(/LIMIT \?/) { Post.first }
|
53
53
|
#
|
54
54
|
# If the +:include_schema+ option is provided, any queries (including schema related)
|
55
|
-
#
|
55
|
+
# that match the matcher are considered.
|
56
56
|
#
|
57
57
|
# assert_queries_match(/FROM pg_attribute/i, include_schema: true) { Post.columns }
|
58
58
|
#
|
@@ -80,7 +80,7 @@ module ActiveRecord
|
|
80
80
|
# assert_no_queries_match(/SELECT/i) { post.comments }
|
81
81
|
#
|
82
82
|
# If the +:include_schema+ option is provided, any queries (including schema related)
|
83
|
-
#
|
83
|
+
# that match the matcher are counted.
|
84
84
|
#
|
85
85
|
# assert_no_queries_match(/FROM pg_attribute/i, include_schema: true) { Post.columns }
|
86
86
|
#
|
data/lib/arel/visitors/sqlite.rb
CHANGED
@@ -33,6 +33,31 @@ module Arel # :nodoc: all
|
|
33
33
|
collector << " IS NOT "
|
34
34
|
visit o.right, collector
|
35
35
|
end
|
36
|
+
|
37
|
+
# Queries used in UNION should not be wrapped by parentheses,
|
38
|
+
# because it is an invalid syntax in SQLite.
|
39
|
+
def infix_value_with_paren(o, collector, value, suppress_parens = false)
|
40
|
+
collector << "( " unless suppress_parens
|
41
|
+
|
42
|
+
left = o.left.is_a?(Nodes::Grouping) ? o.left.expr : o.left
|
43
|
+
collector = if left.class == o.class
|
44
|
+
infix_value_with_paren(left, collector, value, true)
|
45
|
+
else
|
46
|
+
grouping_parentheses left, collector, false
|
47
|
+
end
|
48
|
+
|
49
|
+
collector << value
|
50
|
+
|
51
|
+
right = o.right.is_a?(Nodes::Grouping) ? o.right.expr : o.right
|
52
|
+
collector = if right.class == o.class
|
53
|
+
infix_value_with_paren(right, collector, value, true)
|
54
|
+
else
|
55
|
+
grouping_parentheses right, collector, false
|
56
|
+
end
|
57
|
+
|
58
|
+
collector << " )" unless suppress_parens
|
59
|
+
collector
|
60
|
+
end
|
36
61
|
end
|
37
62
|
end
|
38
63
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: activerecord
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 7.2.
|
4
|
+
version: 7.2.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- David Heinemeier Hansson
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2024-10-
|
11
|
+
date: 2024-10-31 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activesupport
|
@@ -16,28 +16,28 @@ dependencies:
|
|
16
16
|
requirements:
|
17
17
|
- - '='
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version: 7.2.
|
19
|
+
version: 7.2.2
|
20
20
|
type: :runtime
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
24
|
- - '='
|
25
25
|
- !ruby/object:Gem::Version
|
26
|
-
version: 7.2.
|
26
|
+
version: 7.2.2
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
28
|
name: activemodel
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
30
30
|
requirements:
|
31
31
|
- - '='
|
32
32
|
- !ruby/object:Gem::Version
|
33
|
-
version: 7.2.
|
33
|
+
version: 7.2.2
|
34
34
|
type: :runtime
|
35
35
|
prerelease: false
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
37
37
|
requirements:
|
38
38
|
- - '='
|
39
39
|
- !ruby/object:Gem::Version
|
40
|
-
version: 7.2.
|
40
|
+
version: 7.2.2
|
41
41
|
- !ruby/object:Gem::Dependency
|
42
42
|
name: timeout
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
@@ -476,10 +476,10 @@ licenses:
|
|
476
476
|
- MIT
|
477
477
|
metadata:
|
478
478
|
bug_tracker_uri: https://github.com/rails/rails/issues
|
479
|
-
changelog_uri: https://github.com/rails/rails/blob/v7.2.
|
480
|
-
documentation_uri: https://api.rubyonrails.org/v7.2.
|
479
|
+
changelog_uri: https://github.com/rails/rails/blob/v7.2.2/activerecord/CHANGELOG.md
|
480
|
+
documentation_uri: https://api.rubyonrails.org/v7.2.2/
|
481
481
|
mailing_list_uri: https://discuss.rubyonrails.org/c/rubyonrails-talk
|
482
|
-
source_code_uri: https://github.com/rails/rails/tree/v7.2.
|
482
|
+
source_code_uri: https://github.com/rails/rails/tree/v7.2.2/activerecord
|
483
483
|
rubygems_mfa_required: 'true'
|
484
484
|
post_install_message:
|
485
485
|
rdoc_options:
|