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.
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