activerecord 7.2.1.1 → 8.0.0.rc1

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 (123) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +220 -756
  3. data/README.rdoc +1 -1
  4. data/lib/active_record/associations/association.rb +25 -5
  5. data/lib/active_record/associations/builder/association.rb +7 -6
  6. data/lib/active_record/associations/collection_association.rb +10 -8
  7. data/lib/active_record/associations/disable_joins_association_scope.rb +1 -1
  8. data/lib/active_record/associations/has_many_through_association.rb +10 -3
  9. data/lib/active_record/associations/join_dependency/join_association.rb +3 -2
  10. data/lib/active_record/associations/join_dependency.rb +4 -4
  11. data/lib/active_record/associations/preloader/association.rb +2 -2
  12. data/lib/active_record/associations/singular_association.rb +8 -3
  13. data/lib/active_record/associations.rb +34 -4
  14. data/lib/active_record/asynchronous_queries_tracker.rb +28 -24
  15. data/lib/active_record/attribute_assignment.rb +9 -1
  16. data/lib/active_record/attribute_methods/primary_key.rb +2 -7
  17. data/lib/active_record/attribute_methods/time_zone_conversion.rb +6 -12
  18. data/lib/active_record/attributes.rb +1 -2
  19. data/lib/active_record/autosave_association.rb +69 -27
  20. data/lib/active_record/callbacks.rb +1 -1
  21. data/lib/active_record/connection_adapters/abstract/connection_handler.rb +16 -10
  22. data/lib/active_record/connection_adapters/abstract/connection_pool/queue.rb +0 -1
  23. data/lib/active_record/connection_adapters/abstract/connection_pool/reaper.rb +0 -1
  24. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +26 -9
  25. data/lib/active_record/connection_adapters/abstract/database_statements.rb +90 -43
  26. data/lib/active_record/connection_adapters/abstract/query_cache.rb +12 -4
  27. data/lib/active_record/connection_adapters/abstract/quoting.rb +1 -1
  28. data/lib/active_record/connection_adapters/abstract/schema_creation.rb +4 -5
  29. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +7 -2
  30. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +34 -7
  31. data/lib/active_record/connection_adapters/abstract/transaction.rb +15 -5
  32. data/lib/active_record/connection_adapters/abstract_adapter.rb +24 -26
  33. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +28 -42
  34. data/lib/active_record/connection_adapters/mysql/quoting.rb +0 -8
  35. data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +2 -8
  36. data/lib/active_record/connection_adapters/mysql/schema_statements.rb +43 -45
  37. data/lib/active_record/connection_adapters/mysql2/database_statements.rb +42 -98
  38. data/lib/active_record/connection_adapters/mysql2_adapter.rb +1 -8
  39. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +64 -42
  40. data/lib/active_record/connection_adapters/postgresql/oid/array.rb +1 -1
  41. data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +1 -1
  42. data/lib/active_record/connection_adapters/postgresql/oid/point.rb +10 -0
  43. data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +2 -4
  44. data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +0 -11
  45. data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +1 -11
  46. data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +1 -1
  47. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +54 -14
  48. data/lib/active_record/connection_adapters/postgresql_adapter.rb +45 -97
  49. data/lib/active_record/connection_adapters/schema_cache.rb +1 -3
  50. data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +76 -100
  51. data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +0 -6
  52. data/lib/active_record/connection_adapters/sqlite3/schema_dumper.rb +13 -0
  53. data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +8 -1
  54. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +53 -12
  55. data/lib/active_record/connection_adapters/trilogy/database_statements.rb +37 -67
  56. data/lib/active_record/connection_adapters/trilogy_adapter.rb +0 -17
  57. data/lib/active_record/connection_adapters.rb +0 -56
  58. data/lib/active_record/connection_handling.rb +22 -0
  59. data/lib/active_record/core.rb +28 -18
  60. data/lib/active_record/database_configurations/connection_url_resolver.rb +1 -1
  61. data/lib/active_record/encryption/config.rb +3 -1
  62. data/lib/active_record/encryption/encryptable_record.rb +4 -4
  63. data/lib/active_record/encryption/encrypted_attribute_type.rb +10 -1
  64. data/lib/active_record/encryption/encryptor.rb +15 -8
  65. data/lib/active_record/encryption/extended_deterministic_queries.rb +4 -2
  66. data/lib/active_record/encryption/key_provider.rb +1 -1
  67. data/lib/active_record/encryption/scheme.rb +8 -1
  68. data/lib/active_record/encryption.rb +2 -0
  69. data/lib/active_record/enum.rb +54 -75
  70. data/lib/active_record/errors.rb +13 -5
  71. data/lib/active_record/fixtures.rb +0 -2
  72. data/lib/active_record/future_result.rb +14 -10
  73. data/lib/active_record/gem_version.rb +4 -4
  74. data/lib/active_record/insert_all.rb +1 -1
  75. data/lib/active_record/locking/optimistic.rb +1 -1
  76. data/lib/active_record/log_subscriber.rb +5 -11
  77. data/lib/active_record/marshalling.rb +4 -1
  78. data/lib/active_record/migration/command_recorder.rb +22 -5
  79. data/lib/active_record/migration/compatibility.rb +5 -2
  80. data/lib/active_record/migration.rb +35 -38
  81. data/lib/active_record/model_schema.rb +4 -6
  82. data/lib/active_record/nested_attributes.rb +11 -2
  83. data/lib/active_record/persistence.rb +128 -130
  84. data/lib/active_record/query_cache.rb +0 -4
  85. data/lib/active_record/query_logs.rb +102 -50
  86. data/lib/active_record/query_logs_formatter.rb +17 -28
  87. data/lib/active_record/querying.rb +8 -8
  88. data/lib/active_record/railtie.rb +9 -38
  89. data/lib/active_record/railties/databases.rake +1 -1
  90. data/lib/active_record/reflection.rb +23 -23
  91. data/lib/active_record/relation/batches/batch_enumerator.rb +4 -3
  92. data/lib/active_record/relation/batches.rb +132 -72
  93. data/lib/active_record/relation/calculations.rb +41 -40
  94. data/lib/active_record/relation/delegation.rb +25 -14
  95. data/lib/active_record/relation/finder_methods.rb +18 -18
  96. data/lib/active_record/relation/merger.rb +8 -8
  97. data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +1 -1
  98. data/lib/active_record/relation/predicate_builder/relation_handler.rb +4 -3
  99. data/lib/active_record/relation/predicate_builder.rb +14 -1
  100. data/lib/active_record/relation/query_methods.rb +122 -71
  101. data/lib/active_record/relation/spawn_methods.rb +1 -1
  102. data/lib/active_record/relation.rb +79 -61
  103. data/lib/active_record/result.rb +66 -4
  104. data/lib/active_record/sanitization.rb +7 -6
  105. data/lib/active_record/schema_dumper.rb +5 -0
  106. data/lib/active_record/schema_migration.rb +2 -1
  107. data/lib/active_record/scoping/named.rb +5 -2
  108. data/lib/active_record/statement_cache.rb +12 -12
  109. data/lib/active_record/store.rb +7 -3
  110. data/lib/active_record/table_metadata.rb +1 -3
  111. data/lib/active_record/tasks/database_tasks.rb +40 -47
  112. data/lib/active_record/tasks/mysql_database_tasks.rb +0 -2
  113. data/lib/active_record/tasks/sqlite_database_tasks.rb +2 -2
  114. data/lib/active_record/test_fixtures.rb +12 -0
  115. data/lib/active_record/testing/query_assertions.rb +2 -2
  116. data/lib/active_record/token_for.rb +1 -1
  117. data/lib/active_record/validations/uniqueness.rb +9 -8
  118. data/lib/active_record.rb +15 -45
  119. data/lib/arel/collectors/bind.rb +1 -1
  120. data/lib/arel/table.rb +3 -7
  121. data/lib/arel/visitors/sqlite.rb +25 -0
  122. metadata +10 -11
  123. data/lib/active_record/relation/record_fetch_warning.rb +0 -52
