activerecord 8.0.3 → 8.1.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 (160) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +520 -514
  3. data/README.rdoc +1 -1
  4. data/lib/active_record/association_relation.rb +1 -1
  5. data/lib/active_record/associations/association.rb +1 -1
  6. data/lib/active_record/associations/belongs_to_association.rb +2 -0
  7. data/lib/active_record/associations/builder/association.rb +16 -5
  8. data/lib/active_record/associations/builder/belongs_to.rb +17 -4
  9. data/lib/active_record/associations/builder/collection_association.rb +7 -3
  10. data/lib/active_record/associations/builder/has_one.rb +1 -1
  11. data/lib/active_record/associations/builder/singular_association.rb +33 -5
  12. data/lib/active_record/associations/collection_proxy.rb +22 -4
  13. data/lib/active_record/associations/deprecation.rb +88 -0
  14. data/lib/active_record/associations/errors.rb +3 -0
  15. data/lib/active_record/associations/join_dependency.rb +2 -0
  16. data/lib/active_record/associations/preloader/branch.rb +1 -0
  17. data/lib/active_record/associations.rb +159 -21
  18. data/lib/active_record/attribute_methods/serialization.rb +16 -3
  19. data/lib/active_record/attribute_methods/time_zone_conversion.rb +10 -2
  20. data/lib/active_record/attributes.rb +3 -0
  21. data/lib/active_record/autosave_association.rb +1 -1
  22. data/lib/active_record/base.rb +0 -2
  23. data/lib/active_record/coders/json.rb +14 -5
  24. data/lib/active_record/connection_adapters/abstract/connection_handler.rb +1 -3
  25. data/lib/active_record/connection_adapters/abstract/connection_pool/queue.rb +16 -3
  26. data/lib/active_record/connection_adapters/abstract/connection_pool/reaper.rb +51 -12
  27. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +405 -72
  28. data/lib/active_record/connection_adapters/abstract/database_statements.rb +55 -40
  29. data/lib/active_record/connection_adapters/abstract/query_cache.rb +19 -3
  30. data/lib/active_record/connection_adapters/abstract/quoting.rb +15 -24
  31. data/lib/active_record/connection_adapters/abstract/schema_creation.rb +7 -2
  32. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +26 -34
  33. data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +2 -1
  34. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +85 -22
  35. data/lib/active_record/connection_adapters/abstract/transaction.rb +25 -3
  36. data/lib/active_record/connection_adapters/abstract_adapter.rb +86 -20
  37. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +43 -13
  38. data/lib/active_record/connection_adapters/column.rb +17 -4
  39. data/lib/active_record/connection_adapters/mysql/database_statements.rb +4 -4
  40. data/lib/active_record/connection_adapters/mysql/schema_creation.rb +2 -0
  41. data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +42 -5
  42. data/lib/active_record/connection_adapters/mysql/schema_statements.rb +26 -4
  43. data/lib/active_record/connection_adapters/mysql2/database_statements.rb +27 -22
  44. data/lib/active_record/connection_adapters/mysql2_adapter.rb +1 -2
  45. data/lib/active_record/connection_adapters/postgresql/column.rb +4 -0
  46. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +17 -15
  47. data/lib/active_record/connection_adapters/postgresql/oid/array.rb +2 -2
  48. data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +1 -1
  49. data/lib/active_record/connection_adapters/postgresql/quoting.rb +21 -10
  50. data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +8 -6
  51. data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +8 -21
  52. data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +66 -31
  53. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +81 -48
  54. data/lib/active_record/connection_adapters/postgresql_adapter.rb +23 -7
  55. data/lib/active_record/connection_adapters/schema_cache.rb +2 -2
  56. data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +37 -25
  57. data/lib/active_record/connection_adapters/sqlite3/quoting.rb +0 -8
  58. data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +4 -13
  59. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +54 -30
  60. data/lib/active_record/connection_adapters/trilogy/database_statements.rb +4 -3
  61. data/lib/active_record/connection_adapters/trilogy_adapter.rb +1 -1
  62. data/lib/active_record/connection_adapters.rb +1 -0
  63. data/lib/active_record/connection_handling.rb +2 -1
  64. data/lib/active_record/core.rb +5 -4
  65. data/lib/active_record/counter_cache.rb +33 -8
  66. data/lib/active_record/database_configurations/database_config.rb +5 -1
  67. data/lib/active_record/database_configurations/hash_config.rb +53 -9
  68. data/lib/active_record/database_configurations/url_config.rb +13 -3
  69. data/lib/active_record/database_configurations.rb +7 -3
  70. data/lib/active_record/delegated_type.rb +1 -1
  71. data/lib/active_record/dynamic_matchers.rb +54 -69
  72. data/lib/active_record/encryption/encryptable_record.rb +4 -4
  73. data/lib/active_record/encryption/encrypted_attribute_type.rb +1 -1
  74. data/lib/active_record/encryption/encryptor.rb +12 -0
  75. data/lib/active_record/encryption/scheme.rb +1 -1
  76. data/lib/active_record/enum.rb +24 -8
  77. data/lib/active_record/errors.rb +20 -4
  78. data/lib/active_record/explain.rb +1 -1
  79. data/lib/active_record/explain_registry.rb +51 -2
  80. data/lib/active_record/filter_attribute_handler.rb +73 -0
  81. data/lib/active_record/fixtures.rb +2 -2
  82. data/lib/active_record/gem_version.rb +3 -3
  83. data/lib/active_record/inheritance.rb +1 -1
  84. data/lib/active_record/insert_all.rb +12 -7
  85. data/lib/active_record/locking/optimistic.rb +7 -0
  86. data/lib/active_record/locking/pessimistic.rb +5 -0
  87. data/lib/active_record/log_subscriber.rb +2 -6
  88. data/lib/active_record/middleware/shard_selector.rb +34 -17
  89. data/lib/active_record/migration/command_recorder.rb +14 -1
  90. data/lib/active_record/migration/compatibility.rb +34 -24
  91. data/lib/active_record/migration/default_schema_versions_formatter.rb +30 -0
  92. data/lib/active_record/migration.rb +26 -16
  93. data/lib/active_record/model_schema.rb +36 -10
  94. data/lib/active_record/nested_attributes.rb +2 -0
  95. data/lib/active_record/persistence.rb +34 -3
  96. data/lib/active_record/query_cache.rb +22 -15
  97. data/lib/active_record/query_logs.rb +3 -7
  98. data/lib/active_record/railtie.rb +32 -3
  99. data/lib/active_record/railties/controller_runtime.rb +11 -6
  100. data/lib/active_record/railties/databases.rake +15 -3
  101. data/lib/active_record/railties/job_checkpoints.rb +15 -0
  102. data/lib/active_record/railties/job_runtime.rb +10 -11
  103. data/lib/active_record/reflection.rb +42 -3
  104. data/lib/active_record/relation/batches.rb +25 -11
  105. data/lib/active_record/relation/calculations.rb +20 -9
  106. data/lib/active_record/relation/delegation.rb +0 -1
  107. data/lib/active_record/relation/finder_methods.rb +27 -11
  108. data/lib/active_record/relation/predicate_builder/association_query_value.rb +9 -9
  109. data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +7 -7
  110. data/lib/active_record/relation/predicate_builder.rb +9 -7
  111. data/lib/active_record/relation/query_attribute.rb +3 -1
  112. data/lib/active_record/relation/query_methods.rb +38 -28
  113. data/lib/active_record/relation/where_clause.rb +1 -8
  114. data/lib/active_record/relation.rb +24 -12
  115. data/lib/active_record/result.rb +44 -21
  116. data/lib/active_record/runtime_registry.rb +41 -58
  117. data/lib/active_record/sanitization.rb +2 -0
  118. data/lib/active_record/schema_dumper.rb +12 -10
  119. data/lib/active_record/scoping.rb +0 -1
  120. data/lib/active_record/signed_id.rb +43 -15
  121. data/lib/active_record/statement_cache.rb +13 -9
  122. data/lib/active_record/store.rb +44 -19
  123. data/lib/active_record/structured_event_subscriber.rb +85 -0
  124. data/lib/active_record/table_metadata.rb +5 -20
  125. data/lib/active_record/tasks/abstract_tasks.rb +76 -0
  126. data/lib/active_record/tasks/database_tasks.rb +25 -34
  127. data/lib/active_record/tasks/mysql_database_tasks.rb +3 -40
  128. data/lib/active_record/tasks/postgresql_database_tasks.rb +5 -39
  129. data/lib/active_record/tasks/sqlite_database_tasks.rb +14 -26
  130. data/lib/active_record/test_databases.rb +14 -4
  131. data/lib/active_record/test_fixtures.rb +27 -2
  132. data/lib/active_record/testing/query_assertions.rb +8 -2
  133. data/lib/active_record/timestamp.rb +4 -2
  134. data/lib/active_record/transaction.rb +2 -5
  135. data/lib/active_record/transactions.rb +32 -10
  136. data/lib/active_record/type/hash_lookup_type_map.rb +2 -1
  137. data/lib/active_record/type/internal/timezone.rb +7 -0
  138. data/lib/active_record/type/json.rb +15 -2
  139. data/lib/active_record/type/serialized.rb +11 -4
  140. data/lib/active_record/type/type_map.rb +1 -1
  141. data/lib/active_record/type_caster/connection.rb +2 -1
  142. data/lib/active_record/validations/associated.rb +1 -1
  143. data/lib/active_record.rb +65 -3
  144. data/lib/arel/alias_predication.rb +2 -0
  145. data/lib/arel/crud.rb +6 -11
  146. data/lib/arel/nodes/count.rb +2 -2
  147. data/lib/arel/nodes/function.rb +4 -10
  148. data/lib/arel/nodes/named_function.rb +2 -2
  149. data/lib/arel/nodes/node.rb +1 -1
  150. data/lib/arel/nodes.rb +0 -2
  151. data/lib/arel/select_manager.rb +7 -2
  152. data/lib/arel/visitors/dot.rb +0 -3
  153. data/lib/arel/visitors/postgresql.rb +55 -0
  154. data/lib/arel/visitors/sqlite.rb +55 -8
  155. data/lib/arel/visitors/to_sql.rb +3 -21
  156. data/lib/arel.rb +3 -1
  157. data/lib/rails/generators/active_record/application_record/USAGE +1 -1
  158. metadata +14 -10
  159. data/lib/active_record/explain_subscriber.rb +0 -34
  160. data/lib/active_record/normalization.rb +0 -163
