activerecord 8.0.0.beta1 → 8.0.0.rc2

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.
Files changed (56) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +102 -2
  3. data/lib/active_record/association_relation.rb +1 -0
  4. data/lib/active_record/associations/association.rb +9 -5
  5. data/lib/active_record/associations/has_many_through_association.rb +7 -1
  6. data/lib/active_record/associations.rb +28 -16
  7. data/lib/active_record/attribute_methods/primary_key.rb +2 -7
  8. data/lib/active_record/attribute_methods/time_zone_conversion.rb +2 -12
  9. data/lib/active_record/callbacks.rb +1 -1
  10. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +26 -8
  11. data/lib/active_record/connection_adapters/abstract/schema_creation.rb +4 -5
  12. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +6 -1
  13. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +8 -2
  14. data/lib/active_record/connection_adapters/abstract_adapter.rb +0 -1
  15. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +8 -4
  16. data/lib/active_record/connection_adapters/postgresql/oid/array.rb +1 -1
  17. data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +2 -4
  18. data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +1 -10
  19. data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +6 -12
  20. data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +2 -1
  21. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +11 -10
  22. data/lib/active_record/connection_adapters/postgresql_adapter.rb +12 -10
  23. data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +1 -1
  24. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +0 -2
  25. data/lib/active_record/connection_adapters.rb +0 -56
  26. data/lib/active_record/core.rb +43 -14
  27. data/lib/active_record/database_configurations/database_config.rb +4 -0
  28. data/lib/active_record/database_configurations/hash_config.rb +8 -0
  29. data/lib/active_record/enum.rb +9 -22
  30. data/lib/active_record/fixtures.rb +0 -1
  31. data/lib/active_record/gem_version.rb +1 -1
  32. data/lib/active_record/locking/optimistic.rb +1 -1
  33. data/lib/active_record/log_subscriber.rb +5 -11
  34. data/lib/active_record/marshalling.rb +4 -1
  35. data/lib/active_record/migration/command_recorder.rb +5 -5
  36. data/lib/active_record/migration.rb +0 -5
  37. data/lib/active_record/model_schema.rb +2 -3
  38. data/lib/active_record/query_cache.rb +0 -4
  39. data/lib/active_record/query_logs.rb +5 -11
  40. data/lib/active_record/querying.rb +2 -2
  41. data/lib/active_record/railtie.rb +2 -25
  42. data/lib/active_record/railties/databases.rake +2 -17
  43. data/lib/active_record/reflection.rb +14 -19
  44. data/lib/active_record/relation/calculations.rb +24 -28
  45. data/lib/active_record/relation/predicate_builder.rb +8 -0
  46. data/lib/active_record/relation/query_methods.rb +76 -38
  47. data/lib/active_record/relation.rb +8 -1
  48. data/lib/active_record/result.rb +10 -9
  49. data/lib/active_record/table_metadata.rb +1 -3
  50. data/lib/active_record/tasks/database_tasks.rb +26 -34
  51. data/lib/active_record/testing/query_assertions.rb +2 -2
  52. data/lib/active_record.rb +0 -45
  53. data/lib/arel/table.rb +3 -7
  54. data/lib/arel/visitors/sqlite.rb +25 -0
  55. metadata +9 -10
  56. 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, :exclusion_constraint_drops, :unique_constraint_adds, :unique_constraint_drops
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] = "\"#{column.sql_type}\"" if column.enum?
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
- at = create_alter_table(table_name)
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
- at = create_alter_table(table_name)
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
- to = options.fetch(:to) { raise ArgumentError, ":to is required" }
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 #{to}").tap { reload_type_map }
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 << " '#{value}'"
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 '#{before}'"
596
+ sql << " BEFORE #{quote(before)}"
595
597
  elsif after
596
- sql << " AFTER '#{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 '#{from}' TO '#{to}'").tap {
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.alias_type "float8", "float4"
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)
@@ -725,8 +725,6 @@ module ActiveRecord
725
725
  end
726
726
 
727
727
  basic_structure.map do |column|
728
- column = column.to_h
729
-
730
728
  column_name = column["name"]
731
729
 
732
730
  if collation_hash.has_key? column_name
@@ -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(", ")}.
@@ -103,7 +103,19 @@ module ActiveRecord
103
103
 
104
104
  class_attribute :shard_selector, instance_accessor: false, default: nil
105
105
 
106
- # Specifies the attributes that will be included in the output of the #inspect method
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(table_metadata)
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 = @attributes.deep_dup
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 specified by <tt>.attributes_for_inspect</tt> as a nicely formatted string.
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 the full contents of the record as a nicely formatted string.
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
@@ -99,6 +99,10 @@ module ActiveRecord
99
99
  def use_metadata_table?
100
100
  raise NotImplementedError
101
101
  end
102
+
103
+ def seeds?
104
+ raise NotImplementedError
105
+ end
102
106
  end
103
107
  end
104
108
  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
  #
@@ -213,34 +213,16 @@ module ActiveRecord
213
213
  attr_reader :name, :mapping
214
214
  end
215
215
 
216
- def enum(name = nil, values = nil, **options)
217
- if name
218
- values, options = options, {} unless values
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
@@ -2,7 +2,6 @@
2
2
 
3
3
  require "erb"
4
4
  require "yaml"
5
- require "set"
6
5
  require "active_support/dependencies"
7
6
  require "active_support/core_ext/digest/uuid"
8
7
  require "active_record/test_fixtures"
@@ -10,7 +10,7 @@ module ActiveRecord
10
10
  MAJOR = 8
11
11
  MINOR = 0
12
12
  TINY = 0
13
- PRE = "beta1"
13
+ PRE = "rc2"
14
14
 
15
15
  STRING = [MAJOR, MINOR, TINY, PRE].compact.join(".")
16
16
  end
@@ -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 +ActiveRecord::Locking::Pessimistic+ for an alternative.
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
- if Thread.respond_to?(:each_caller_location)
130
- def query_source_location
131
- Thread.each_caller_location do |location|
132
- frame = backtrace_cleaner.clean_frame(location)
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) && association(reflection.name).loaded?
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 (must supply a +:to+ option)
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, options = args
367
+ name, new_name, = args
368
368
 
369
- unless options.is_a?(Hash) && options.has_key?(:to)
370
- raise ActiveRecord::IrreversibleMigration, "rename_enum is only reversible if given a :to option."
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, [options[:to], to: name]]
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, used to construct SQL statements.
284
+ # Returns a quoted version of the table name.
286
285
  def quoted_table_name
287
- @quoted_table_name ||= adapter_class.quote_table_name(table_name)
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
- if Thread.respond_to?(:each_caller_location)
156
- def query_source_location # :nodoc:
157
- Thread.each_caller_location do |location|
158
- frame = LogSubscriber.backtrace_cleaner.clean_frame(location.path)
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