activerecord 8.0.0.rc1 → 8.0.0
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 +43 -2
- data/lib/active_record/association_relation.rb +1 -0
- data/lib/active_record/associations/association.rb +9 -5
- data/lib/active_record/associations.rb +28 -16
- data/lib/active_record/attribute_methods.rb +1 -1
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +1 -0
- data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +5 -1
- data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +1 -0
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +7 -2
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +5 -3
- data/lib/active_record/core.rb +29 -3
- data/lib/active_record/database_configurations/database_config.rb +4 -0
- data/lib/active_record/database_configurations/hash_config.rb +8 -0
- data/lib/active_record/enum.rb +55 -50
- data/lib/active_record/gem_version.rb +1 -1
- data/lib/active_record/insert_all.rb +1 -1
- data/lib/active_record/migration/command_recorder.rb +5 -5
- data/lib/active_record/persistence.rb +1 -1
- data/lib/active_record/query_cache.rb +4 -1
- data/lib/active_record/railtie.rb +1 -1
- data/lib/active_record/railties/databases.rake +1 -16
- data/lib/active_record/relation/query_methods.rb +25 -11
- data/lib/active_record/tasks/database_tasks.rb +22 -3
- metadata +10 -10
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: fdca074c8ca76d0768b2989fb21aaafa5c31f3b80ce1d22275ccfd9d88dd6910
|
4
|
+
data.tar.gz: a282424df2605d4c5239f8eedbeb129fe4190e387e7da03292b6ad13e8b2e0ef
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: f636c65b58ab040b9d820854f97f16df201d08142e50c609bb6acbd1f4817d55c2eeeb3859541c9b26ec47c48b20e01a7ec4e5736a68e6c8ce8d4ecb6342d39a
|
7
|
+
data.tar.gz: 7768bdbf0ff1b8dc3c369fc3168c0c66a56fcf21c00502043f846b1531a8e5962067987e33e43015172a8f346829362598838df197f5fa59f02ed44e9cb6a583
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,44 @@
|
|
1
|
+
## Rails 8.0.0 (November 07, 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
|
+
## Rails 8.0.0.rc2 (October 30, 2024) ##
|
10
|
+
|
11
|
+
* NULLS NOT DISTINCT works with UNIQUE CONSTRAINT as well as UNIQUE INDEX.
|
12
|
+
|
13
|
+
*Ryuta Kamizono*
|
14
|
+
|
15
|
+
* The `db:prepare` task no longer loads seeds when a non-primary database is created.
|
16
|
+
|
17
|
+
Previously, the `db:prepare` task would load seeds whenever a new database
|
18
|
+
is created, leading to potential loss of data if a database is added to an
|
19
|
+
existing environment.
|
20
|
+
|
21
|
+
Introduces a new database config property `seeds` to control whether seeds
|
22
|
+
are loaded during `db:prepare` which defaults to `true` for primary database
|
23
|
+
configs and `false` otherwise.
|
24
|
+
|
25
|
+
Fixes #53348.
|
26
|
+
|
27
|
+
*Mike Dalessio*
|
28
|
+
|
29
|
+
* `PG::UnableToSend: no connection to the server` is now retryable as a connection-related exception
|
30
|
+
|
31
|
+
*Kazuma Watanabe*
|
32
|
+
|
33
|
+
* Fix strict loading propagation even if statement cache is not used.
|
34
|
+
|
35
|
+
*Ryuta Kamizono*
|
36
|
+
|
37
|
+
* Allow `rename_enum` accepts two from/to name arguments as `rename_table` does so.
|
38
|
+
|
39
|
+
*Ryuta Kamizono*
|
40
|
+
|
41
|
+
|
1
42
|
## Rails 8.0.0.rc1 (October 19, 2024) ##
|
2
43
|
|
3
44
|
* Remove deprecated support to setting `ENV["SCHEMA_CACHE"]`.
|
@@ -82,9 +123,9 @@
|
|
82
123
|
|
83
124
|
*Ariel Rzezak*
|
84
125
|
|
85
|
-
* When running `db:migrate` on a fresh database, load the
|
126
|
+
* When running `db:migrate` on a fresh database, load the databases schemas before running migrations.
|
86
127
|
|
87
|
-
*Andrew Novoselac*
|
128
|
+
*Andrew Novoselac*, *Marek Kasztelnik*
|
88
129
|
|
89
130
|
* Fix an issue where `.left_outer_joins` used with multiple associations that have
|
90
131
|
the same child association but different parents does not join all parents.
|
@@ -120,6 +120,14 @@ module ActiveRecord
|
|
120
120
|
@association_scope = nil
|
121
121
|
end
|
122
122
|
|
123
|
+
def set_strict_loading(record)
|
124
|
+
if owner.strict_loading_n_plus_one_only? && reflection.macro == :has_many
|
125
|
+
record.strict_loading!
|
126
|
+
else
|
127
|
+
record.strict_loading!(false, mode: owner.strict_loading_mode)
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
123
131
|
# Set the inverse association, if possible
|
124
132
|
def set_inverse_instance(record)
|
125
133
|
if inverse = inverse_association_for(record)
|
@@ -260,11 +268,7 @@ module ActiveRecord
|
|
260
268
|
klass.with_connection do |c|
|
261
269
|
sc.execute(binds, c, async: async) do |record|
|
262
270
|
set_inverse_instance(record)
|
263
|
-
|
264
|
-
record.strict_loading!
|
265
|
-
else
|
266
|
-
record.strict_loading!(false, mode: owner.strict_loading_mode)
|
267
|
-
end
|
271
|
+
set_strict_loading(record)
|
268
272
|
end
|
269
273
|
end
|
270
274
|
end
|
@@ -559,7 +559,7 @@ module ActiveRecord
|
|
559
559
|
# @group.avatars << Avatar.new # this would work if User belonged_to Avatar rather than the other way around
|
560
560
|
# @group.avatars.delete(@group.avatars.last) # so would this
|
561
561
|
#
|
562
|
-
#
|
562
|
+
# === Setting Inverses
|
563
563
|
#
|
564
564
|
# If you are using a #belongs_to on the join model, it is a good idea to set the
|
565
565
|
# <tt>:inverse_of</tt> option on the #belongs_to, which will mean that the following example
|
@@ -1221,8 +1221,11 @@ module ActiveRecord
|
|
1221
1221
|
# If you are going to modify the association (rather than just read from it), then it is
|
1222
1222
|
# a good idea to set the <tt>:inverse_of</tt> option on the source association on the
|
1223
1223
|
# join model. This allows associated records to be built which will automatically create
|
1224
|
-
# the appropriate join model records when they are saved.
|
1225
|
-
#
|
1224
|
+
# the appropriate join model records when they are saved. See
|
1225
|
+
# {Association Join Models}[rdoc-ref:Associations::ClassMethods@Association+Join+Models]
|
1226
|
+
# and {Setting Inverses}[rdoc-ref:Associations::ClassMethods@Setting+Inverses] for
|
1227
|
+
# more detail.
|
1228
|
+
#
|
1226
1229
|
# [+:disable_joins+]
|
1227
1230
|
# Specifies whether joins should be skipped for an association. If set to true, two or more queries
|
1228
1231
|
# will be generated. Note that in some cases, if order or limit is applied, it will be done in-memory
|
@@ -1251,7 +1254,8 @@ module ActiveRecord
|
|
1251
1254
|
# [+:inverse_of+]
|
1252
1255
|
# Specifies the name of the #belongs_to association on the associated object
|
1253
1256
|
# that is the inverse of this #has_many association.
|
1254
|
-
# See
|
1257
|
+
# See {Bi-directional associations}[rdoc-ref:Associations::ClassMethods@Bi-directional+associations]
|
1258
|
+
# for more detail.
|
1255
1259
|
# [+:extend+]
|
1256
1260
|
# Specifies a module or array of modules that will be extended into the association object returned.
|
1257
1261
|
# Useful for defining methods on associations, especially when they should be shared between multiple
|
@@ -1300,10 +1304,12 @@ module ActiveRecord
|
|
1300
1304
|
Reflection.add_reflection self, name, reflection
|
1301
1305
|
end
|
1302
1306
|
|
1303
|
-
# Specifies a one-to-one association with another class. This method
|
1304
|
-
# if the other class contains the foreign key. If
|
1305
|
-
#
|
1306
|
-
#
|
1307
|
+
# Specifies a one-to-one association with another class. This method
|
1308
|
+
# should only be used if the other class contains the foreign key. If
|
1309
|
+
# the current class contains the foreign key, then you should use
|
1310
|
+
# #belongs_to instead. See {Is it a belongs_to or has_one
|
1311
|
+
# association?}[rdoc-ref:Associations::ClassMethods@Is+it+a+-23belongs_to+or+-23has_one+association-3F]
|
1312
|
+
# for more detail on when to use #has_one and when to use #belongs_to.
|
1307
1313
|
#
|
1308
1314
|
# The following methods for retrieval and query of a single associated object will be added:
|
1309
1315
|
#
|
@@ -1418,8 +1424,10 @@ module ActiveRecord
|
|
1418
1424
|
# If you are going to modify the association (rather than just read from it), then it is
|
1419
1425
|
# a good idea to set the <tt>:inverse_of</tt> option on the source association on the
|
1420
1426
|
# join model. This allows associated records to be built which will automatically create
|
1421
|
-
# the appropriate join model records when they are saved.
|
1422
|
-
#
|
1427
|
+
# the appropriate join model records when they are saved. See
|
1428
|
+
# {Association Join Models}[rdoc-ref:Associations::ClassMethods@Association+Join+Models]
|
1429
|
+
# and {Setting Inverses}[rdoc-ref:Associations::ClassMethods@Setting+Inverses] for
|
1430
|
+
# more detail.
|
1423
1431
|
# [+:disable_joins+]
|
1424
1432
|
# Specifies whether joins should be skipped for an association. If set to true, two or more queries
|
1425
1433
|
# will be generated. Note that in some cases, if order or limit is applied, it will be done in-memory
|
@@ -1457,7 +1465,8 @@ module ActiveRecord
|
|
1457
1465
|
# [+:inverse_of+]
|
1458
1466
|
# Specifies the name of the #belongs_to association on the associated object
|
1459
1467
|
# that is the inverse of this #has_one association.
|
1460
|
-
# See
|
1468
|
+
# See {Bi-directional associations}[rdoc-ref:Associations::ClassMethods@Bi-directional+associations]
|
1469
|
+
# for more detail.
|
1461
1470
|
# [+:required+]
|
1462
1471
|
# When set to +true+, the association will also have its presence validated.
|
1463
1472
|
# This will validate the association itself, not the id. You can use
|
@@ -1491,10 +1500,12 @@ module ActiveRecord
|
|
1491
1500
|
Reflection.add_reflection self, name, reflection
|
1492
1501
|
end
|
1493
1502
|
|
1494
|
-
# Specifies a one-to-one association with another class. This method
|
1495
|
-
# if this class contains the foreign key. If the
|
1496
|
-
# then you should use #has_one
|
1497
|
-
#
|
1503
|
+
# Specifies a one-to-one association with another class. This method
|
1504
|
+
# should only be used if this class contains the foreign key. If the
|
1505
|
+
# other class contains the foreign key, then you should use #has_one
|
1506
|
+
# instead. See {Is it a belongs_to or has_one
|
1507
|
+
# association?}[rdoc-ref:Associations::ClassMethods@Is+it+a+-23belongs_to+or+-23has_one+association-3F]
|
1508
|
+
# for more detail on when to use #has_one and when to use #belongs_to.
|
1498
1509
|
#
|
1499
1510
|
# Methods will be added for retrieval and query for a single associated object, for which
|
1500
1511
|
# this object holds an id:
|
@@ -1636,7 +1647,8 @@ module ActiveRecord
|
|
1636
1647
|
# [+:inverse_of+]
|
1637
1648
|
# Specifies the name of the #has_one or #has_many association on the associated
|
1638
1649
|
# object that is the inverse of this #belongs_to association.
|
1639
|
-
# See
|
1650
|
+
# See {Bi-directional associations}[rdoc-ref:Associations::ClassMethods@Bi-directional+associations]
|
1651
|
+
# for more detail.
|
1640
1652
|
# [+:optional+]
|
1641
1653
|
# When set to +true+, the association will not have its presence validated.
|
1642
1654
|
# [+:required+]
|
@@ -84,7 +84,7 @@ module ActiveRecord
|
|
84
84
|
attribute_method_patterns_cache.clear
|
85
85
|
end
|
86
86
|
|
87
|
-
def alias_attribute_method_definition(code_generator, pattern, new_name, old_name)
|
87
|
+
def alias_attribute_method_definition(code_generator, pattern, new_name, old_name) # :nodoc:
|
88
88
|
old_name = old_name.to_s
|
89
89
|
|
90
90
|
if !abstract_class? && !has_attribute?(old_name)
|
@@ -674,7 +674,7 @@ module ActiveRecord
|
|
674
674
|
raise AsynchronousQueryInsideTransactionError, "Asynchronous queries are not allowed inside transactions"
|
675
675
|
end
|
676
676
|
|
677
|
-
# We make sure to run query transformers on the
|
677
|
+
# We make sure to run query transformers on the original thread
|
678
678
|
sql = preprocess_query(sql)
|
679
679
|
future_result = async.new(
|
680
680
|
pool,
|
@@ -52,6 +52,7 @@ module ActiveRecord
|
|
52
52
|
sql = ["CONSTRAINT"]
|
53
53
|
sql << quote_column_name(o.name)
|
54
54
|
sql << "UNIQUE"
|
55
|
+
sql << "NULLS NOT DISTINCT" if supports_nulls_not_distinct? && o.nulls_not_distinct
|
55
56
|
|
56
57
|
if o.using_index
|
57
58
|
sql << "USING INDEX #{quote_column_name(o.using_index)}"
|
@@ -224,6 +224,10 @@ module ActiveRecord
|
|
224
224
|
options[:using_index]
|
225
225
|
end
|
226
226
|
|
227
|
+
def nulls_not_distinct
|
228
|
+
options[:nulls_not_distinct]
|
229
|
+
end
|
230
|
+
|
227
231
|
def export_name_on_schema_dump?
|
228
232
|
!ActiveRecord::SchemaDumper.unique_ignore_pattern.match?(name) if name
|
229
233
|
end
|
@@ -317,7 +321,7 @@ module ActiveRecord
|
|
317
321
|
|
318
322
|
# Adds a unique constraint.
|
319
323
|
#
|
320
|
-
# t.unique_constraint(:position, name: 'unique_position', deferrable: :deferred)
|
324
|
+
# t.unique_constraint(:position, name: 'unique_position', deferrable: :deferred, nulls_not_distinct: true)
|
321
325
|
#
|
322
326
|
# See {connection.add_unique_constraint}[rdoc-ref:SchemaStatements#add_unique_constraint]
|
323
327
|
def unique_constraint(*args)
|
@@ -68,6 +68,7 @@ module ActiveRecord
|
|
68
68
|
"t.unique_constraint #{unique_constraint.column.inspect}"
|
69
69
|
]
|
70
70
|
|
71
|
+
parts << "nulls_not_distinct: #{unique_constraint.nulls_not_distinct.inspect}" if unique_constraint.nulls_not_distinct
|
71
72
|
parts << "deferrable: #{unique_constraint.deferrable.inspect}" if unique_constraint.deferrable
|
72
73
|
|
73
74
|
if unique_constraint.export_name_on_schema_dump?
|
@@ -698,7 +698,7 @@ module ActiveRecord
|
|
698
698
|
scope = quoted_scope(table_name)
|
699
699
|
|
700
700
|
unique_info = internal_exec_query(<<~SQL, "SCHEMA", allow_retry: true, materialize_transactions: false)
|
701
|
-
SELECT c.conname, c.conrelid, c.conkey, c.condeferrable, c.condeferred
|
701
|
+
SELECT c.conname, c.conrelid, c.conkey, c.condeferrable, c.condeferred, pg_get_constraintdef(c.oid) AS constraintdef
|
702
702
|
FROM pg_constraint c
|
703
703
|
JOIN pg_class t ON c.conrelid = t.oid
|
704
704
|
JOIN pg_namespace n ON n.oid = c.connamespace
|
@@ -711,10 +711,12 @@ module ActiveRecord
|
|
711
711
|
conkey = row["conkey"].delete("{}").split(",").map(&:to_i)
|
712
712
|
columns = column_names_from_column_numbers(row["conrelid"], conkey)
|
713
713
|
|
714
|
+
nulls_not_distinct = row["constraintdef"].start_with?("UNIQUE NULLS NOT DISTINCT")
|
714
715
|
deferrable = extract_constraint_deferrable(row["condeferrable"], row["condeferred"])
|
715
716
|
|
716
717
|
options = {
|
717
718
|
name: row["conname"],
|
719
|
+
nulls_not_distinct: nulls_not_distinct,
|
718
720
|
deferrable: deferrable
|
719
721
|
}
|
720
722
|
|
@@ -771,7 +773,7 @@ module ActiveRecord
|
|
771
773
|
|
772
774
|
# Adds a new unique constraint to the table.
|
773
775
|
#
|
774
|
-
# add_unique_constraint :sections, [:position], deferrable: :deferred, name: "unique_position"
|
776
|
+
# add_unique_constraint :sections, [:position], deferrable: :deferred, name: "unique_position", nulls_not_distinct: true
|
775
777
|
#
|
776
778
|
# generates:
|
777
779
|
#
|
@@ -788,6 +790,9 @@ module ActiveRecord
|
|
788
790
|
# Specify whether or not the unique constraint should be deferrable. Valid values are +false+ or +:immediate+ or +:deferred+ to specify the default behavior. Defaults to +false+.
|
789
791
|
# [<tt>:using_index</tt>]
|
790
792
|
# To specify an existing unique index name. Defaults to +nil+.
|
793
|
+
# [<tt>:nulls_not_distinct</tt>]
|
794
|
+
# Create a unique constraint where NULLs are treated equally.
|
795
|
+
# Note: only supported by PostgreSQL version 15.0.0 and greater.
|
791
796
|
def add_unique_constraint(table_name, column_name = nil, **options)
|
792
797
|
options = unique_constraint_options(table_name, column_name, options)
|
793
798
|
at = create_alter_table(table_name)
|
@@ -575,8 +575,10 @@ module ActiveRecord
|
|
575
575
|
end
|
576
576
|
|
577
577
|
# Rename an existing enum type to something else.
|
578
|
-
def rename_enum(name, **options)
|
579
|
-
new_name
|
578
|
+
def rename_enum(name, new_name = nil, **options)
|
579
|
+
new_name ||= options.fetch(:to) do
|
580
|
+
raise ArgumentError, "rename_enum requires two from/to name positional arguments."
|
581
|
+
end
|
580
582
|
|
581
583
|
exec_query("ALTER TYPE #{quote_table_name(name)} RENAME TO #{quote_table_name(new_name)}").tap { reload_type_map }
|
582
584
|
end
|
@@ -796,7 +798,7 @@ module ActiveRecord
|
|
796
798
|
|
797
799
|
case exception.result.try(:error_field, PG::PG_DIAG_SQLSTATE)
|
798
800
|
when nil
|
799
|
-
if exception.message.match?(/connection is closed/i)
|
801
|
+
if exception.message.match?(/connection is closed/i) || exception.message.match?(/no connection to the server/i)
|
800
802
|
ConnectionNotEstablished.new(exception, connection_pool: @pool)
|
801
803
|
elsif exception.is_a?(PG::ConnectionBad)
|
802
804
|
# libpq message style always ends with a newline; the pg gem's internal
|
data/lib/active_record/core.rb
CHANGED
@@ -103,7 +103,19 @@ module ActiveRecord
|
|
103
103
|
|
104
104
|
class_attribute :shard_selector, instance_accessor: false, default: nil
|
105
105
|
|
106
|
-
|
106
|
+
##
|
107
|
+
# :singleton-method:
|
108
|
+
#
|
109
|
+
# Specifies the attributes that will be included in the output of the
|
110
|
+
# #inspect method:
|
111
|
+
#
|
112
|
+
# Post.attributes_for_inspect = [:id, :title]
|
113
|
+
# Post.first.inspect #=> "#<Post id: 1, title: "Hello, World!">"
|
114
|
+
#
|
115
|
+
# When set to `:all` inspect will list all the record's attributes:
|
116
|
+
#
|
117
|
+
# Post.attributes_for_inspect = :all
|
118
|
+
# Post.first.inspect #=> "#<Post id: 1, title: "Hello, World!", published_at: "2023-10-23 14:28:11 +0000">"
|
107
119
|
class_attribute :attributes_for_inspect, instance_accessor: false, default: :all
|
108
120
|
|
109
121
|
def self.application_record_class? # :nodoc:
|
@@ -728,12 +740,26 @@ module ActiveRecord
|
|
728
740
|
self.class.connection_handler
|
729
741
|
end
|
730
742
|
|
731
|
-
# Returns the attributes
|
743
|
+
# Returns the attributes of the record as a nicely formatted string.
|
744
|
+
#
|
745
|
+
# Post.first.inspect
|
746
|
+
# #=> "#<Post id: 1, title: "Hello, World!", published_at: "2023-10-23 14:28:11 +0000">"
|
747
|
+
#
|
748
|
+
# The attributes can be limited by setting <tt>.attributes_for_inspect</tt>.
|
749
|
+
#
|
750
|
+
# Post.attributes_for_inspect = [:id, :title]
|
751
|
+
# Post.first.inspect
|
752
|
+
# #=> "#<Post id: 1, title: "Hello, World!">"
|
732
753
|
def inspect
|
733
754
|
inspect_with_attributes(attributes_for_inspect)
|
734
755
|
end
|
735
756
|
|
736
|
-
# Returns
|
757
|
+
# Returns all attributes of the record as a nicely formatted string,
|
758
|
+
# ignoring <tt>.attributes_for_inspect</tt>.
|
759
|
+
#
|
760
|
+
# Post.first.full_inspect
|
761
|
+
# #=> "#<Post id: 1, title: "Hello, World!", published_at: "2023-10-23 14:28:11 +0000">"
|
762
|
+
#
|
737
763
|
def full_inspect
|
738
764
|
inspect_with_attributes(all_attributes_for_inspect)
|
739
765
|
end
|
@@ -130,6 +130,14 @@ module ActiveRecord
|
|
130
130
|
Base.configurations.primary?(name)
|
131
131
|
end
|
132
132
|
|
133
|
+
# Determines whether the db:prepare task should seed the database from db/seeds.rb.
|
134
|
+
#
|
135
|
+
# If the `seeds` key is present in the config, `seeds?` will return its value. Otherwise, it
|
136
|
+
# will return `true` for the primary database and `false` for all other configs.
|
137
|
+
def seeds?
|
138
|
+
configuration_hash.fetch(:seeds, primary?)
|
139
|
+
end
|
140
|
+
|
133
141
|
# Determines whether to dump the schema/structure files and the filename that
|
134
142
|
# should be used.
|
135
143
|
#
|
data/lib/active_record/enum.rb
CHANGED
@@ -213,74 +213,79 @@ module ActiveRecord
|
|
213
213
|
attr_reader :name, :mapping
|
214
214
|
end
|
215
215
|
|
216
|
-
def enum(name, values
|
217
|
-
|
218
|
-
|
216
|
+
def enum(name, values = nil, **options)
|
217
|
+
values, options = options, {} unless values
|
218
|
+
_enum(name, values, **options)
|
219
|
+
end
|
219
220
|
|
220
|
-
|
221
|
-
|
222
|
-
|
221
|
+
private
|
222
|
+
def _enum(name, values, prefix: nil, suffix: nil, scopes: true, instance_methods: true, validate: false, **options)
|
223
|
+
assert_valid_enum_definition_values(values)
|
224
|
+
assert_valid_enum_options(options)
|
223
225
|
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
defined_enums[name] = enum_values
|
226
|
+
# statuses = { }
|
227
|
+
enum_values = ActiveSupport::HashWithIndifferentAccess.new
|
228
|
+
name = name.to_s
|
228
229
|
|
229
|
-
|
230
|
-
|
230
|
+
# def self.statuses() statuses end
|
231
|
+
detect_enum_conflict!(name, name.pluralize, true)
|
232
|
+
singleton_class.define_method(name.pluralize) { enum_values }
|
233
|
+
defined_enums[name] = enum_values
|
231
234
|
|
232
|
-
|
235
|
+
detect_enum_conflict!(name, name)
|
236
|
+
detect_enum_conflict!(name, "#{name}=")
|
233
237
|
|
234
|
-
|
235
|
-
if subtype == ActiveModel::Type.default_value
|
236
|
-
raise "Undeclared attribute type for enum '#{name}' in #{self.name}. Enums must be" \
|
237
|
-
" backed by a database column or declared with an explicit type" \
|
238
|
-
" via `attribute`."
|
239
|
-
end
|
238
|
+
attribute(name, **options)
|
240
239
|
|
241
|
-
|
242
|
-
|
243
|
-
|
240
|
+
decorate_attributes([name]) do |_name, subtype|
|
241
|
+
if subtype == ActiveModel::Type.default_value
|
242
|
+
raise "Undeclared attribute type for enum '#{name}' in #{self.name}. Enums must be" \
|
243
|
+
" backed by a database column or declared with an explicit type" \
|
244
|
+
" via `attribute`."
|
245
|
+
end
|
244
246
|
|
245
|
-
|
246
|
-
|
247
|
-
prefix = if prefix
|
248
|
-
prefix == true ? "#{name}_" : "#{prefix}_"
|
247
|
+
subtype = subtype.subtype if EnumType === subtype
|
248
|
+
EnumType.new(name, enum_values, subtype, raise_on_invalid_values: !validate)
|
249
249
|
end
|
250
250
|
|
251
|
-
|
252
|
-
|
253
|
-
|
251
|
+
value_method_names = []
|
252
|
+
_enum_methods_module.module_eval do
|
253
|
+
prefix = if prefix
|
254
|
+
prefix == true ? "#{name}_" : "#{prefix}_"
|
255
|
+
end
|
256
|
+
|
257
|
+
suffix = if suffix
|
258
|
+
suffix == true ? "_#{name}" : "_#{suffix}"
|
259
|
+
end
|
254
260
|
|
255
|
-
|
256
|
-
|
257
|
-
|
258
|
-
|
261
|
+
pairs = values.respond_to?(:each_pair) ? values.each_pair : values.each_with_index
|
262
|
+
pairs.each do |label, value|
|
263
|
+
enum_values[label] = value
|
264
|
+
label = label.to_s
|
259
265
|
|
260
|
-
|
261
|
-
|
262
|
-
|
266
|
+
value_method_name = "#{prefix}#{label}#{suffix}"
|
267
|
+
value_method_names << value_method_name
|
268
|
+
define_enum_methods(name, value_method_name, value, scopes, instance_methods)
|
263
269
|
|
264
|
-
|
265
|
-
|
270
|
+
method_friendly_label = label.gsub(/[\W&&[:ascii:]]+/, "_")
|
271
|
+
value_method_alias = "#{prefix}#{method_friendly_label}#{suffix}"
|
266
272
|
|
267
|
-
|
268
|
-
|
269
|
-
|
273
|
+
if value_method_alias != value_method_name && !value_method_names.include?(value_method_alias)
|
274
|
+
value_method_names << value_method_alias
|
275
|
+
define_enum_methods(name, value_method_alias, value, scopes, instance_methods)
|
276
|
+
end
|
270
277
|
end
|
271
278
|
end
|
272
|
-
|
273
|
-
detect_negative_enum_conditions!(value_method_names) if scopes
|
279
|
+
detect_negative_enum_conditions!(value_method_names) if scopes
|
274
280
|
|
275
|
-
|
276
|
-
|
277
|
-
|
278
|
-
|
281
|
+
if validate
|
282
|
+
validate = {} unless Hash === validate
|
283
|
+
validates_inclusion_of name, in: enum_values.keys, **validate
|
284
|
+
end
|
279
285
|
|
280
|
-
|
281
|
-
|
286
|
+
enum_values.freeze
|
287
|
+
end
|
282
288
|
|
283
|
-
private
|
284
289
|
def inherited(base)
|
285
290
|
base.defined_enums = defined_enums.deep_dup
|
286
291
|
super
|
@@ -240,7 +240,7 @@ module ActiveRecord
|
|
240
240
|
|
241
241
|
values_list = insert_all.map_key_with_value do |key, value|
|
242
242
|
next value if Arel::Nodes::SqlLiteral === value
|
243
|
-
|
243
|
+
ActiveModel::Type::SerializeCastValue.serialize(type = types[key], type.cast(value))
|
244
244
|
end
|
245
245
|
|
246
246
|
connection.visitor.compile(Arel::Nodes::ValuesList.new(values_list))
|
@@ -40,7 +40,7 @@ module ActiveRecord
|
|
40
40
|
# * remove_reference
|
41
41
|
# * remove_timestamps
|
42
42
|
# * rename_column
|
43
|
-
# * rename_enum
|
43
|
+
# * rename_enum
|
44
44
|
# * rename_enum_value (must supply a +:from+ and +:to+ option)
|
45
45
|
# * rename_index
|
46
46
|
# * rename_table
|
@@ -364,13 +364,13 @@ module ActiveRecord
|
|
364
364
|
end
|
365
365
|
|
366
366
|
def invert_rename_enum(args)
|
367
|
-
name,
|
367
|
+
name, new_name, = args
|
368
368
|
|
369
|
-
|
370
|
-
|
369
|
+
if new_name.is_a?(Hash) && new_name.key?(:to)
|
370
|
+
new_name = new_name[:to]
|
371
371
|
end
|
372
372
|
|
373
|
-
[:rename_enum, [
|
373
|
+
[:rename_enum, [new_name, name]]
|
374
374
|
end
|
375
375
|
|
376
376
|
def invert_rename_enum_value(args)
|
@@ -930,7 +930,7 @@ module ActiveRecord
|
|
930
930
|
)
|
931
931
|
|
932
932
|
returning_columns.zip(returning_values).each do |column, value|
|
933
|
-
_write_attribute(column, value) if !_read_attribute(column)
|
933
|
+
_write_attribute(column, type_for_attribute(column).deserialize(value)) if !_read_attribute(column)
|
934
934
|
end if returning_values
|
935
935
|
end
|
936
936
|
|
@@ -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)
|
@@ -87,22 +87,7 @@ db_namespace = namespace :db do
|
|
87
87
|
|
88
88
|
desc "Migrate the database (options: VERSION=x, VERBOSE=false, SCOPE=blog)."
|
89
89
|
task migrate: :load_config do
|
90
|
-
|
91
|
-
|
92
|
-
if db_configs.size == 1 && db_configs.first.primary?
|
93
|
-
ActiveRecord::Tasks::DatabaseTasks.migrate
|
94
|
-
else
|
95
|
-
mapped_versions = ActiveRecord::Tasks::DatabaseTasks.db_configs_with_versions
|
96
|
-
|
97
|
-
mapped_versions.sort.each do |version, db_configs|
|
98
|
-
db_configs.each do |db_config|
|
99
|
-
ActiveRecord::Tasks::DatabaseTasks.with_temporary_connection(db_config) do
|
100
|
-
ActiveRecord::Tasks::DatabaseTasks.migrate(version)
|
101
|
-
end
|
102
|
-
end
|
103
|
-
end
|
104
|
-
end
|
105
|
-
|
90
|
+
ActiveRecord::Tasks::DatabaseTasks.migrate_all
|
106
91
|
db_namespace["_dump"].invoke
|
107
92
|
end
|
108
93
|
|
@@ -498,7 +498,8 @@ module ActiveRecord
|
|
498
498
|
|
499
499
|
# Like #with, but modifies relation in place.
|
500
500
|
def with!(*args) # :nodoc:
|
501
|
-
|
501
|
+
args = process_with_args(args)
|
502
|
+
self.with_values |= args
|
502
503
|
self
|
503
504
|
end
|
504
505
|
|
@@ -521,7 +522,8 @@ module ActiveRecord
|
|
521
522
|
|
522
523
|
# Like #with_recursive but modifies the relation in place.
|
523
524
|
def with_recursive!(*args) # :nodoc:
|
524
|
-
|
525
|
+
args = process_with_args(args)
|
526
|
+
self.with_values |= args
|
525
527
|
@with_is_recursive = true
|
526
528
|
self
|
527
529
|
end
|
@@ -1912,8 +1914,6 @@ module ActiveRecord
|
|
1912
1914
|
return if with_values.empty?
|
1913
1915
|
|
1914
1916
|
with_statements = with_values.map do |with_value|
|
1915
|
-
raise ArgumentError, "Unsupported argument type: #{with_value} #{with_value.class}" unless with_value.is_a?(Hash)
|
1916
|
-
|
1917
1917
|
build_with_value_from_hash(with_value)
|
1918
1918
|
end
|
1919
1919
|
|
@@ -1964,10 +1964,10 @@ module ActiveRecord
|
|
1964
1964
|
table_name = table_name.name if table_name.is_a?(Symbol)
|
1965
1965
|
case columns
|
1966
1966
|
when Symbol, String
|
1967
|
-
arel_column_with_table(table_name, columns
|
1967
|
+
arel_column_with_table(table_name, columns)
|
1968
1968
|
when Array
|
1969
1969
|
columns.map do |column|
|
1970
|
-
arel_column_with_table(table_name, column
|
1970
|
+
arel_column_with_table(table_name, column)
|
1971
1971
|
end
|
1972
1972
|
else
|
1973
1973
|
raise TypeError, "Expected Symbol, String or Array, got: #{columns.class}"
|
@@ -1977,8 +1977,13 @@ module ActiveRecord
|
|
1977
1977
|
|
1978
1978
|
def arel_column_with_table(table_name, column_name)
|
1979
1979
|
self.references_values |= [Arel.sql(table_name, retryable: true)]
|
1980
|
-
|
1981
|
-
|
1980
|
+
|
1981
|
+
if column_name.is_a?(Symbol) || !column_name.match?(/\W/)
|
1982
|
+
predicate_builder.resolve_arel_attribute(table_name, column_name) do
|
1983
|
+
lookup_table_klass_from_join_dependencies(table_name)
|
1984
|
+
end
|
1985
|
+
else
|
1986
|
+
Arel.sql("#{model.adapter_class.quote_table_name(table_name)}.#{column_name}")
|
1982
1987
|
end
|
1983
1988
|
end
|
1984
1989
|
|
@@ -1994,6 +1999,8 @@ module ActiveRecord
|
|
1994
1999
|
arel_column_with_table(table, column)
|
1995
2000
|
elsif block_given?
|
1996
2001
|
yield field
|
2002
|
+
elsif Arel.arel_node?(field)
|
2003
|
+
field
|
1997
2004
|
else
|
1998
2005
|
Arel.sql(is_symbol ? model.adapter_class.quote_table_name(field) : field)
|
1999
2006
|
end
|
@@ -2136,7 +2143,7 @@ module ActiveRecord
|
|
2136
2143
|
arg.expr.relation.name
|
2137
2144
|
end
|
2138
2145
|
end
|
2139
|
-
end.
|
2146
|
+
end.filter_map { |ref| Arel.sql(ref, retryable: true) if ref }
|
2140
2147
|
end
|
2141
2148
|
|
2142
2149
|
def extract_table_name_from(string)
|
@@ -2230,12 +2237,12 @@ module ActiveRecord
|
|
2230
2237
|
case columns_aliases
|
2231
2238
|
when Hash
|
2232
2239
|
columns_aliases.map do |column, column_alias|
|
2233
|
-
arel_column_with_table(table_name, column
|
2240
|
+
arel_column_with_table(table_name, column)
|
2234
2241
|
.as(model.adapter_class.quote_column_name(column_alias.to_s))
|
2235
2242
|
end
|
2236
2243
|
when Array
|
2237
2244
|
columns_aliases.map do |column|
|
2238
|
-
arel_column_with_table(table_name, column
|
2245
|
+
arel_column_with_table(table_name, column)
|
2239
2246
|
end
|
2240
2247
|
when String, Symbol
|
2241
2248
|
arel_column(key)
|
@@ -2244,6 +2251,13 @@ module ActiveRecord
|
|
2244
2251
|
end
|
2245
2252
|
end
|
2246
2253
|
|
2254
|
+
def process_with_args(args)
|
2255
|
+
args.flat_map do |arg|
|
2256
|
+
raise ArgumentError, "Unsupported argument type: #{arg} #{arg.class}" unless arg.is_a?(Hash)
|
2257
|
+
arg.map { |k, v| { k => v } }
|
2258
|
+
end
|
2259
|
+
end
|
2260
|
+
|
2247
2261
|
STRUCTURAL_VALUE_METHODS = (
|
2248
2262
|
Relation::VALUE_METHODS -
|
2249
2263
|
[:extending, :where, :having, :unscope, :references, :annotate, :optimizer_hints]
|
@@ -180,7 +180,7 @@ module ActiveRecord
|
|
180
180
|
each_current_configuration(env) do |db_config|
|
181
181
|
database_initialized = initialize_database(db_config)
|
182
182
|
|
183
|
-
seed = true if database_initialized
|
183
|
+
seed = true if database_initialized && db_config.seeds?
|
184
184
|
end
|
185
185
|
|
186
186
|
each_current_environment(env) do |environment|
|
@@ -240,13 +240,32 @@ module ActiveRecord
|
|
240
240
|
end
|
241
241
|
end
|
242
242
|
|
243
|
-
def
|
243
|
+
def migrate_all
|
244
|
+
db_configs = ActiveRecord::Base.configurations.configs_for(env_name: ActiveRecord::Tasks::DatabaseTasks.env)
|
245
|
+
db_configs.each { |db_config| initialize_database(db_config) }
|
246
|
+
|
247
|
+
if db_configs.size == 1 && db_configs.first.primary?
|
248
|
+
ActiveRecord::Tasks::DatabaseTasks.migrate(skip_initialize: true)
|
249
|
+
else
|
250
|
+
mapped_versions = ActiveRecord::Tasks::DatabaseTasks.db_configs_with_versions
|
251
|
+
|
252
|
+
mapped_versions.sort.each do |version, db_configs|
|
253
|
+
db_configs.each do |db_config|
|
254
|
+
ActiveRecord::Tasks::DatabaseTasks.with_temporary_connection(db_config) do
|
255
|
+
ActiveRecord::Tasks::DatabaseTasks.migrate(version, skip_initialize: true)
|
256
|
+
end
|
257
|
+
end
|
258
|
+
end
|
259
|
+
end
|
260
|
+
end
|
261
|
+
|
262
|
+
def migrate(version = nil, skip_initialize: false)
|
244
263
|
scope = ENV["SCOPE"]
|
245
264
|
verbose_was, Migration.verbose = Migration.verbose, verbose?
|
246
265
|
|
247
266
|
check_target_version
|
248
267
|
|
249
|
-
initialize_database(migration_connection_pool.db_config)
|
268
|
+
initialize_database(migration_connection_pool.db_config) unless skip_initialize
|
250
269
|
|
251
270
|
migration_connection_pool.migration_context.migrate(target_version) do |migration|
|
252
271
|
if version.blank?
|
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: 8.0.0
|
4
|
+
version: 8.0.0
|
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-
|
11
|
+
date: 2024-11-07 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: 8.0.0
|
19
|
+
version: 8.0.0
|
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: 8.0.0
|
26
|
+
version: 8.0.0
|
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: 8.0.0
|
33
|
+
version: 8.0.0
|
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: 8.0.0
|
40
|
+
version: 8.0.0
|
41
41
|
- !ruby/object:Gem::Dependency
|
42
42
|
name: timeout
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
@@ -475,10 +475,10 @@ licenses:
|
|
475
475
|
- MIT
|
476
476
|
metadata:
|
477
477
|
bug_tracker_uri: https://github.com/rails/rails/issues
|
478
|
-
changelog_uri: https://github.com/rails/rails/blob/v8.0.0
|
479
|
-
documentation_uri: https://api.rubyonrails.org/v8.0.0
|
478
|
+
changelog_uri: https://github.com/rails/rails/blob/v8.0.0/activerecord/CHANGELOG.md
|
479
|
+
documentation_uri: https://api.rubyonrails.org/v8.0.0/
|
480
480
|
mailing_list_uri: https://discuss.rubyonrails.org/c/rubyonrails-talk
|
481
|
-
source_code_uri: https://github.com/rails/rails/tree/v8.0.0
|
481
|
+
source_code_uri: https://github.com/rails/rails/tree/v8.0.0/activerecord
|
482
482
|
rubygems_mfa_required: 'true'
|
483
483
|
post_install_message:
|
484
484
|
rdoc_options:
|
@@ -497,7 +497,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
497
497
|
- !ruby/object:Gem::Version
|
498
498
|
version: '0'
|
499
499
|
requirements: []
|
500
|
-
rubygems_version: 3.5.
|
500
|
+
rubygems_version: 3.5.22
|
501
501
|
signing_key:
|
502
502
|
specification_version: 4
|
503
503
|
summary: Object-relational mapper framework (part of Rails).
|