activerecord 8.0.0.beta1 → 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 +102 -2
- data/lib/active_record/association_relation.rb +1 -0
- data/lib/active_record/associations/association.rb +9 -5
- data/lib/active_record/associations/has_many_through_association.rb +7 -1
- data/lib/active_record/associations.rb +28 -16
- data/lib/active_record/attribute_methods/primary_key.rb +2 -7
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +2 -12
- data/lib/active_record/callbacks.rb +1 -1
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +26 -8
- data/lib/active_record/connection_adapters/abstract/schema_creation.rb +4 -5
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +6 -1
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +8 -2
- data/lib/active_record/connection_adapters/abstract_adapter.rb +0 -1
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +8 -4
- data/lib/active_record/connection_adapters/postgresql/oid/array.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +2 -4
- data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +1 -10
- data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +6 -12
- data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +2 -1
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +11 -10
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +12 -10
- data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +1 -1
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +0 -2
- data/lib/active_record/connection_adapters.rb +0 -56
- data/lib/active_record/core.rb +43 -14
- 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 +9 -22
- data/lib/active_record/fixtures.rb +0 -1
- data/lib/active_record/gem_version.rb +1 -1
- data/lib/active_record/locking/optimistic.rb +1 -1
- data/lib/active_record/log_subscriber.rb +5 -11
- data/lib/active_record/marshalling.rb +4 -1
- data/lib/active_record/migration/command_recorder.rb +5 -5
- data/lib/active_record/migration.rb +0 -5
- data/lib/active_record/model_schema.rb +2 -3
- data/lib/active_record/query_cache.rb +0 -4
- data/lib/active_record/query_logs.rb +5 -11
- data/lib/active_record/querying.rb +2 -2
- data/lib/active_record/railtie.rb +2 -25
- data/lib/active_record/railties/databases.rake +2 -17
- data/lib/active_record/reflection.rb +14 -19
- data/lib/active_record/relation/calculations.rb +24 -28
- data/lib/active_record/relation/predicate_builder.rb +8 -0
- data/lib/active_record/relation/query_methods.rb +76 -38
- data/lib/active_record/relation.rb +8 -1
- data/lib/active_record/result.rb +10 -9
- data/lib/active_record/table_metadata.rb +1 -3
- data/lib/active_record/tasks/database_tasks.rb +26 -34
- data/lib/active_record/testing/query_assertions.rb +2 -2
- data/lib/active_record.rb +0 -45
- data/lib/arel/table.rb +3 -7
- data/lib/arel/visitors/sqlite.rb +25 -0
- metadata +9 -10
- data/lib/active_record/relation/record_fetch_warning.rb +0 -52
@@ -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)
|
@@ -356,15 +360,13 @@ module ActiveRecord
|
|
356
360
|
|
357
361
|
# = Active Record PostgreSQL Adapter Alter \Table
|
358
362
|
class AlterTable < ActiveRecord::ConnectionAdapters::AlterTable
|
359
|
-
attr_reader :constraint_validations, :exclusion_constraint_adds, :
|
363
|
+
attr_reader :constraint_validations, :exclusion_constraint_adds, :unique_constraint_adds
|
360
364
|
|
361
365
|
def initialize(td)
|
362
366
|
super
|
363
367
|
@constraint_validations = []
|
364
368
|
@exclusion_constraint_adds = []
|
365
|
-
@exclusion_constraint_drops = []
|
366
369
|
@unique_constraint_adds = []
|
367
|
-
@unique_constraint_drops = []
|
368
370
|
end
|
369
371
|
|
370
372
|
def validate_constraint(name)
|
@@ -375,17 +377,9 @@ module ActiveRecord
|
|
375
377
|
@exclusion_constraint_adds << @td.new_exclusion_constraint_definition(expression, options)
|
376
378
|
end
|
377
379
|
|
378
|
-
def drop_exclusion_constraint(constraint_name)
|
379
|
-
@exclusion_constraint_drops << constraint_name
|
380
|
-
end
|
381
|
-
|
382
380
|
def add_unique_constraint(column_name, options)
|
383
381
|
@unique_constraint_adds << @td.new_unique_constraint_definition(column_name, options)
|
384
382
|
end
|
385
|
-
|
386
|
-
def drop_unique_constraint(unique_constraint_name)
|
387
|
-
@unique_constraint_drops << unique_constraint_name
|
388
|
-
end
|
389
383
|
end
|
390
384
|
end
|
391
385
|
end
|
@@ -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?
|
@@ -91,7 +92,7 @@ module ActiveRecord
|
|
91
92
|
spec = { type: schema_type(column).inspect }.merge!(spec)
|
92
93
|
end
|
93
94
|
|
94
|
-
spec[:enum_type] =
|
95
|
+
spec[:enum_type] = column.sql_type.inspect if column.enum?
|
95
96
|
|
96
97
|
spec
|
97
98
|
end
|
@@ -299,6 +299,8 @@ module ActiveRecord
|
|
299
299
|
|
300
300
|
# Returns the sequence name for a table's primary key or some other specified key.
|
301
301
|
def default_sequence_name(table_name, pk = "id") # :nodoc:
|
302
|
+
return nil if pk.is_a?(Array)
|
303
|
+
|
302
304
|
result = serial_sequence(table_name, pk)
|
303
305
|
return nil unless result
|
304
306
|
Utils.extract_schema_qualified_name(result).to_s
|
@@ -696,7 +698,7 @@ module ActiveRecord
|
|
696
698
|
scope = quoted_scope(table_name)
|
697
699
|
|
698
700
|
unique_info = internal_exec_query(<<~SQL, "SCHEMA", allow_retry: true, materialize_transactions: false)
|
699
|
-
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
|
700
702
|
FROM pg_constraint c
|
701
703
|
JOIN pg_class t ON c.conrelid = t.oid
|
702
704
|
JOIN pg_namespace n ON n.oid = c.connamespace
|
@@ -709,10 +711,12 @@ module ActiveRecord
|
|
709
711
|
conkey = row["conkey"].delete("{}").split(",").map(&:to_i)
|
710
712
|
columns = column_names_from_column_numbers(row["conrelid"], conkey)
|
711
713
|
|
714
|
+
nulls_not_distinct = row["constraintdef"].start_with?("UNIQUE NULLS NOT DISTINCT")
|
712
715
|
deferrable = extract_constraint_deferrable(row["condeferrable"], row["condeferred"])
|
713
716
|
|
714
717
|
options = {
|
715
718
|
name: row["conname"],
|
719
|
+
nulls_not_distinct: nulls_not_distinct,
|
716
720
|
deferrable: deferrable
|
717
721
|
}
|
718
722
|
|
@@ -764,15 +768,12 @@ module ActiveRecord
|
|
764
768
|
def remove_exclusion_constraint(table_name, expression = nil, **options)
|
765
769
|
excl_name_to_delete = exclusion_constraint_for!(table_name, expression: expression, **options).name
|
766
770
|
|
767
|
-
|
768
|
-
at.drop_exclusion_constraint(excl_name_to_delete)
|
769
|
-
|
770
|
-
execute schema_creation.accept(at)
|
771
|
+
remove_constraint(table_name, excl_name_to_delete)
|
771
772
|
end
|
772
773
|
|
773
774
|
# Adds a new unique constraint to the table.
|
774
775
|
#
|
775
|
-
# 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
|
776
777
|
#
|
777
778
|
# generates:
|
778
779
|
#
|
@@ -789,6 +790,9 @@ module ActiveRecord
|
|
789
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+.
|
790
791
|
# [<tt>:using_index</tt>]
|
791
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.
|
792
796
|
def add_unique_constraint(table_name, column_name = nil, **options)
|
793
797
|
options = unique_constraint_options(table_name, column_name, options)
|
794
798
|
at = create_alter_table(table_name)
|
@@ -819,10 +823,7 @@ module ActiveRecord
|
|
819
823
|
def remove_unique_constraint(table_name, column_name = nil, **options)
|
820
824
|
unique_name_to_delete = unique_constraint_for!(table_name, column: column_name, **options).name
|
821
825
|
|
822
|
-
|
823
|
-
at.drop_unique_constraint(unique_name_to_delete)
|
824
|
-
|
825
|
-
execute schema_creation.accept(at)
|
826
|
+
remove_constraint(table_name, unique_name_to_delete)
|
826
827
|
end
|
827
828
|
|
828
829
|
# Maps logical Rails types to PostgreSQL-specific data types.
|
@@ -575,10 +575,12 @@ module ActiveRecord
|
|
575
575
|
end
|
576
576
|
|
577
577
|
# Rename an existing enum type to something else.
|
578
|
-
def rename_enum(name, **options)
|
579
|
-
|
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
|
-
exec_query("ALTER TYPE #{quote_table_name(name)} RENAME TO #{
|
583
|
+
exec_query("ALTER TYPE #{quote_table_name(name)} RENAME TO #{quote_table_name(new_name)}").tap { reload_type_map }
|
582
584
|
end
|
583
585
|
|
584
586
|
# Add enum value to an existing enum type.
|
@@ -586,14 +588,14 @@ module ActiveRecord
|
|
586
588
|
before, after = options.values_at(:before, :after)
|
587
589
|
sql = +"ALTER TYPE #{quote_table_name(type_name)} ADD VALUE"
|
588
590
|
sql << " IF NOT EXISTS" if options[:if_not_exists]
|
589
|
-
sql << "
|
591
|
+
sql << " #{quote(value)}"
|
590
592
|
|
591
593
|
if before && after
|
592
594
|
raise ArgumentError, "Cannot have both :before and :after at the same time"
|
593
595
|
elsif before
|
594
|
-
sql << " BEFORE
|
596
|
+
sql << " BEFORE #{quote(before)}"
|
595
597
|
elsif after
|
596
|
-
sql << " AFTER
|
598
|
+
sql << " AFTER #{quote(after)}"
|
597
599
|
end
|
598
600
|
|
599
601
|
execute(sql).tap { reload_type_map }
|
@@ -608,7 +610,7 @@ module ActiveRecord
|
|
608
610
|
from = options.fetch(:from) { raise ArgumentError, ":from is required" }
|
609
611
|
to = options.fetch(:to) { raise ArgumentError, ":to is required" }
|
610
612
|
|
611
|
-
execute("ALTER TYPE #{quote_table_name(type_name)} RENAME VALUE
|
613
|
+
execute("ALTER TYPE #{quote_table_name(type_name)} RENAME VALUE #{quote(from)} TO #{quote(to)}").tap {
|
612
614
|
reload_type_map
|
613
615
|
}
|
614
616
|
end
|
@@ -671,8 +673,8 @@ module ActiveRecord
|
|
671
673
|
m.register_type "int4", Type::Integer.new(limit: 4)
|
672
674
|
m.register_type "int8", Type::Integer.new(limit: 8)
|
673
675
|
m.register_type "oid", OID::Oid.new
|
674
|
-
m.register_type "float4", Type::Float.new
|
675
|
-
m.
|
676
|
+
m.register_type "float4", Type::Float.new(limit: 24)
|
677
|
+
m.register_type "float8", Type::Float.new
|
676
678
|
m.register_type "text", Type::Text.new
|
677
679
|
register_class_with_limit m, "varchar", Type::String
|
678
680
|
m.alias_type "char", "varchar"
|
@@ -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
|
@@ -68,7 +68,7 @@ module ActiveRecord
|
|
68
68
|
raise StandardError, "You need to enable the shared-cache mode in SQLite mode before attempting to change the transaction isolation level" unless shared_cache?
|
69
69
|
end
|
70
70
|
|
71
|
-
internal_execute("BEGIN #{mode} TRANSACTION", allow_retry: true, materialize_transactions: false)
|
71
|
+
internal_execute("BEGIN #{mode} TRANSACTION", "TRANSACTION", allow_retry: true, materialize_transactions: false)
|
72
72
|
if isolation
|
73
73
|
@previous_read_uncommitted = query_value("PRAGMA read_uncommitted")
|
74
74
|
internal_execute("PRAGMA read_uncommitted=ON", "TRANSACTION", allow_retry: true, materialize_transactions: false)
|
@@ -31,62 +31,6 @@ module ActiveRecord
|
|
31
31
|
class_name, path_to_adapter = @adapters[adapter_name.to_s]
|
32
32
|
|
33
33
|
unless class_name
|
34
|
-
# To provide better error messages for adapters expecting the pre-7.2 adapter registration API, we attempt
|
35
|
-
# to load the adapter file from the old location which was required by convention, and then raise an error
|
36
|
-
# describing how to upgrade the adapter to the new API.
|
37
|
-
legacy_adapter_path = "active_record/connection_adapters/#{adapter_name}_adapter"
|
38
|
-
legacy_adapter_connection_method_name = "#{adapter_name}_connection".to_sym
|
39
|
-
|
40
|
-
begin
|
41
|
-
require legacy_adapter_path
|
42
|
-
# If we reach here it means we found the found a file that may be the legacy adapter and should raise.
|
43
|
-
if ActiveRecord::ConnectionHandling.method_defined?(legacy_adapter_connection_method_name)
|
44
|
-
# If we find the connection method then we care certain it is a legacy adapter.
|
45
|
-
deprecation_message = <<~MSG.squish
|
46
|
-
Database configuration specifies '#{adapter_name}' adapter but that adapter has not been registered.
|
47
|
-
Rails 7.2 has changed the way Active Record database adapters are loaded. The adapter needs to be
|
48
|
-
updated to register itself rather than being loaded by convention.
|
49
|
-
Ensure that the adapter in the Gemfile is at the latest version. If it is, then the adapter may need to
|
50
|
-
be modified.
|
51
|
-
See:
|
52
|
-
https://api.rubyonrails.org/classes/ActiveRecord/ConnectionAdapters.html#method-c-register
|
53
|
-
MSG
|
54
|
-
|
55
|
-
exception_message = <<~MSG.squish
|
56
|
-
Database configuration specifies '#{adapter_name}' adapter but that adapter has not been registered.
|
57
|
-
Ensure that the adapter in the Gemfile is at the latest version. If it is, then the adapter may need to
|
58
|
-
be modified.
|
59
|
-
MSG
|
60
|
-
else
|
61
|
-
# If we do not find the connection method we are much less certain it is a legacy adapter. Even though the
|
62
|
-
# file exists in the location defined by convenntion, it does not necessarily mean that file is supposed
|
63
|
-
# to define the adapter the legacy way. So raise an error that explains both possibilities.
|
64
|
-
deprecation_message = <<~MSG.squish
|
65
|
-
Database configuration specifies nonexistent '#{adapter_name}' adapter.
|
66
|
-
Available adapters are: #{@adapters.keys.sort.join(", ")}.
|
67
|
-
Ensure that the adapter is spelled correctly in config/database.yml and that you've added the necessary
|
68
|
-
adapter gem to your Gemfile if it's not in the list of available adapters.
|
69
|
-
Rails 7.2 has changed the way Active Record database adapters are loaded. Ensure that the adapter in
|
70
|
-
the Gemfile is at the latest version. If it is up to date, the adapter may need to be modified.
|
71
|
-
See:
|
72
|
-
https://api.rubyonrails.org/classes/ActiveRecord/ConnectionAdapters.html#method-c-register
|
73
|
-
MSG
|
74
|
-
|
75
|
-
exception_message = <<~MSG.squish
|
76
|
-
Database configuration specifies nonexistent '#{adapter_name}' adapter.
|
77
|
-
Available adapters are: #{@adapters.keys.sort.join(", ")}.
|
78
|
-
Ensure that the adapter is spelled correctly in config/database.yml and that you've added the necessary
|
79
|
-
adapter gem to your Gemfile and that it is at its latest version. If it is up to date, the adapter may
|
80
|
-
need to be modified.
|
81
|
-
MSG
|
82
|
-
end
|
83
|
-
|
84
|
-
ActiveRecord.deprecator.warn(deprecation_message)
|
85
|
-
raise AdapterNotFound, exception_message
|
86
|
-
rescue LoadError => error
|
87
|
-
# The adapter was not found in the legacy location so fall through to the error handling for a missing adapter.
|
88
|
-
end
|
89
|
-
|
90
34
|
raise AdapterNotFound, <<~MSG.squish
|
91
35
|
Database configuration specifies nonexistent '#{adapter_name}' adapter.
|
92
36
|
Available adapters are: #{@adapters.keys.sort.join(", ")}.
|
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:
|
@@ -370,7 +382,7 @@ module ActiveRecord
|
|
370
382
|
end
|
371
383
|
|
372
384
|
def predicate_builder # :nodoc:
|
373
|
-
@predicate_builder ||= PredicateBuilder.new(
|
385
|
+
@predicate_builder ||= PredicateBuilder.new(TableMetadata.new(self, arel_table))
|
374
386
|
end
|
375
387
|
|
376
388
|
def type_caster # :nodoc:
|
@@ -415,10 +427,6 @@ module ActiveRecord
|
|
415
427
|
end
|
416
428
|
end
|
417
429
|
|
418
|
-
def table_metadata
|
419
|
-
TableMetadata.new(self, arel_table)
|
420
|
-
end
|
421
|
-
|
422
430
|
def cached_find_by(keys, values)
|
423
431
|
with_connection do |connection|
|
424
432
|
statement = cached_find_by_statement(connection, keys) { |params|
|
@@ -529,12 +537,7 @@ module ActiveRecord
|
|
529
537
|
|
530
538
|
##
|
531
539
|
def initialize_dup(other) # :nodoc:
|
532
|
-
@attributes =
|
533
|
-
if self.class.composite_primary_key?
|
534
|
-
@primary_key.each { |key| @attributes.reset(key) }
|
535
|
-
else
|
536
|
-
@attributes.reset(@primary_key)
|
537
|
-
end
|
540
|
+
@attributes = init_attributes(other)
|
538
541
|
|
539
542
|
_run_initialize_callbacks
|
540
543
|
|
@@ -546,6 +549,18 @@ module ActiveRecord
|
|
546
549
|
super
|
547
550
|
end
|
548
551
|
|
552
|
+
def init_attributes(_) # :nodoc:
|
553
|
+
attrs = @attributes.deep_dup
|
554
|
+
|
555
|
+
if self.class.composite_primary_key?
|
556
|
+
@primary_key.each { |key| attrs.reset(key) }
|
557
|
+
else
|
558
|
+
attrs.reset(@primary_key)
|
559
|
+
end
|
560
|
+
|
561
|
+
attrs
|
562
|
+
end
|
563
|
+
|
549
564
|
# Populate +coder+ with attributes about this record that should be
|
550
565
|
# serialized. The structure of +coder+ defined in this method is
|
551
566
|
# guaranteed to match the structure of +coder+ passed to the #init_with
|
@@ -725,12 +740,26 @@ module ActiveRecord
|
|
725
740
|
self.class.connection_handler
|
726
741
|
end
|
727
742
|
|
728
|
-
# 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!">"
|
729
753
|
def inspect
|
730
754
|
inspect_with_attributes(attributes_for_inspect)
|
731
755
|
end
|
732
756
|
|
733
|
-
# 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
|
+
#
|
734
763
|
def full_inspect
|
735
764
|
inspect_with_attributes(all_attributes_for_inspect)
|
736
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,34 +213,16 @@ module ActiveRecord
|
|
213
213
|
attr_reader :name, :mapping
|
214
214
|
end
|
215
215
|
|
216
|
-
def enum(name
|
217
|
-
|
218
|
-
|
219
|
-
return _enum(name, values, **options)
|
220
|
-
end
|
221
|
-
|
222
|
-
definitions = options.slice!(:_prefix, :_suffix, :_scopes, :_default, :_instance_methods)
|
223
|
-
options.transform_keys! { |key| :"#{key[1..-1]}" }
|
224
|
-
|
225
|
-
definitions.each { |name, values| _enum(name, values, **options) }
|
226
|
-
|
227
|
-
ActiveRecord.deprecator.warn(<<~MSG)
|
228
|
-
Defining enums with keyword arguments is deprecated and will be removed
|
229
|
-
in Rails 8.0. Positional arguments should be used instead:
|
230
|
-
|
231
|
-
#{definitions.map { |name, values| "enum :#{name}, #{values}" }.join("\n")}
|
232
|
-
MSG
|
216
|
+
def enum(name, values = nil, **options)
|
217
|
+
values, options = options, {} unless values
|
218
|
+
_enum(name, values, **options)
|
233
219
|
end
|
234
220
|
|
235
221
|
private
|
236
|
-
def inherited(base)
|
237
|
-
base.defined_enums = defined_enums.deep_dup
|
238
|
-
super
|
239
|
-
end
|
240
|
-
|
241
222
|
def _enum(name, values, prefix: nil, suffix: nil, scopes: true, instance_methods: true, validate: false, **options)
|
242
223
|
assert_valid_enum_definition_values(values)
|
243
224
|
assert_valid_enum_options(options)
|
225
|
+
|
244
226
|
# statuses = { }
|
245
227
|
enum_values = ActiveSupport::HashWithIndifferentAccess.new
|
246
228
|
name = name.to_s
|
@@ -304,6 +286,11 @@ module ActiveRecord
|
|
304
286
|
enum_values.freeze
|
305
287
|
end
|
306
288
|
|
289
|
+
def inherited(base)
|
290
|
+
base.defined_enums = defined_enums.deep_dup
|
291
|
+
super
|
292
|
+
end
|
293
|
+
|
307
294
|
class EnumMethods < Module # :nodoc:
|
308
295
|
def initialize(klass)
|
309
296
|
@klass = klass
|
@@ -9,7 +9,7 @@ module ActiveRecord
|
|
9
9
|
# it was opened, an ActiveRecord::StaleObjectError exception is thrown if that has occurred
|
10
10
|
# and the update is ignored.
|
11
11
|
#
|
12
|
-
# Check out
|
12
|
+
# Check out ActiveRecord::Locking::Pessimistic for an alternative.
|
13
13
|
#
|
14
14
|
# == Usage
|
15
15
|
#
|
@@ -126,18 +126,12 @@ module ActiveRecord
|
|
126
126
|
end
|
127
127
|
end
|
128
128
|
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
return frame if frame
|
134
|
-
end
|
135
|
-
nil
|
136
|
-
end
|
137
|
-
else
|
138
|
-
def query_source_location
|
139
|
-
backtrace_cleaner.clean(caller(1).lazy).first
|
129
|
+
def query_source_location
|
130
|
+
Thread.each_caller_location do |location|
|
131
|
+
frame = backtrace_cleaner.clean_frame(location)
|
132
|
+
return frame if frame
|
140
133
|
end
|
134
|
+
nil
|
141
135
|
end
|
142
136
|
|
143
137
|
def filter(name, value)
|
@@ -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?
|
@@ -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)
|
@@ -1,6 +1,5 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require "set"
|
4
3
|
require "active_support/core_ext/array/access"
|
5
4
|
require "active_support/core_ext/enumerable"
|
6
5
|
require "active_support/core_ext/module/attribute_accessors"
|
@@ -679,10 +678,6 @@ module ActiveRecord
|
|
679
678
|
paths = all_configs.flat_map { |config| config.migrations_paths || Migrator.migrations_paths }.uniq
|
680
679
|
@file_watcher.new([], paths.index_with(["rb"]), &block)
|
681
680
|
end
|
682
|
-
|
683
|
-
def connection
|
684
|
-
ActiveRecord::Tasks::DatabaseTasks.migration_connection
|
685
|
-
end
|
686
681
|
end
|
687
682
|
|
688
683
|
class << self
|
@@ -276,15 +276,14 @@ module ActiveRecord
|
|
276
276
|
end
|
277
277
|
|
278
278
|
@table_name = value
|
279
|
-
@quoted_table_name = nil
|
280
279
|
@arel_table = nil
|
281
280
|
@sequence_name = nil unless @explicit_sequence_name
|
282
281
|
@predicate_builder = nil
|
283
282
|
end
|
284
283
|
|
285
|
-
# Returns a quoted version of the table name
|
284
|
+
# Returns a quoted version of the table name.
|
286
285
|
def quoted_table_name
|
287
|
-
|
286
|
+
adapter_class.quote_table_name(table_name)
|
288
287
|
end
|
289
288
|
|
290
289
|
# Computes the table name, (re)sets it internally, and returns it.
|
@@ -43,10 +43,6 @@ module ActiveRecord
|
|
43
43
|
pool.disable_query_cache!
|
44
44
|
pool.clear_query_cache
|
45
45
|
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
46
|
end
|
51
47
|
|
52
48
|
def self.install_executor_hooks(executor = ActiveSupport::Executor)
|
@@ -152,18 +152,12 @@ module ActiveRecord
|
|
152
152
|
self.cached_comment = nil
|
153
153
|
end
|
154
154
|
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
return frame if frame
|
160
|
-
end
|
161
|
-
nil
|
162
|
-
end
|
163
|
-
else
|
164
|
-
def query_source_location # :nodoc:
|
165
|
-
LogSubscriber.backtrace_cleaner.clean(caller_locations(1).each).first
|
155
|
+
def query_source_location # :nodoc:
|
156
|
+
Thread.each_caller_location do |location|
|
157
|
+
frame = LogSubscriber.backtrace_cleaner.clean_frame(location)
|
158
|
+
return frame if frame
|
166
159
|
end
|
160
|
+
nil
|
167
161
|
end
|
168
162
|
|
169
163
|
ActiveSupport::ExecutionContext.after_change { ActiveRecord::QueryLogs.clear_cache }
|
@@ -86,10 +86,10 @@ module ActiveRecord
|
|
86
86
|
|
87
87
|
message_bus.instrument("instantiation.active_record", payload) do
|
88
88
|
if result_set.includes_column?(inheritance_column)
|
89
|
-
result_set.map { |record| instantiate(record, column_types, &block) }
|
89
|
+
result_set.indexed_rows.map { |record| instantiate(record, column_types, &block) }
|
90
90
|
else
|
91
91
|
# Instantiate a homogeneous set
|
92
|
-
result_set.map { |record| instantiate_instance_of(self, record, column_types, &block) }
|
92
|
+
result_set.indexed_rows.map { |record| instantiate_instance_of(self, record, column_types, &block) }
|
93
93
|
end
|
94
94
|
end
|
95
95
|
end
|