@@ -12,7 +12,7 @@ module ActiveRecord
12
12
  @keys = Array(keys)
13
13
  end
14
14
 
15
- # Returns the first key in the list as the active key to perform encryptions
15
+ # Returns the last key in the list as the active key to perform encryptions
16
16
  #
17
17
  # When +ActiveRecord::Encryption.config.store_key_references+ is true, the key will include
18
18
  # a public tag referencing the key itself. That key will be stored in the public
@@ -11,7 +11,7 @@ module ActiveRecord
11
11
  attr_accessor :previous_schemes
12
12
 
13
13
  def initialize(key_provider: nil, key: nil, deterministic: nil, support_unencrypted_data: nil, downcase: nil, ignore_case: nil,
14
- previous_schemes: nil, **context_properties)
14
+ previous_schemes: nil, compress: true, compressor: nil, **context_properties)
15
15
  # Initializing all attributes to +nil+ as we want to allow a "not set" semantics so that we
16
16
  # can merge schemes without overriding values with defaults. See +#merge+
17
17
 
@@ -24,8 +24,13 @@ module ActiveRecord
24
24
  @previous_schemes_param = previous_schemes
25
25
  @previous_schemes = Array.wrap(previous_schemes)
26
26
  @context_properties = context_properties
27
+ @compress = compress
28
+ @compressor = compressor
27
29
 
