activerecord 7.2.1.1 → 7.2.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +144 -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,147 @@
|
|
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
|
+
|
140
|
+
## Rails 7.2.1.2 (October 23, 2024) ##
|
141
|
+
|
142
|
+
* No changes.
|
143
|
+
|
144
|
+
|
1
145
|
## Rails 7.2.1.1 (October 15, 2024) ##
|
2
146
|
|
3
147
|
* 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:
|