activerecord 8.0.0.rc1 → 8.0.0.rc2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +35 -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/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/migration/command_recorder.rb +5 -5
- 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 +10 -2
- data/lib/active_record/tasks/database_tasks.rb +22 -3
- 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: 5b6b5ce7951d63889da24f22f9635d27371d6fc733e400d1510cd0ffe27f669e
|
4
|
+
data.tar.gz: 68f851f76e82b3969bc3a7125b3700ce3623ed7cf1717064f26202b4a5c062cd
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ef1e91d706ec3c79e71b2e59780a831a63fe82ab45a8e123748c5d073bc120c3d9506d3e8b43b68aa77dc90a5f564b8ef45cb1d5abc19e008127757966bf32dc
|
7
|
+
data.tar.gz: 35e7644e3037334b724042c5f26539c2489c579fede36d461e3661cf04ca79b5c8ca0b3e3c29d8edfc9eab3de15af0b8dcee33a7d88f2f4985c46acfce26a324
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,36 @@
|
|
1
|
+
## Rails 8.0.0.rc2 (October 30, 2024) ##
|
2
|
+
|
3
|
+
* NULLS NOT DISTINCT works with UNIQUE CONSTRAINT as well as UNIQUE INDEX.
|
4
|
+
|
5
|
+
*Ryuta Kamizono*
|
6
|
+
|
7
|
+
* The `db:prepare` task no longer loads seeds when a non-primary database is created.
|
8
|
+
|
9
|
+
Previously, the `db:prepare` task would load seeds whenever a new database
|
10
|
+
is created, leading to potential loss of data if a database is added to an
|
11
|
+
existing environment.
|
12
|
+
|
13
|
+
Introduces a new database config property `seeds` to control whether seeds
|
14
|
+
are loaded during `db:prepare` which defaults to `true` for primary database
|
15
|
+
configs and `false` otherwise.
|
16
|
+
|
17
|
+
Fixes #53348.
|
18
|
+
|
19
|
+
*Mike Dalessio*
|
20
|
+
|
21
|
+
* `PG::UnableToSend: no connection to the server` is now retryable as a connection-related exception
|
22
|
+
|
23
|
+
*Kazuma Watanabe*
|
24
|
+
|
25
|
+
* Fix strict loading propagation even if statement cache is not used.
|
26
|
+
|
27
|
+
*Ryuta Kamizono*
|
28
|
+
|
29
|
+
* Allow `rename_enum` accepts two from/to name arguments as `rename_table` does so.
|
30
|
+
|
31
|
+
*Ryuta Kamizono*
|
32
|
+
|
33
|
+
|
1
34
|
## Rails 8.0.0.rc1 (October 19, 2024) ##
|
2
35
|
|
3
36
|
* Remove deprecated support to setting `ENV["SCHEMA_CACHE"]`.
|
@@ -82,9 +115,9 @@
|
|
82
115
|
|
83
116
|
*Ariel Rzezak*
|
84
117
|
|
85
|
-
* When running `db:migrate` on a fresh database, load the
|
118
|
+
* When running `db:migrate` on a fresh database, load the databases schemas before running migrations.
|
86
119
|
|
87
|
-
*Andrew Novoselac*
|
120
|
+
*Andrew Novoselac*, *Marek Kasztelnik*
|
88
121
|
|
89
122
|
* Fix an issue where `.left_outer_joins` used with multiple associations that have
|
90
123
|
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+]
|
@@ -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
|
@@ -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)
|
@@ -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
|
@@ -2244,6 +2246,12 @@ module ActiveRecord
|
|
2244
2246
|
end
|
2245
2247
|
end
|
2246
2248
|
|
2249
|
+
def process_with_args(args)
|
2250
|
+
args.flat_map do |arg|
|
2251
|
+
arg.map { |k, v| { k => v } }
|
2252
|
+
end
|
2253
|
+
end
|
2254
|
+
|
2247
2255
|
STRUCTURAL_VALUE_METHODS = (
|
2248
2256
|
Relation::VALUE_METHODS -
|
2249
2257
|
[: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.rc2
|
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-30 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.rc2
|
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.rc2
|
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.rc2
|
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.rc2
|
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.rc2/activerecord/CHANGELOG.md
|
479
|
+
documentation_uri: https://api.rubyonrails.org/v8.0.0.rc2/
|
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.rc2/activerecord
|
482
482
|
rubygems_mfa_required: 'true'
|
483
483
|
post_install_message:
|
484
484
|
rdoc_options:
|