28
30
  validate_config!
31
+
32
+ @context_properties[:encryptor] = Encryptor.new(compress: @compress) unless @compress
33
+ @context_properties[:encryptor] = Encryptor.new(compressor: compressor) if compressor
29
34
  end
30
35
 
31
36
  def ignore_case?
@@ -78,6 +83,8 @@ module ActiveRecord
78
83
  def validate_config!
79
84
  raise Errors::Configuration, "ignore_case: can only be used with deterministic encryption" if @ignore_case && !@deterministic
80
85
  raise Errors::Configuration, "key_provider: and key: can't be used simultaneously" if @key_provider_param && @key
86
+ raise Errors::Configuration, "compressor: can't be used with compress: false" if !@compress && @compressor
87
+ raise Errors::Configuration, "compressor: can't be used with encryptor" if @compressor && @context_properties[:encryptor]
81
88
  end
82
89
 
83
90
  def key_provider_from_key
@@ -53,4 +53,6 @@ module ActiveRecord
53
53
  Cipher.eager_load!
54
54
  end
55
55
  end
56
+
57
+ ActiveSupport.run_load_hooks :active_record_encryption, Encryption
56
58
  end
@@ -167,15 +167,6 @@ module ActiveRecord
167
167
  base.class_attribute(:defined_enums, instance_writer: false, default: {})
168
168
  end
169
169
 
170
- def load_schema! # :nodoc:
171
- defined_enums.each_key do |name|
172
- unless columns_hash.key?(resolve_attribute_name(name))
173
- raise "Unknown enum attribute '#{name}' for #{self.name}. Enums must be" \
174
- " backed by a database column."
175
- end
176
- end
177
- end
178
-
179
170
  class EnumType < Type::Value # :nodoc:
180
171
  delegate :type, to: :subtype
181
172
 
@@ -222,89 +213,77 @@ module ActiveRecord
222
213
  attr_reader :name, :mapping
223
214
  end
224
215
 
225
- def enum(name = nil, values = nil, **options)
226
- if name
227
- values, options = options, {} unless values
228
- return _enum(name, values, **options)
229
- end
216
+ def enum(name, values, prefix: nil, suffix: nil, scopes: true, instance_methods: true, validate: false, **options)
217
+ assert_valid_enum_definition_values(values)
218
+ assert_valid_enum_options(options)
230
219
 
231
- definitions = options.slice!(:_prefix, :_suffix, :_scopes, :_default, :_instance_methods)
232
- options.transform_keys! { |key| :"#{key[1..-1]}" }
220
+ # statuses = { }
221
+ enum_values = ActiveSupport::HashWithIndifferentAccess.new
222
+ name = name.to_s
233
223
 
234
- definitions.each { |name, values| _enum(name, values, **options) }
224
+ # def self.statuses() statuses end
225
+ detect_enum_conflict!(name, name.pluralize, true)
226
+ singleton_class.define_method(name.pluralize) { enum_values }
227
+ defined_enums[name] = enum_values
235
228
 
236
- ActiveRecord.deprecator.warn(<<~MSG)
237
- Defining enums with keyword arguments is deprecated and will be removed
238
- in Rails 8.0. Positional arguments should be used instead:
229
+ detect_enum_conflict!(name, name)
230
+ detect_enum_conflict!(name, "#{name}=")
239
231
 
240
- #{definitions.map { |name, values| "enum :#{name}, #{values}" }.join("\n")}
241
- MSG
242
- end
232
+ attribute(name, **options)
243
233
 