@@ -101,6 +101,13 @@ module ActiveRecord
101
101
  attribute_names = attribute_names.dup if attribute_names.frozen?
102
102
  attribute_names << locking_column
103
103
 
104
+ if self[locking_column].nil?
105
+ raise(<<-MSG.squish)
106
+ For optimistic locking, locking_column ('#{locking_column}') can't be nil.
107
+ Are you missing a default value or validation on '#{locking_column}'?
108
+ MSG
109
+ end
110
+
104
111
  self[locking_column] += 1
105
112
 
106
113
  affected_rows = self.class._update_record(
@@ -67,6 +67,10 @@ module ActiveRecord
67
67
  # or pass true for "FOR UPDATE" (the default, an exclusive row lock). Returns
68
68
  # the locked record.
69
69
  def lock!(lock = true)
70
+ if self.class.current_preventing_writes
71
+ raise ActiveRecord::ReadOnlyError, "Lock query attempted while in readonly mode"
72
+ end
73
+
70
74
  if persisted?
71
75
  if has_changes_to_save?
72
76
  raise(<<-MSG.squish)
@@ -79,6 +83,7 @@ module ActiveRecord
79
83
 
80
84
  reload(lock: lock)
81
85
  end
86
+
82
87
  self
83
88
  end
84
89
 
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module ActiveRecord
4
- class LogSubscriber < ActiveSupport::LogSubscriber
4
+ class LogSubscriber < ActiveSupport::LogSubscriber # :nodoc:
5
5
  IGNORE_PAYLOAD_NAMES = ["SCHEMA", "EXPLAIN"]
6
6
 
7
7
  class_attribute :backtrace_cleaner, default: ActiveSupport::BacktraceCleaner.new
@@ -127,11 +127,7 @@ module ActiveRecord
127
127
  end
128
128
 
129
129
  def query_source_location
130
- Thread.each_caller_location do |location|
131
- frame = backtrace_cleaner.clean_frame(location)
132
- return frame if frame
133
- end
134
- nil
130
+ backtrace_cleaner.first_clean_frame
135
131
  end
136
132
 
137
133
  def filter(name, value)
@@ -9,25 +9,40 @@ module ActiveRecord
9
9
  # shard to switch to and allows for applications to write custom strategies
10
10
  # for swapping if needed.
11
11
  #
12
- # The ShardSelector takes a set of options (currently only +lock+ is supported)
13
- # that can be used by the middleware to alter behavior. +lock+ is
14
- # true by default and will prohibit the request from switching shards once
15
- # inside the block. If +lock+ is false, then shard swapping will be allowed.
16
- # For tenant based sharding, +lock+ should always be true to prevent application
17
- # code from mistakenly switching between tenants.
12
+ # == Setup
18
13
  #
19
- # Options can be set in the config:
14
+ # Applications must provide a resolver that will provide application-specific logic for
15
+ # selecting the appropriate shard. Setting +config.active_record.shard_resolver+ will cause
16
+ # Rails to add ShardSelector to the default middleware stack.
20
17
  #
21
- # config.active_record.shard_selector = { lock: true }
18
+ # The resolver, along with any configuration options, can be set in the application
19
+ # configuration using an initializer like so:
22
20
  #
23
- # Applications must also provide the code for the resolver as it depends on application
24
- # specific models. An example resolver would look like this:
21
+ # Rails.application.configure do
22
+ # config.active_record.shard_selector = { lock: false, class_name: "AnimalsRecord" }
23
+ # config.active_record.shard_resolver = ->(request) {
24
+ # subdomain = request.subdomain
25
+ # tenant = Tenant.find_by_subdomain!(subdomain)
26
+ # tenant.shard
27
+ # }
28
+ # end
29
+ #
30
+ # == Configuration
31
+ #
32
+ # The behavior of ShardSelector can be altered through some configuration options.
33
+ #
34
+ # [+lock:+]
35
+ # +lock+ is true by default and will prohibit the request from switching shards once inside
36
+ # the block. If +lock+ is false, then shard switching will be allowed. For tenant based
37
+ # sharding, +lock+ should always be true to prevent application code from mistakenly switching
38
+ # between tenants.
39
+ #
40
+ # [+class_name:+]
41
+ # +class_name+ is the name of the abstract connection class to switch. By
42
+ # default, the ShardSelector will use ActiveRecord::Base, but if the
43
+ # application has multiple databases, then this option should be set to
44
+ # the name of the sharded database's abstract connection class.
25
45
  #
26
- # config.active_record.shard_resolver = ->(request) {
27
- # subdomain = request.subdomain
28
- # tenant = Tenant.find_by_subdomain!(subdomain)
29
- # tenant.shard
30
- # }
31
46
  class ShardSelector
32
47
  def initialize(app, resolver, options = {})
33
48
  @app = app
@@ -53,8 +68,10 @@ module ActiveRecord
53
68
  end
54
69
 
55
70
  def set_shard(shard, &block)
56
- ActiveRecord::Base.connected_to(shard: shard.to_sym) do
57
- ActiveRecord::Base.prohibit_shard_swapping(options.fetch(:lock, true), &block)
71
+ klass = options[:class_name]&.constantize || ActiveRecord::Base
72
+
73
+ klass.connected_to(shard: shard.to_sym) do
74
+ klass.prohibit_shard_swapping(options.fetch(:lock, true), &block)
58
75
  end
59
76
  end
60
77
  end
@@ -44,6 +44,8 @@ module ActiveRecord
44
44
  # * rename_enum_value (must supply a +:from+ and +:to+ option)
45
45
  # * rename_index
46
46
  # * rename_table
47
+ # * enable_index
48
+ # * disable_index
47
49
  class CommandRecorder
48
50
  ReversibleAndIrreversibleMethods = [
49
51
  :create_table, :create_join_table, :rename_table, :add_column, :remove_column,
@@ -58,7 +60,8 @@ module ActiveRecord
58
60
  :add_unique_constraint, :remove_unique_constraint,
59
61
  :create_enum, :drop_enum, :rename_enum, :add_enum_value, :rename_enum_value,
60
62
  :create_schema, :drop_schema,
61
- :create_virtual_table, :drop_virtual_table
63
+ :create_virtual_table, :drop_virtual_table,
64
+ :enable_index, :disable_index
62
65
  ]
63
66
  include JoinTable
64
67
 
@@ -183,6 +186,16 @@ module ActiveRecord
183
186
 
184
187
  include StraightReversions
185
188
 
189
+ def invert_enable_index(args)
190
+ table_name, index_name = args
191
+ [:disable_index, [table_name, index_name]]
192
+ end
193
+
194
+ def invert_disable_index(args)
195
+ table_name, index_name = args
196
+ [:enable_index, [table_name, index_name]]
197
+ end
198
+
186
199
  def invert_transaction(args, &block)
187
200
  sub_recorder = CommandRecorder.new(delegate)
188
201
  sub_recorder.revert(&block)
@@ -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 < 8.0
24
+ # 5.2 < 6.0 < 6.1 < 7.0 < 7.1 < 7.2 < 8.0 < 8.1
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,31 @@ 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
- V8_0 = Current
32
+ V8_1 = Current
33
+
34
+ class V8_0 < V8_1
35
+ module RemoveForeignKeyColumnMatch
36
+ def remove_foreign_key(*args, **options)
37
+ options[:_skip_column_match] = true
38
+ super
39
+ end
40
+ end
41
+
42
+ module TableDefinition
43
+ def remove_foreign_key(to_table = nil, **options)
44
+ options[:_skip_column_match] = true
45
+ super
46
+ end
47
+ end
48
+
49
+ include RemoveForeignKeyColumnMatch
50
+
51
+ private
52
+ def compatible_table_definition(t)
53
+ t.singleton_class.prepend(TableDefinition)
54
+ super
55
+ end
56
+ end
33
57
 
34
58
  class V7_2 < V8_0
35
59
  end
@@ -154,9 +178,7 @@ module ActiveRecord
154
178
 
155
179
  private
156
180
  def compatible_table_definition(t)
157
- class << t
158
- prepend TableDefinition
159
- end
181
+ t.singleton_class.prepend(TableDefinition)
160
182
  super
161
183
  end
162
184
  end
@@ -217,9 +239,7 @@ module ActiveRecord
217
239
 
218
240
  private
219
241
  def compatible_table_definition(t)
220
- class << t
221
- prepend TableDefinition
222
- end
242
+ t.singleton_class.prepend(TableDefinition)
223
243
  super
224
244
  end
225
245
  end
@@ -260,9 +280,7 @@ module ActiveRecord
260
280
 
261
281
  private
262
282
  def compatible_table_definition(t)
263
- class << t
264
- prepend TableDefinition
265
- end
283
+ t.singleton_class.prepend(TableDefinition)
266
284
  super
267
285
  end
268
286
  end
@@ -308,17 +326,13 @@ module ActiveRecord
308
326
 
309
327
  private
310
328
  def compatible_table_definition(t)
311
- class << t
312
- prepend TableDefinition
313
- end
329
+ t.singleton_class.prepend(TableDefinition)
314
330
  super
315
331
  end
316
332
 
317
333
  def command_recorder
318
334
  recorder = super
319
- class << recorder
320
- prepend CommandRecorder
321
- end
335
+ recorder.singleton_class.prepend(CommandRecorder)
322
336
  recorder
323
337
  end
324
338
  end
@@ -406,9 +420,7 @@ module ActiveRecord
406
420
 
407
421
  private
408
422
  def compatible_table_definition(t)
409
- class << t
410
- prepend TableDefinition
411
- end
423
+ t.singleton_class.prepend(TableDefinition)
412
424
  super
413
425
  end
414
426
  end
@@ -442,7 +454,7 @@ module ActiveRecord
442
454
  super
443
455
  end
444
456
 
445
- def index_exists?(table_name, column_name, **options)
457
+ def index_exists?(table_name, column_name = nil, **options)
446
458
  column_names = Array(column_name).map(&:to_s)
447
459
  options[:name] =
448
460
  if options[:name].present?
@@ -460,9 +472,7 @@ module ActiveRecord
460
472
 
461
473
  private
462
474
  def compatible_table_definition(t)
463
- class << t
464
- prepend TableDefinition
465
- end
475
+ t.singleton_class.prepend(TableDefinition)
466
476
  super
467
477
  end
468
478
 
@@ -0,0 +1,30 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActiveRecord
4
+ class Migration
5
+ # This class is used by the schema dumper to format versions information.
6
+ #
7
+ # The class receives the current +connection+ when initialized.
8
+ class DefaultSchemaVersionsFormatter # :nodoc:
9
+ def initialize(connection)
10
+ @connection = connection
11
+ end
12
+
13
+ def format(versions)
14
+ sm_table = connection.quote_table_name(connection.pool.schema_migration.table_name)
15
+
16
+ if versions.is_a?(Array)
17
+ sql = +"INSERT INTO #{sm_table} (version) VALUES\n"
18
+ sql << versions.reverse.map { |v| "(#{connection.quote(v)})" }.join(",\n")
19
+ sql << ";"
20
+ sql
21
+ else
22
+ "INSERT INTO #{sm_table} (version) VALUES (#{connection.quote(versions)});"
23
+ end
24
+ end
25
+
26
+ private
27
+ attr_reader :connection
28
+ end
29
+ end
30
+ end
@@ -18,7 +18,7 @@ module ActiveRecord
18
18
  # For example the following migration is not reversible.
19
19
  # Rolling back this migration will raise an ActiveRecord::IrreversibleMigration error.
20
20
  #
21
- # class IrreversibleMigrationExample < ActiveRecord::Migration[8.0]
21
+ # class IrreversibleMigrationExample < ActiveRecord::Migration[8.1]
22
22
  # def change
23
23
  # create_table :distributors do |t|
24
24
  # t.string :zipcode
@@ -36,7 +36,7 @@ module ActiveRecord
36
36
  #
37
37
  # 1. Define <tt>#up</tt> and <tt>#down</tt> methods instead of <tt>#change</tt>:
38
38
  #
39
- # class ReversibleMigrationExample < ActiveRecord::Migration[8.0]
39
+ # class ReversibleMigrationExample < ActiveRecord::Migration[8.1]
40
40
  # def up
41
41
  # create_table :distributors do |t|
42
42
  # t.string :zipcode
@@ -61,7 +61,7 @@ module ActiveRecord
61
61
  #
62
62
  # 2. Use the #reversible method in <tt>#change</tt> method:
63
63
  #
64
- # class ReversibleMigrationExample < ActiveRecord::Migration[8.0]
64
+ # class ReversibleMigrationExample < ActiveRecord::Migration[8.1]
65
65
  # def change
66
66
  # create_table :distributors do |t|
67
67
  # t.string :zipcode
@@ -246,7 +246,7 @@ module ActiveRecord
246
246
  #
247
247
  # Example of a simple migration:
248
248
  #
249
- # class AddSsl < ActiveRecord::Migration[8.0]
249
+ # class AddSsl < ActiveRecord::Migration[8.1]
250
250
  # def up
251
251
  # add_column :accounts, :ssl_enabled, :boolean, default: true
252
252
  # end
@@ -266,7 +266,7 @@ module ActiveRecord
266
266
  #
267
267
  # Example of a more complex migration that also needs to initialize data:
268
268
  #
269
- # class AddSystemSettings < ActiveRecord::Migration[8.0]
269
+ # class AddSystemSettings < ActiveRecord::Migration[8.1]
270
270
  # def up
271
271
  # create_table :system_settings do |t|
272
272
  # t.string :name
@@ -395,7 +395,7 @@ module ActiveRecord
395
395
  # $ bin/rails generate migration add_fieldname_to_tablename fieldname:string
396
396
  #
397
397
  # This will generate the file <tt>timestamp_add_fieldname_to_tablename.rb</tt>, which will look like this:
398
- # class AddFieldnameToTablename < ActiveRecord::Migration[8.0]
398
+ # class AddFieldnameToTablename < ActiveRecord::Migration[8.1]
399
399
  # def change
400
400
  # add_column :tablenames, :fieldname, :string
401
401
  # end
@@ -421,7 +421,7 @@ module ActiveRecord
421
421
  #
422
422
  # Not all migrations change the schema. Some just fix the data:
423
423
  #
424
- # class RemoveEmptyTags < ActiveRecord::Migration[8.0]
424
+ # class RemoveEmptyTags < ActiveRecord::Migration[8.1]
425
425
  # def up
426
426
  # Tag.all.each { |tag| tag.destroy if tag.pages.empty? }
427
427
  # end
@@ -434,7 +434,7 @@ module ActiveRecord
434
434
  #
435
435
  # Others remove columns when they migrate up instead of down:
436
436
  #
437
- # class RemoveUnnecessaryItemAttributes < ActiveRecord::Migration[8.0]
437
+ # class RemoveUnnecessaryItemAttributes < ActiveRecord::Migration[8.1]
438
438
  # def up
439
439
  # remove_column :items, :incomplete_items_count
440
440
  # remove_column :items, :completed_items_count
@@ -448,7 +448,7 @@ module ActiveRecord
448
448
  #
449
449
  # And sometimes you need to do something in SQL not abstracted directly by migrations:
450
450
  #
451
- # class MakeJoinUnique < ActiveRecord::Migration[8.0]
451
+ # class MakeJoinUnique < ActiveRecord::Migration[8.1]
452
452
  # def up
453
453
  # execute "ALTER TABLE `pages_linked_pages` ADD UNIQUE `page_id_linked_page_id` (`page_id`,`linked_page_id`)"
454
454
  # end
@@ -465,7 +465,7 @@ module ActiveRecord
465
465
  # <tt>Base#reset_column_information</tt> in order to ensure that the model has the
466
466
  # latest column data from after the new column was added. Example:
467
467
  #
468
- # class AddPeopleSalary < ActiveRecord::Migration[8.0]
468
+ # class AddPeopleSalary < ActiveRecord::Migration[8.1]
469
469
  # def up
470
470
  # add_column :people, :salary, :integer
471
471
  # Person.reset_column_information
@@ -527,7 +527,7 @@ module ActiveRecord
527
527
  # To define a reversible migration, define the +change+ method in your
528
528
  # migration like this:
529
529
  #
530
- # class TenderloveMigration < ActiveRecord::Migration[8.0]
530
+ # class TenderloveMigration < ActiveRecord::Migration[8.1]
531
531
  # def change
532
532
  # create_table(:horses) do |t|
533
533
  # t.column :content, :text
@@ -557,7 +557,7 @@ module ActiveRecord
557
557
  # can't execute inside a transaction though, and for these situations
558
558
  # you can turn the automatic transactions off.
559
559
  #
560
- # class ChangeEnum < ActiveRecord::Migration[8.0]
560
+ # class ChangeEnum < ActiveRecord::Migration[8.1]
561
561
  # disable_ddl_transaction!
562
562
  #
563
563
  # def up
@@ -570,6 +570,7 @@ module ActiveRecord
570
570
  class Migration
571
571
  autoload :CommandRecorder, "active_record/migration/command_recorder"
572
572
  autoload :Compatibility, "active_record/migration/compatibility"
573
+ autoload :DefaultSchemaVersionsFormatter, "active_record/migration/default_schema_versions_formatter"
573
574
  autoload :JoinTable, "active_record/migration/join_table"
574
575
  autoload :ExecutionStrategy, "active_record/migration/execution_strategy"
575
576
  autoload :DefaultStrategy, "active_record/migration/default_strategy"
@@ -781,6 +782,11 @@ module ActiveRecord
781
782
  system("bin/rails db:test:prepare")
782
783
  end
783
784
  end
785
+
786
+ def respond_to_missing?(method, include_private = false)
787
+ return false if nearest_delegate == delegate
788
+ nearest_delegate.respond_to?(method, include_private)
789
+ end
784
790
  end
785
791
 
786
792
  def disable_ddl_transaction # :nodoc:
@@ -818,7 +824,7 @@ module ActiveRecord
818
824
  # and create the table 'apples' on the way up, and the reverse
819
825
  # on the way down.
820
826
  #
821
- # class FixTLMigration < ActiveRecord::Migration[8.0]
827
+ # class FixTLMigration < ActiveRecord::Migration[8.1]
822
828
  # def change
823
829
  # revert do
824
830
  # create_table(:horses) do |t|
@@ -837,7 +843,7 @@ module ActiveRecord
837
843
  #
838
844
  # require_relative "20121212123456_tenderlove_migration"
839
845
  #
840
- # class FixupTLMigration < ActiveRecord::Migration[8.0]
846
+ # class FixupTLMigration < ActiveRecord::Migration[8.1]
841
847
  # def change
842
848
  # revert TenderloveMigration
843
849
  #
@@ -888,7 +894,7 @@ module ActiveRecord
888
894
  # when the three columns 'first_name', 'last_name' and 'full_name' exist,
889
895
  # even when migrating down:
890
896
  #
891
- # class SplitNameMigration < ActiveRecord::Migration[8.0]
897
+ # class SplitNameMigration < ActiveRecord::Migration[8.1]
892
898
  # def change
893
899
  # add_column :users, :first_name, :string
894
900
  # add_column :users, :last_name, :string
@@ -916,7 +922,7 @@ module ActiveRecord
916
922
  # In the following example, the new column +published+ will be given
917
923
  # the value +true+ for all existing records.
918
924
  #
919
- # class AddPublishedToPosts < ActiveRecord::Migration[8.0]
925
+ # class AddPublishedToPosts < ActiveRecord::Migration[8.1]
920
926
  # def change
921
927
  # add_column :posts, :published, :boolean, default: false
922
928
  # up_only do
@@ -1169,6 +1175,10 @@ module ActiveRecord
1169
1175
  def command_recorder
1170
1176
  CommandRecorder.new(connection)
1171
1177
  end
1178
+
1179
+ def respond_to_missing?(method, include_private = false)
1180
+ execution_strategy.respond_to?(method, include_private) || super
1181
+ end
1172
1182
  end
1173
1183
 
1174
1184
  # MigrationProxy is used to defer loading of the actual migration classes
@@ -48,7 +48,7 @@ module ActiveRecord
48
48
  # way of creating a namespace for tables in a shared database. By default, the prefix is the
49
49
  # empty string.
50
50
  #
51
- # If you are organising your models within modules you can add a prefix to the models within
51
+ # If you are organizing your models within modules you can add a prefix to the models within
52
52
  # a namespace by defining a singleton method in the parent module called table_name_prefix which
53
53
  # returns your chosen prefix.
54
54
 
@@ -65,7 +65,7 @@ module ActiveRecord
65
65
  # Works like +table_name_prefix=+, but appends instead of prepends (set to "_basecamp" gives "projects_basecamp",
66
66
  # "people_basecamp"). By default, the suffix is the empty string.
67
67
  #
68
- # If you are organising your models within modules, you can add a suffix to the models within
68
+ # If you are organizing your models within modules, you can add a suffix to the models within
69
69
  # a namespace by defining a singleton method in the parent module called table_name_suffix which
70
70
  # returns your chosen suffix.
71
71
 
@@ -113,17 +113,19 @@ module ActiveRecord
113
113
  # :singleton-method: implicit_order_column
114
114
  # :call-seq: implicit_order_column
115
115
  #
116
- # The name of the column records are ordered by if no explicit order clause
116
+ # The name of the column(s) records are ordered by if no explicit order clause
117
117
  # is used during an ordered finder call. If not set the primary key is used.
118
118
 
119
119
  ##
120
120
  # :singleton-method: implicit_order_column=
121
121
  # :call-seq: implicit_order_column=(column_name)
122
122
  #
123
- # Sets the column to sort records by when no explicit order clause is used
124
- # during an ordered finder call. Useful when the primary key is not an
125
- # auto-incrementing integer, for example when it's a UUID. Records are subsorted
126
- # by the primary key if it exists to ensure deterministic results.
123
+ # Sets the column(s) to sort records by when no explicit order clause is used
124
+ # during an ordered finder call. Useful for models where the primary key isn't an
125
+ # auto-incrementing integer (such as UUID).
126
+ #
127
+ # By default, records are subsorted by primary key to ensure deterministic results.
128
+ # To disable this subsort behavior, set `implicit_order_column` to `["column_name", nil]`.
127
129
 
128
130
  ##
129
131
  # :singleton-method: immutable_strings_by_default=
@@ -179,6 +181,7 @@ module ActiveRecord
179
181
  self.protected_environments = ["production"]
180
182
 
181
183
  self.ignored_columns = [].freeze
184
+ self.only_columns = [].freeze
182
185
 
183
186
  delegate :type_for_attribute, :column_for_attribute, to: :class
184
187
 
@@ -332,6 +335,12 @@ module ActiveRecord
332
335
  @ignored_columns || superclass.ignored_columns
333
336
  end
334
337
 
338
+ # The list of columns names the model should allow. Only columns are used to define
339
+ # attribute accessors, and are referenced in SQL queries.
340
+ def only_columns
341
+ @only_columns || superclass.only_columns
342
+ end
343
+
335
344
  # Sets the columns names the model should ignore. Ignored columns won't have attribute
336
345
  # accessors defined, and won't be referenced in SQL queries.
337
346
  #
@@ -364,10 +373,17 @@ module ActiveRecord
364
373
  # user = Project.create!(name: "First Project")
365
374
  # user.category # => raises NoMethodError
366
375
  def ignored_columns=(columns)
376
+ check_model_columns(@only_columns.present?)
367
377
  reload_schema_from_cache
368
378
  @ignored_columns = columns.map(&:to_s).freeze
369
379
  end
370
380
 
381
+ def only_columns=(columns)
382
+ check_model_columns(@ignored_columns.present?)
383
+ reload_schema_from_cache
384
+ @only_columns = columns.map(&:to_s).freeze
385
+ end
386
+
371
387
  def sequence_name
372
388
  if base_class?
373
389
  @sequence_name ||= reset_sequence_name
@@ -501,7 +517,7 @@ module ActiveRecord
501
517
  # when just after creating a table you want to populate it with some default
502
518
  # values, e.g.:
503
519
  #
504
- # class CreateJobLevels < ActiveRecord::Migration[8.0]
520
+ # class CreateJobLevels < ActiveRecord::Migration[8.1]
505
521
  # def up
506
522
  # create_table :job_levels do |t|
507
523
  # t.integer :id
@@ -577,6 +593,7 @@ module ActiveRecord
577
593
  child_class.reload_schema_from_cache(false)
578
594
  child_class.class_eval do
579
595
  @ignored_columns = nil
596
+ @only_columns = nil
580
597
  end
581
598
  end
582
599
 
@@ -590,7 +607,11 @@ module ActiveRecord
590
607
  end
591
608
 
592
609
  columns_hash = schema_cache.columns_hash(table_name)
593
- columns_hash = columns_hash.except(*ignored_columns) unless ignored_columns.empty?
610
+ if only_columns.present?
611
+ columns_hash = columns_hash.slice(*only_columns)
612
+ elsif ignored_columns.present?
613
+ columns_hash = columns_hash.except(*ignored_columns)
614
+ end
594
615
  @columns_hash = columns_hash.freeze
595
616
 
596
617
  _default_attributes # Precompute to cache DB-dependent attribute types
@@ -620,7 +641,8 @@ module ActiveRecord
620
641
  end
621
642
 
622
643
  def type_for_column(connection, column)
623
- type = connection.lookup_cast_type_from_column(column)
644
+ # TODO: Remove the need for a connection after we release 8.1.
645
+ type = column.fetch_cast_type(connection)
624
646
 
625
647
  if immutable_strings_by_default && type.respond_to?(:to_immutable_string)
626
648
  type = type.to_immutable_string
@@ -628,6 +650,10 @@ module ActiveRecord
628
650
 
629
651
  type
630
652
  end
653
+
654
+ def check_model_columns(columns_present)
655
+ raise ArgumentError, "You can not use both only_columns and ignored_columns in the same model." if columns_present
656
+ end
631
657
  end
632
658
  end
633
659
  end
@@ -387,6 +387,8 @@ module ActiveRecord
387
387
  generated_association_methods.module_eval <<-eoruby, __FILE__, __LINE__ + 1
388
388
  silence_redefinition_of_method :#{association_name}_attributes=
389
389
  def #{association_name}_attributes=(attributes)
390
+ association = association(:#{association_name})
391
+ deprecated_associations_api_guard(association, __method__)
390
392
  assign_nested_attributes_for_#{type}_association(:#{association_name}, attributes)
391
393
  end
392
394
  eoruby