244
- private
245
- def inherited(base)
246
- base.defined_enums = defined_enums.deep_dup
247
- super
248
- end
249
-
250
- def _enum(name, values, prefix: nil, suffix: nil, scopes: true, instance_methods: true, validate: false, **options)
251
- assert_valid_enum_definition_values(values)
252
- assert_valid_enum_options(options)
253
- # statuses = { }
254
- enum_values = ActiveSupport::HashWithIndifferentAccess.new
255
- name = name.to_s
256
-
257
- # def self.statuses() statuses end
258
- detect_enum_conflict!(name, name.pluralize, true)
259
- singleton_class.define_method(name.pluralize) { enum_values }
260
- defined_enums[name] = enum_values
261
-
262
- detect_enum_conflict!(name, name)
263
- detect_enum_conflict!(name, "#{name}=")
234
+ decorate_attributes([name]) do |_name, subtype|
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
264
240
 
265
- attribute(name, **options)
241
+ subtype = subtype.subtype if EnumType === subtype
242
+ EnumType.new(name, enum_values, subtype, raise_on_invalid_values: !validate)
243
+ end
266
244
 
267
- decorate_attributes([name]) do |name, subtype|
268
- subtype = subtype.subtype if EnumType === subtype
269
- EnumType.new(name, enum_values, subtype, raise_on_invalid_values: !validate)
245
+ value_method_names = []
246
+ _enum_methods_module.module_eval do
247
+ prefix = if prefix
248
+ prefix == true ? "#{name}_" : "#{prefix}_"
270
249
  end
271
250
 
272
- value_method_names = []
273
- _enum_methods_module.module_eval do
274
- prefix = if prefix
275
- prefix == true ? "#{name}_" : "#{prefix}_"
276
- end
277
-
278
- suffix = if suffix
279
- suffix == true ? "_#{name}" : "_#{suffix}"
280
- end
251
+ suffix = if suffix
252
+ suffix == true ? "_#{name}" : "_#{suffix}"
253
+ end
281
254
 
282
- pairs = values.respond_to?(:each_pair) ? values.each_pair : values.each_with_index
283
- pairs.each do |label, value|
284
- enum_values[label] = value
285
- label = label.to_s
255
+ pairs = values.respond_to?(:each_pair) ? values.each_pair : values.each_with_index
256
+ pairs.each do |label, value|
257
+ enum_values[label] = value
258
+ label = label.to_s
286
259
 
287
- value_method_name = "#{prefix}#{label}#{suffix}"
288
- value_method_names << value_method_name
289
- define_enum_methods(name, value_method_name, value, scopes, instance_methods)
260
+ value_method_name = "#{prefix}#{label}#{suffix}"
261
+ value_method_names << value_method_name
262
+ define_enum_methods(name, value_method_name, value, scopes, instance_methods)
290
263
 
291
- method_friendly_label = label.gsub(/[\W&&[:ascii:]]+/, "_")
292
- value_method_alias = "#{prefix}#{method_friendly_label}#{suffix}"
264
+ method_friendly_label = label.gsub(/[\W&&[:ascii:]]+/, "_")
265
+ value_method_alias = "#{prefix}#{method_friendly_label}#{suffix}"
293
266
 
294
- if value_method_alias != value_method_name && !value_method_names.include?(value_method_alias)
295
- value_method_names << value_method_alias
296
- define_enum_methods(name, value_method_alias, value, scopes, instance_methods)
297
- end
267
+ if value_method_alias != value_method_name && !value_method_names.include?(value_method_alias)
268
+ value_method_names << value_method_alias
269
+ define_enum_methods(name, value_method_alias, value, scopes, instance_methods)
298
270
  end
299
271
  end
300
- detect_negative_enum_conditions!(value_method_names) if scopes
272
+ end
273
+ detect_negative_enum_conditions!(value_method_names) if scopes
301
274
 
302
- if validate
303
- validate = {} unless Hash === validate
304
- validates_inclusion_of name, in: enum_values.keys, **validate
305
- end
275
+ if validate
276
+ validate = {} unless Hash === validate
277
+ validates_inclusion_of name, in: enum_values.keys, **validate
278
+ end
279
+
280
+ enum_values.freeze
281
+ end
306
282
 
307
- enum_values.freeze
283
+ private
284
+ def inherited(base)
285
+ base.defined_enums = defined_enums.deep_dup
286
+ super
308
287
  end
309
288
 
310
289
  class EnumMethods < Module # :nodoc:
@@ -84,6 +84,19 @@ module ActiveRecord
84
84
  class ConnectionTimeoutError < ConnectionNotEstablished
85
85
  end
86
86
 
87
+ # Raised when a database connection pool is requested but
88
+ # has not been defined.
89
+ class ConnectionNotDefined < ConnectionNotEstablished
90
+ def initialize(message = nil, connection_name: nil, role: nil, shard: nil)
91
+ super(message)
92
+ @connection_name = connection_name
93
+ @role = role
94
+ @shard = shard
95
+ end
96
+
97
+ attr_reader :connection_name, :role, :shard
98
+ end
99
+
87
100
  # Raised when connection to the database could not been established because it was not
88
101
  # able to connect to the host or when the authorization failed.
89
102
  class DatabaseConnectionError < ConnectionNotEstablished
@@ -484,11 +497,6 @@ module ActiveRecord
484
497
  # relation.limit!(5) # => ActiveRecord::UnmodifiableRelation
485
498
  class UnmodifiableRelation < ActiveRecordError
486
499
  end
487
- deprecate_constant(
488
- :ImmutableRelation,
489
- "ActiveRecord::UnmodifiableRelation",
490
- deprecator: ActiveRecord.deprecator
491
- )
492
500
 
493
501
  # TransactionIsolationError will be raised under the following conditions:
494
502
  #
@@ -2,8 +2,6 @@
2
2
 
3
3
  require "erb"
4
4
  require "yaml"
5
- require "zlib"
6
- require "set"
7
5
  require "active_support/dependencies"
8
6
  require "active_support/core_ext/digest/uuid"
9
7
  require "active_record/test_fixtures"
@@ -100,17 +100,21 @@ module ActiveRecord
100
100
  def execute_or_skip
101
101
  return unless pending?
102
102
 
103
- @pool.with_connection do |connection|
104
- return unless @mutex.try_lock
105
- begin
106
- if pending?
107
- @event_buffer = EventBuffer.new(self, @instrumenter)
108
- connection.with_instrumenter(@event_buffer) do
109
- execute_query(connection, async: true)
103
+ @session.synchronize do
104
+ return unless pending?
105
+
106
+ @pool.with_connection do |connection|
107
+ return unless @mutex.try_lock
108
+ begin
109
+ if pending?
110
+ @event_buffer = EventBuffer.new(self, @instrumenter)
111
+ connection.with_instrumenter(@event_buffer) do
112
+ execute_query(connection, async: true)
113
+ end
110
114
  end
115
+ ensure
116
+ @mutex.unlock
111
117
  end
112
- ensure
113
- @mutex.unlock
114
118
  end
115
119
  end
116
120
  end
@@ -163,7 +167,7 @@ module ActiveRecord
163
167
  end
164
168
 
165
169
  def exec_query(connection, *args, **kwargs)
166
- connection.internal_exec_query(*args, **kwargs)
170
+ connection.raw_exec_query(*args, **kwargs)
167
171
  end
168
172
 
169
173
  class SelectAll < FutureResult # :nodoc:
@@ -7,10 +7,10 @@ module ActiveRecord
7
7
  end
8
8
 
9
9
  module VERSION
10
- MAJOR = 7
11
- MINOR = 2
12
- TINY = 1
13
- PRE = "1"
10
+ MAJOR = 8
11
+ MINOR = 0
12
+ TINY = 0
13
+ PRE = "rc1"
14
14
 
15
15
  STRING = [MAJOR, MINOR, TINY, PRE].compact.join(".")
16
16
  end
@@ -240,7 +240,7 @@ module ActiveRecord
240
240
 
241
241
  values_list = insert_all.map_key_with_value do |key, value|
242
242
  next value if Arel::Nodes::SqlLiteral === value
243
- connection.with_yaml_fallback(types[key].serialize(value))
243
+ types[key].serialize(types[key].cast(value))
244
244
  end
245
245
 
246
246
  connection.visitor.compile(Arel::Nodes::ValuesList.new(values_list))
@@ -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?
@@ -22,10 +22,12 @@ module ActiveRecord
22
22
  # * change_table_comment (must supply a +:from+ and +:to+ option)
23
23
  # * create_enum
24
24
  # * create_join_table
25
+ # * create_virtual_table
25
26
  # * create_table
26
27
  # * disable_extension
27
28
  # * drop_enum (must supply a list of values)
28
29
  # * drop_join_table
30
+ # * drop_virtual_table (must supply options)
29
31
  # * drop_table (must supply a block)
30
32
  # * enable_extension
31
33
  # * remove_column (must supply a type)
@@ -55,6 +57,8 @@ module ActiveRecord
55
57
  :add_exclusion_constraint, :remove_exclusion_constraint,
56
58
  :add_unique_constraint, :remove_unique_constraint,
57
59
  :create_enum, :drop_enum, :rename_enum, :add_enum_value, :rename_enum_value,
60
+ :create_schema, :drop_schema,
61
+ :create_virtual_table, :drop_virtual_table
58
62
  ]
59
63
  include JoinTable
60
64
 
@@ -163,7 +167,9 @@ module ActiveRecord
163
167
  add_exclusion_constraint: :remove_exclusion_constraint,
164
168
  add_unique_constraint: :remove_unique_constraint,
165
169
  enable_extension: :disable_extension,
166
- create_enum: :drop_enum
170
+ create_enum: :drop_enum,
171
+ create_schema: :drop_schema,
172
+ create_virtual_table: :drop_virtual_table
167
173
  }.each do |cmd, inv|
168
174
  [[inv, cmd], [cmd, inv]].uniq.each do |method, inverse|
169
175
  class_eval <<-EOV, __FILE__, __LINE__ + 1
@@ -196,13 +202,18 @@ module ActiveRecord
196
202
  end
197
203
 
198
204
  def invert_drop_table(args, &block)
199
- if args.last.is_a?(Hash)
200
- args.last.delete(:if_exists)
205
+ options = args.extract_options!
206
+ options.delete(:if_exists)
207
+
208
+ if args.size > 1
209
+ raise ActiveRecord::IrreversibleMigration, "To avoid mistakes, drop_table is only reversible if given a single table name."
201
210
  end
202
- if args.size == 1 && block == nil
211
+
212
+ if args.size == 1 && options == {} && block == nil
203
213
  raise ActiveRecord::IrreversibleMigration, "To avoid mistakes, drop_table is only reversible if given options or a block (can be empty)."
204
214
  end
205
- super
215
+
216
+ super(args.push(options), &block)
206
217
  end
207
218
 
208
219
  def invert_rename_table(args)
@@ -372,6 +383,12 @@ module ActiveRecord
372
383
  [:rename_enum_value, [type_name, from: options[:to], to: options[:from]]]
373
384
  end
374
385
 
386
+ def invert_drop_virtual_table(args)
387
+ _enum, values = args.dup.tap(&:extract_options!)
388
+ raise ActiveRecord::IrreversibleMigration, "drop_virtual_table is only reversible if given options." unless values
389
+ super
390
+ end
391
+
375
392
  def respond_to_missing?(method, _)
376
393
  super || delegate.respond_to?(method)
377
394
  end
@@ -21,7 +21,7 @@ module ActiveRecord
21
21
  # New migration functionality that will never be backward compatible should be added directly to `ActiveRecord::Migration`.
22
22
  #
23
23
  # There are classes for each prior Rails version. Each class descends from the *next* Rails version, so:
24
- # 5.2 < 6.0 < 6.1 < 7.0 < 7.1 < 7.2
24
+ # 5.2 < 6.0 < 6.1 < 7.0 < 7.1 < 7.2 < 8.0
25
25
  #
26
26
  # If you are introducing new migration functionality that should only apply from Rails 7 onward, then you should
27
27
  # find the class that immediately precedes it (6.1), and override the relevant migration methods to undo your changes.
@@ -29,7 +29,10 @@ module ActiveRecord
29
29
  # For example, Rails 6 added a default value for the `precision` option on datetime columns. So in this file, the `V5_2`
30
30
  # class sets the value of `precision` to `nil` if it's not explicitly provided. This way, the default value will not apply
31
31
  # for migrations written for 5.2, but will for migrations written for 6.0.
32
- V7_2 = Current
32
+ V8_0 = Current
33
+
34
+ class V7_2 < V8_0
35
+ end
33
36
 
34
37
  class V7_1 < V7_2
35
38
  end