activerecord 7.1.3.2 → 7.2.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +570 -2094
- data/README.rdoc +15 -15
- data/examples/performance.rb +2 -2
- data/lib/active_record/association_relation.rb +1 -1
- data/lib/active_record/associations/alias_tracker.rb +25 -19
- data/lib/active_record/associations/association.rb +15 -8
- data/lib/active_record/associations/belongs_to_association.rb +18 -11
- data/lib/active_record/associations/belongs_to_polymorphic_association.rb +3 -2
- data/lib/active_record/associations/builder/belongs_to.rb +1 -0
- data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +2 -2
- data/lib/active_record/associations/builder/has_many.rb +3 -4
- data/lib/active_record/associations/builder/has_one.rb +3 -4
- data/lib/active_record/associations/collection_association.rb +11 -5
- data/lib/active_record/associations/collection_proxy.rb +14 -1
- data/lib/active_record/associations/errors.rb +265 -0
- data/lib/active_record/associations/has_many_association.rb +3 -3
- data/lib/active_record/associations/has_one_association.rb +2 -2
- data/lib/active_record/associations/join_dependency/join_association.rb +27 -25
- data/lib/active_record/associations/join_dependency.rb +6 -8
- data/lib/active_record/associations/nested_error.rb +47 -0
- data/lib/active_record/associations/preloader/association.rb +2 -1
- data/lib/active_record/associations/preloader/branch.rb +7 -1
- data/lib/active_record/associations/preloader/through_association.rb +1 -3
- data/lib/active_record/associations/singular_association.rb +6 -0
- data/lib/active_record/associations/through_association.rb +1 -1
- data/lib/active_record/associations.rb +34 -273
- data/lib/active_record/attribute_assignment.rb +1 -11
- data/lib/active_record/attribute_methods/composite_primary_key.rb +84 -0
- data/lib/active_record/attribute_methods/dirty.rb +2 -2
- data/lib/active_record/attribute_methods/primary_key.rb +23 -55
- data/lib/active_record/attribute_methods/read.rb +4 -16
- data/lib/active_record/attribute_methods/serialization.rb +4 -24
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +7 -6
- data/lib/active_record/attribute_methods/write.rb +3 -3
- data/lib/active_record/attribute_methods.rb +89 -58
- data/lib/active_record/attributes.rb +60 -45
- data/lib/active_record/autosave_association.rb +17 -31
- data/lib/active_record/base.rb +2 -3
- data/lib/active_record/connection_adapters/abstract/connection_handler.rb +24 -107
- data/lib/active_record/connection_adapters/abstract/connection_pool/reaper.rb +1 -0
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +244 -58
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +35 -18
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +188 -75
- data/lib/active_record/connection_adapters/abstract/quoting.rb +65 -91
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +1 -1
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +22 -9
- data/lib/active_record/connection_adapters/abstract/transaction.rb +125 -62
- data/lib/active_record/connection_adapters/abstract_adapter.rb +38 -59
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +69 -19
- data/lib/active_record/connection_adapters/mysql/database_statements.rb +9 -1
- data/lib/active_record/connection_adapters/mysql/quoting.rb +43 -48
- data/lib/active_record/connection_adapters/mysql/schema_statements.rb +8 -1
- data/lib/active_record/connection_adapters/mysql2/database_statements.rb +16 -15
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +20 -32
- data/lib/active_record/connection_adapters/pool_config.rb +7 -6
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +27 -4
- data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +6 -0
- data/lib/active_record/connection_adapters/postgresql/oid/interval.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +14 -4
- data/lib/active_record/connection_adapters/postgresql/quoting.rb +58 -58
- data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +20 -0
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +16 -12
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +26 -21
- data/lib/active_record/connection_adapters/schema_cache.rb +123 -128
- data/lib/active_record/connection_adapters/sqlite3/column.rb +14 -1
- data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +10 -6
- data/lib/active_record/connection_adapters/sqlite3/quoting.rb +44 -46
- data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +22 -0
- data/lib/active_record/connection_adapters/sqlite3/schema_definitions.rb +13 -0
- data/lib/active_record/connection_adapters/sqlite3/schema_dumper.rb +16 -0
- data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +25 -2
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +127 -77
- data/lib/active_record/connection_adapters/trilogy/database_statements.rb +15 -15
- data/lib/active_record/connection_adapters/trilogy_adapter.rb +32 -65
- data/lib/active_record/connection_adapters.rb +121 -0
- data/lib/active_record/connection_handling.rb +56 -41
- data/lib/active_record/core.rb +60 -39
- data/lib/active_record/counter_cache.rb +23 -10
- data/lib/active_record/database_configurations/connection_url_resolver.rb +7 -2
- data/lib/active_record/database_configurations/database_config.rb +19 -4
- data/lib/active_record/database_configurations/hash_config.rb +44 -36
- data/lib/active_record/database_configurations/url_config.rb +20 -1
- data/lib/active_record/database_configurations.rb +1 -1
- data/lib/active_record/delegated_type.rb +30 -6
- data/lib/active_record/destroy_association_async_job.rb +1 -1
- data/lib/active_record/dynamic_matchers.rb +2 -2
- data/lib/active_record/encryption/encryptable_record.rb +3 -3
- data/lib/active_record/encryption/encrypted_attribute_type.rb +26 -6
- data/lib/active_record/encryption/encryptor.rb +18 -3
- data/lib/active_record/encryption/message_pack_message_serializer.rb +76 -0
- data/lib/active_record/encryption/message_serializer.rb +4 -0
- data/lib/active_record/encryption/null_encryptor.rb +4 -0
- data/lib/active_record/encryption/read_only_null_encryptor.rb +4 -0
- data/lib/active_record/encryption/scheme.rb +8 -4
- data/lib/active_record/enum.rb +26 -6
- data/lib/active_record/errors.rb +46 -20
- data/lib/active_record/explain.rb +13 -24
- data/lib/active_record/fixtures.rb +37 -31
- data/lib/active_record/future_result.rb +17 -4
- data/lib/active_record/gem_version.rb +3 -3
- data/lib/active_record/inheritance.rb +4 -2
- data/lib/active_record/insert_all.rb +18 -15
- data/lib/active_record/integration.rb +4 -1
- data/lib/active_record/internal_metadata.rb +48 -34
- data/lib/active_record/locking/optimistic.rb +8 -7
- data/lib/active_record/log_subscriber.rb +0 -21
- data/lib/active_record/marshalling.rb +1 -1
- data/lib/active_record/message_pack.rb +2 -2
- data/lib/active_record/migration/command_recorder.rb +2 -3
- data/lib/active_record/migration/compatibility.rb +11 -3
- data/lib/active_record/migration/default_strategy.rb +4 -5
- data/lib/active_record/migration/pending_migration_connection.rb +2 -2
- data/lib/active_record/migration.rb +85 -76
- data/lib/active_record/model_schema.rb +39 -70
- data/lib/active_record/nested_attributes.rb +11 -3
- data/lib/active_record/normalization.rb +3 -7
- data/lib/active_record/persistence.rb +32 -354
- data/lib/active_record/query_cache.rb +18 -6
- data/lib/active_record/query_logs.rb +15 -0
- data/lib/active_record/query_logs_formatter.rb +1 -1
- data/lib/active_record/querying.rb +21 -9
- data/lib/active_record/railtie.rb +54 -67
- data/lib/active_record/railties/controller_runtime.rb +13 -4
- data/lib/active_record/railties/databases.rake +42 -45
- data/lib/active_record/reflection.rb +102 -37
- data/lib/active_record/relation/batches/batch_enumerator.rb +15 -2
- data/lib/active_record/relation/batches.rb +14 -8
- data/lib/active_record/relation/calculations.rb +95 -62
- data/lib/active_record/relation/delegation.rb +8 -11
- data/lib/active_record/relation/finder_methods.rb +16 -2
- data/lib/active_record/relation/merger.rb +4 -6
- data/lib/active_record/relation/predicate_builder/array_handler.rb +2 -2
- data/lib/active_record/relation/predicate_builder/association_query_value.rb +9 -3
- data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +6 -1
- data/lib/active_record/relation/predicate_builder.rb +3 -3
- data/lib/active_record/relation/query_methods.rb +212 -47
- data/lib/active_record/relation/record_fetch_warning.rb +3 -0
- data/lib/active_record/relation/spawn_methods.rb +2 -18
- data/lib/active_record/relation/where_clause.rb +7 -19
- data/lib/active_record/relation.rb +500 -66
- data/lib/active_record/result.rb +32 -45
- data/lib/active_record/runtime_registry.rb +39 -0
- data/lib/active_record/sanitization.rb +24 -19
- data/lib/active_record/schema.rb +8 -6
- data/lib/active_record/schema_dumper.rb +19 -9
- data/lib/active_record/schema_migration.rb +30 -14
- data/lib/active_record/scoping/named.rb +1 -0
- data/lib/active_record/signed_id.rb +20 -1
- data/lib/active_record/statement_cache.rb +7 -7
- data/lib/active_record/table_metadata.rb +1 -10
- data/lib/active_record/tasks/database_tasks.rb +87 -48
- data/lib/active_record/tasks/mysql_database_tasks.rb +1 -1
- data/lib/active_record/tasks/postgresql_database_tasks.rb +1 -1
- data/lib/active_record/tasks/sqlite_database_tasks.rb +2 -1
- data/lib/active_record/test_fixtures.rb +87 -89
- data/lib/active_record/testing/query_assertions.rb +121 -0
- data/lib/active_record/timestamp.rb +5 -3
- data/lib/active_record/token_for.rb +22 -12
- data/lib/active_record/touch_later.rb +1 -1
- data/lib/active_record/transaction.rb +132 -0
- data/lib/active_record/transactions.rb +70 -14
- data/lib/active_record/translation.rb +0 -2
- data/lib/active_record/type/serialized.rb +1 -3
- data/lib/active_record/type_caster/connection.rb +4 -4
- data/lib/active_record/validations/associated.rb +9 -3
- data/lib/active_record/validations/uniqueness.rb +14 -10
- data/lib/active_record/validations.rb +4 -1
- data/lib/active_record.rb +150 -41
- data/lib/arel/alias_predication.rb +1 -1
- data/lib/arel/collectors/bind.rb +2 -0
- data/lib/arel/collectors/composite.rb +7 -0
- data/lib/arel/collectors/sql_string.rb +1 -1
- data/lib/arel/collectors/substitute_binds.rb +1 -1
- data/lib/arel/nodes/binary.rb +0 -6
- data/lib/arel/nodes/bound_sql_literal.rb +9 -5
- data/lib/arel/nodes/{and.rb → nary.rb} +5 -2
- data/lib/arel/nodes/node.rb +4 -3
- data/lib/arel/nodes/sql_literal.rb +7 -0
- data/lib/arel/nodes.rb +2 -2
- data/lib/arel/predications.rb +1 -1
- data/lib/arel/select_manager.rb +1 -1
- data/lib/arel/tree_manager.rb +8 -3
- data/lib/arel/update_manager.rb +2 -1
- data/lib/arel/visitors/dot.rb +1 -0
- data/lib/arel/visitors/mysql.rb +9 -4
- data/lib/arel/visitors/postgresql.rb +1 -12
- data/lib/arel/visitors/to_sql.rb +31 -17
- data/lib/arel.rb +7 -3
- data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb.tt +4 -1
- metadata +18 -12
@@ -21,7 +21,7 @@ module ActiveRecord
|
|
21
21
|
# For example the following migration is not reversible.
|
22
22
|
# Rolling back this migration will raise an ActiveRecord::IrreversibleMigration error.
|
23
23
|
#
|
24
|
-
# class IrreversibleMigrationExample < ActiveRecord::Migration[7.
|
24
|
+
# class IrreversibleMigrationExample < ActiveRecord::Migration[7.2]
|
25
25
|
# def change
|
26
26
|
# create_table :distributors do |t|
|
27
27
|
# t.string :zipcode
|
@@ -39,7 +39,7 @@ module ActiveRecord
|
|
39
39
|
#
|
40
40
|
# 1. Define <tt>#up</tt> and <tt>#down</tt> methods instead of <tt>#change</tt>:
|
41
41
|
#
|
42
|
-
# class ReversibleMigrationExample < ActiveRecord::Migration[7.
|
42
|
+
# class ReversibleMigrationExample < ActiveRecord::Migration[7.2]
|
43
43
|
# def up
|
44
44
|
# create_table :distributors do |t|
|
45
45
|
# t.string :zipcode
|
@@ -64,7 +64,7 @@ module ActiveRecord
|
|
64
64
|
#
|
65
65
|
# 2. Use the #reversible method in <tt>#change</tt> method:
|
66
66
|
#
|
67
|
-
# class ReversibleMigrationExample < ActiveRecord::Migration[7.
|
67
|
+
# class ReversibleMigrationExample < ActiveRecord::Migration[7.2]
|
68
68
|
# def change
|
69
69
|
# create_table :distributors do |t|
|
70
70
|
# t.string :zipcode
|
@@ -131,6 +131,22 @@ module ActiveRecord
|
|
131
131
|
end
|
132
132
|
end
|
133
133
|
|
134
|
+
class InvalidMigrationTimestampError < MigrationError # :nodoc:
|
135
|
+
def initialize(version = nil, name = nil)
|
136
|
+
if version && name
|
137
|
+
super(<<~MSG)
|
138
|
+
Invalid timestamp #{version} for migration file: #{name}.
|
139
|
+
Timestamp must be in form YYYYMMDDHHMMSS, and less than #{(Time.now.utc + 1.day).strftime("%Y%m%d%H%M%S")}.
|
140
|
+
MSG
|
141
|
+
else
|
142
|
+
super(<<~MSG)
|
143
|
+
Invalid timestamp for migration.
|
144
|
+
Timestamp must be in form YYYYMMDDHHMMSS, and less than #{(Time.now.utc + 1.day).strftime("%Y%m%d%H%M%S")}.
|
145
|
+
MSG
|
146
|
+
end
|
147
|
+
end
|
148
|
+
end
|
149
|
+
|
134
150
|
class PendingMigrationError < MigrationError # :nodoc:
|
135
151
|
include ActiveSupport::ActionableError
|
136
152
|
|
@@ -145,8 +161,7 @@ module ActiveRecord
|
|
145
161
|
|
146
162
|
def initialize(message = nil, pending_migrations: nil)
|
147
163
|
if pending_migrations.nil?
|
148
|
-
|
149
|
-
pending_migrations = connection.migration_context.open.pending_migrations
|
164
|
+
pending_migrations = connection_pool.migration_context.open.pending_migrations
|
150
165
|
end
|
151
166
|
|
152
167
|
super(message || detailed_migration_message(pending_migrations))
|
@@ -167,8 +182,8 @@ module ActiveRecord
|
|
167
182
|
message
|
168
183
|
end
|
169
184
|
|
170
|
-
def
|
171
|
-
ActiveRecord::Tasks::DatabaseTasks.
|
185
|
+
def connection_pool
|
186
|
+
ActiveRecord::Tasks::DatabaseTasks.migration_connection_pool
|
172
187
|
end
|
173
188
|
end
|
174
189
|
|
@@ -235,7 +250,7 @@ module ActiveRecord
|
|
235
250
|
#
|
236
251
|
# Example of a simple migration:
|
237
252
|
#
|
238
|
-
# class AddSsl < ActiveRecord::Migration[7.
|
253
|
+
# class AddSsl < ActiveRecord::Migration[7.2]
|
239
254
|
# def up
|
240
255
|
# add_column :accounts, :ssl_enabled, :boolean, default: true
|
241
256
|
# end
|
@@ -255,7 +270,7 @@ module ActiveRecord
|
|
255
270
|
#
|
256
271
|
# Example of a more complex migration that also needs to initialize data:
|
257
272
|
#
|
258
|
-
# class AddSystemSettings < ActiveRecord::Migration[7.
|
273
|
+
# class AddSystemSettings < ActiveRecord::Migration[7.2]
|
259
274
|
# def up
|
260
275
|
# create_table :system_settings do |t|
|
261
276
|
# t.string :name
|
@@ -384,7 +399,7 @@ module ActiveRecord
|
|
384
399
|
# $ bin/rails generate migration add_fieldname_to_tablename fieldname:string
|
385
400
|
#
|
386
401
|
# This will generate the file <tt>timestamp_add_fieldname_to_tablename.rb</tt>, which will look like this:
|
387
|
-
# class AddFieldnameToTablename < ActiveRecord::Migration[7.
|
402
|
+
# class AddFieldnameToTablename < ActiveRecord::Migration[7.2]
|
388
403
|
# def change
|
389
404
|
# add_column :tablenames, :fieldname, :string
|
390
405
|
# end
|
@@ -410,7 +425,7 @@ module ActiveRecord
|
|
410
425
|
#
|
411
426
|
# Not all migrations change the schema. Some just fix the data:
|
412
427
|
#
|
413
|
-
# class RemoveEmptyTags < ActiveRecord::Migration[7.
|
428
|
+
# class RemoveEmptyTags < ActiveRecord::Migration[7.2]
|
414
429
|
# def up
|
415
430
|
# Tag.all.each { |tag| tag.destroy if tag.pages.empty? }
|
416
431
|
# end
|
@@ -423,7 +438,7 @@ module ActiveRecord
|
|
423
438
|
#
|
424
439
|
# Others remove columns when they migrate up instead of down:
|
425
440
|
#
|
426
|
-
# class RemoveUnnecessaryItemAttributes < ActiveRecord::Migration[7.
|
441
|
+
# class RemoveUnnecessaryItemAttributes < ActiveRecord::Migration[7.2]
|
427
442
|
# def up
|
428
443
|
# remove_column :items, :incomplete_items_count
|
429
444
|
# remove_column :items, :completed_items_count
|
@@ -437,7 +452,7 @@ module ActiveRecord
|
|
437
452
|
#
|
438
453
|
# And sometimes you need to do something in SQL not abstracted directly by migrations:
|
439
454
|
#
|
440
|
-
# class MakeJoinUnique < ActiveRecord::Migration[7.
|
455
|
+
# class MakeJoinUnique < ActiveRecord::Migration[7.2]
|
441
456
|
# def up
|
442
457
|
# execute "ALTER TABLE `pages_linked_pages` ADD UNIQUE `page_id_linked_page_id` (`page_id`,`linked_page_id`)"
|
443
458
|
# end
|
@@ -454,7 +469,7 @@ module ActiveRecord
|
|
454
469
|
# <tt>Base#reset_column_information</tt> in order to ensure that the model has the
|
455
470
|
# latest column data from after the new column was added. Example:
|
456
471
|
#
|
457
|
-
# class AddPeopleSalary < ActiveRecord::Migration[7.
|
472
|
+
# class AddPeopleSalary < ActiveRecord::Migration[7.2]
|
458
473
|
# def up
|
459
474
|
# add_column :people, :salary, :integer
|
460
475
|
# Person.reset_column_information
|
@@ -470,7 +485,7 @@ module ActiveRecord
|
|
470
485
|
# them to the console as they happen, along with benchmarks describing how
|
471
486
|
# long each step took.
|
472
487
|
#
|
473
|
-
# You can quiet them down by setting ActiveRecord::Migration.verbose = false
|
488
|
+
# You can quiet them down by setting <tt>ActiveRecord::Migration.verbose = false</tt>.
|
474
489
|
#
|
475
490
|
# You can also insert your own messages and benchmarks by using the +say_with_time+
|
476
491
|
# method:
|
@@ -494,7 +509,11 @@ module ActiveRecord
|
|
494
509
|
#
|
495
510
|
# 20080717013526_your_migration_name.rb
|
496
511
|
#
|
497
|
-
# The prefix is a generation timestamp (in UTC).
|
512
|
+
# The prefix is a generation timestamp (in UTC). Timestamps should not be
|
513
|
+
# modified manually. To validate that migration timestamps adhere to the
|
514
|
+
# format Active Record expects, you can use the following configuration option:
|
515
|
+
#
|
516
|
+
# config.active_record.validate_migration_timestamps = true
|
498
517
|
#
|
499
518
|
# If you'd prefer to use numeric prefixes, you can turn timestamped migrations
|
500
519
|
# off by setting:
|
@@ -512,7 +531,7 @@ module ActiveRecord
|
|
512
531
|
# To define a reversible migration, define the +change+ method in your
|
513
532
|
# migration like this:
|
514
533
|
#
|
515
|
-
# class TenderloveMigration < ActiveRecord::Migration[7.
|
534
|
+
# class TenderloveMigration < ActiveRecord::Migration[7.2]
|
516
535
|
# def change
|
517
536
|
# create_table(:horses) do |t|
|
518
537
|
# t.column :content, :text
|
@@ -542,7 +561,7 @@ module ActiveRecord
|
|
542
561
|
# can't execute inside a transaction though, and for these situations
|
543
562
|
# you can turn the automatic transactions off.
|
544
563
|
#
|
545
|
-
# class ChangeEnum < ActiveRecord::Migration[7.
|
564
|
+
# class ChangeEnum < ActiveRecord::Migration[7.2]
|
546
565
|
# disable_ddl_transaction!
|
547
566
|
#
|
548
567
|
# def up
|
@@ -676,30 +695,13 @@ module ActiveRecord
|
|
676
695
|
delegate || superclass.nearest_delegate
|
677
696
|
end
|
678
697
|
|
679
|
-
# Raises ActiveRecord::PendingMigrationError error if any migrations are pending.
|
680
|
-
#
|
681
|
-
# This is deprecated in favor of +check_all_pending!+
|
682
|
-
def check_pending!(connection = ActiveRecord::Tasks::DatabaseTasks.migration_connection)
|
683
|
-
ActiveRecord.deprecator.warn(<<-MSG.squish)
|
684
|
-
The `check_pending!` method is deprecated in favor of `check_all_pending!`. The
|
685
|
-
new implementation will loop through all available database configurations and find
|
686
|
-
pending migrations. The prior implementation did not permit this.
|
687
|
-
MSG
|
688
|
-
|
689
|
-
pending_migrations = connection.migration_context.open.pending_migrations
|
690
|
-
|
691
|
-
if pending_migrations.any?
|
692
|
-
raise ActiveRecord::PendingMigrationError.new(pending_migrations: pending_migrations)
|
693
|
-
end
|
694
|
-
end
|
695
|
-
|
696
698
|
# Raises ActiveRecord::PendingMigrationError error if any migrations are pending
|
697
699
|
# for all database configurations in an environment.
|
698
700
|
def check_all_pending!
|
699
701
|
pending_migrations = []
|
700
702
|
|
701
|
-
ActiveRecord::Tasks::DatabaseTasks.
|
702
|
-
if pending =
|
703
|
+
ActiveRecord::Tasks::DatabaseTasks.with_temporary_pool_for_each(env: env) do |pool|
|
704
|
+
if pending = pool.migration_context.open.pending_migrations
|
703
705
|
pending_migrations << pending
|
704
706
|
end
|
705
707
|
end
|
@@ -731,10 +733,9 @@ module ActiveRecord
|
|
731
733
|
end
|
732
734
|
end
|
733
735
|
|
734
|
-
def method_missing(name,
|
735
|
-
nearest_delegate.send(name,
|
736
|
+
def method_missing(name, ...) # :nodoc:
|
737
|
+
nearest_delegate.send(name, ...)
|
736
738
|
end
|
737
|
-
ruby2_keywords(:method_missing)
|
738
739
|
|
739
740
|
def migrate(direction)
|
740
741
|
new.migrate direction
|
@@ -771,8 +772,8 @@ module ActiveRecord
|
|
771
772
|
pending_migrations = []
|
772
773
|
|
773
774
|
ActiveRecord::Base.configurations.configs_for(env_name: env).each do |db_config|
|
774
|
-
ActiveRecord::PendingMigrationConnection.
|
775
|
-
if pending =
|
775
|
+
ActiveRecord::PendingMigrationConnection.with_temporary_pool(db_config) do |pool|
|
776
|
+
if pending = pool.migration_context.open.pending_migrations
|
776
777
|
pending_migrations << pending
|
777
778
|
end
|
778
779
|
end
|
@@ -790,6 +791,12 @@ module ActiveRecord
|
|
790
791
|
self.class.disable_ddl_transaction
|
791
792
|
end
|
792
793
|
|
794
|
+
##
|
795
|
+
# :singleton-method: verbose
|
796
|
+
#
|
797
|
+
# Specifies if migrations will write the actions they are taking to the console as they
|
798
|
+
# happen, along with benchmarks describing how long each step took. Defaults to
|
799
|
+
# true.
|
793
800
|
cattr_accessor :verbose
|
794
801
|
attr_accessor :name, :version
|
795
802
|
|
@@ -797,6 +804,7 @@ module ActiveRecord
|
|
797
804
|
@name = name
|
798
805
|
@version = version
|
799
806
|
@connection = nil
|
807
|
+
@pool = nil
|
800
808
|
end
|
801
809
|
|
802
810
|
def execution_strategy
|
@@ -814,7 +822,7 @@ module ActiveRecord
|
|
814
822
|
# and create the table 'apples' on the way up, and the reverse
|
815
823
|
# on the way down.
|
816
824
|
#
|
817
|
-
# class FixTLMigration < ActiveRecord::Migration[7.
|
825
|
+
# class FixTLMigration < ActiveRecord::Migration[7.2]
|
818
826
|
# def change
|
819
827
|
# revert do
|
820
828
|
# create_table(:horses) do |t|
|
@@ -833,7 +841,7 @@ module ActiveRecord
|
|
833
841
|
#
|
834
842
|
# require_relative "20121212123456_tenderlove_migration"
|
835
843
|
#
|
836
|
-
# class FixupTLMigration < ActiveRecord::Migration[7.
|
844
|
+
# class FixupTLMigration < ActiveRecord::Migration[7.2]
|
837
845
|
# def change
|
838
846
|
# revert TenderloveMigration
|
839
847
|
#
|
@@ -884,7 +892,7 @@ module ActiveRecord
|
|
884
892
|
# when the three columns 'first_name', 'last_name' and 'full_name' exist,
|
885
893
|
# even when migrating down:
|
886
894
|
#
|
887
|
-
# class SplitNameMigration < ActiveRecord::Migration[7.
|
895
|
+
# class SplitNameMigration < ActiveRecord::Migration[7.2]
|
888
896
|
# def change
|
889
897
|
# add_column :users, :first_name, :string
|
890
898
|
# add_column :users, :last_name, :string
|
@@ -912,7 +920,7 @@ module ActiveRecord
|
|
912
920
|
# In the following example, the new column +published+ will be given
|
913
921
|
# the value +true+ for all existing records.
|
914
922
|
#
|
915
|
-
# class AddPublishedToPosts < ActiveRecord::Migration[7.
|
923
|
+
# class AddPublishedToPosts < ActiveRecord::Migration[7.2]
|
916
924
|
# def change
|
917
925
|
# add_column :posts, :published, :boolean, default: false
|
918
926
|
# up_only do
|
@@ -1032,6 +1040,10 @@ module ActiveRecord
|
|
1032
1040
|
@connection || ActiveRecord::Tasks::DatabaseTasks.migration_connection
|
1033
1041
|
end
|
1034
1042
|
|
1043
|
+
def connection_pool
|
1044
|
+
@pool || ActiveRecord::Tasks::DatabaseTasks.migration_connection_pool
|
1045
|
+
end
|
1046
|
+
|
1035
1047
|
def method_missing(method, *arguments, &block)
|
1036
1048
|
say_with_time "#{method}(#{format_arguments(arguments)})" do
|
1037
1049
|
unless connection.respond_to? :revert
|
@@ -1203,31 +1215,9 @@ module ActiveRecord
|
|
1203
1215
|
attr_reader :migrations_paths, :schema_migration, :internal_metadata
|
1204
1216
|
|
1205
1217
|
def initialize(migrations_paths, schema_migration = nil, internal_metadata = nil)
|
1206
|
-
if schema_migration == SchemaMigration
|
1207
|
-
ActiveRecord.deprecator.warn(<<-MSG.squish)
|
1208
|
-
SchemaMigration no longer inherits from ActiveRecord::Base. If you want
|
1209
|
-
to use the default connection, remove this argument. If you want to use a
|
1210
|
-
specific connection, instantiate MigrationContext with the connection's schema
|
1211
|
-
migration, for example `MigrationContext.new(path, Dog.connection.schema_migration)`.
|
1212
|
-
MSG
|
1213
|
-
|
1214
|
-
schema_migration = nil
|
1215
|
-
end
|
1216
|
-
|
1217
|
-
if internal_metadata == InternalMetadata
|
1218
|
-
ActiveRecord.deprecator.warn(<<-MSG.squish)
|
1219
|
-
SchemaMigration no longer inherits from ActiveRecord::Base. If you want
|
1220
|
-
to use the default connection, remove this argument. If you want to use a
|
1221
|
-
specific connection, instantiate MigrationContext with the connection's internal
|
1222
|
-
metadata, for example `MigrationContext.new(path, nil, Dog.connection.internal_metadata)`.
|
1223
|
-
MSG
|
1224
|
-
|
1225
|
-
internal_metadata = nil
|
1226
|
-
end
|
1227
|
-
|
1228
1218
|
@migrations_paths = migrations_paths
|
1229
|
-
@schema_migration = schema_migration || SchemaMigration.new(
|
1230
|
-
@internal_metadata = internal_metadata || InternalMetadata.new(
|
1219
|
+
@schema_migration = schema_migration || SchemaMigration.new(connection_pool)
|
1220
|
+
@internal_metadata = internal_metadata || InternalMetadata.new(connection_pool)
|
1231
1221
|
end
|
1232
1222
|
|
1233
1223
|
# Runs the migrations in the +migrations_path+.
|
@@ -1317,6 +1307,9 @@ module ActiveRecord
|
|
1317
1307
|
migrations = migration_files.map do |file|
|
1318
1308
|
version, name, scope = parse_migration_filename(file)
|
1319
1309
|
raise IllegalMigrationNameError.new(file) unless version
|
1310
|
+
if validate_timestamp? && !valid_migration_timestamp?(version)
|
1311
|
+
raise InvalidMigrationTimestampError.new(version, name)
|
1312
|
+
end
|
1320
1313
|
version = version.to_i
|
1321
1314
|
name = name.camelize
|
1322
1315
|
|
@@ -1332,6 +1325,9 @@ module ActiveRecord
|
|
1332
1325
|
file_list = migration_files.filter_map do |file|
|
1333
1326
|
version, name, scope = parse_migration_filename(file)
|
1334
1327
|
raise IllegalMigrationNameError.new(file) unless version
|
1328
|
+
if validate_timestamp? && !valid_migration_timestamp?(version)
|
1329
|
+
raise InvalidMigrationTimestampError.new(version, name)
|
1330
|
+
end
|
1335
1331
|
version = schema_migration.normalize_migration_number(version)
|
1336
1332
|
status = db_list.delete(version) ? "up" : "down"
|
1337
1333
|
[status, version, (name + scope).humanize]
|
@@ -1353,11 +1349,12 @@ module ActiveRecord
|
|
1353
1349
|
end
|
1354
1350
|
|
1355
1351
|
def last_stored_environment # :nodoc:
|
1356
|
-
|
1352
|
+
internal_metadata = connection_pool.internal_metadata
|
1353
|
+
return nil unless internal_metadata.enabled?
|
1357
1354
|
return nil if current_version == 0
|
1358
|
-
raise NoEnvironmentInSchemaError unless
|
1355
|
+
raise NoEnvironmentInSchemaError unless internal_metadata.table_exists?
|
1359
1356
|
|
1360
|
-
environment =
|
1357
|
+
environment = internal_metadata[:environment]
|
1361
1358
|
raise NoEnvironmentInSchemaError unless environment
|
1362
1359
|
environment
|
1363
1360
|
end
|
@@ -1367,6 +1364,10 @@ module ActiveRecord
|
|
1367
1364
|
ActiveRecord::Tasks::DatabaseTasks.migration_connection
|
1368
1365
|
end
|
1369
1366
|
|
1367
|
+
def connection_pool
|
1368
|
+
ActiveRecord::Tasks::DatabaseTasks.migration_connection_pool
|
1369
|
+
end
|
1370
|
+
|
1370
1371
|
def migration_files
|
1371
1372
|
paths = Array(migrations_paths)
|
1372
1373
|
Dir[*paths.flat_map { |path| "#{path}/**/[0-9]*_*.rb" }]
|
@@ -1376,6 +1377,14 @@ module ActiveRecord
|
|
1376
1377
|
File.basename(filename).scan(Migration::MigrationFilenameRegexp).first
|
1377
1378
|
end
|
1378
1379
|
|
1380
|
+
def validate_timestamp?
|
1381
|
+
ActiveRecord.timestamped_migrations && ActiveRecord.validate_migration_timestamps
|
1382
|
+
end
|
1383
|
+
|
1384
|
+
def valid_migration_timestamp?(version)
|
1385
|
+
version.to_i < (Time.now.utc + 1.day).strftime("%Y%m%d%H%M%S").to_i
|
1386
|
+
end
|
1387
|
+
|
1379
1388
|
def move(direction, steps)
|
1380
1389
|
migrator = Migrator.new(direction, migrations, schema_migration, internal_metadata)
|
1381
1390
|
|
@@ -1402,9 +1411,9 @@ module ActiveRecord
|
|
1402
1411
|
|
1403
1412
|
# For cases where a table doesn't exist like loading from schema cache
|
1404
1413
|
def current_version
|
1405
|
-
|
1406
|
-
schema_migration = SchemaMigration.new(
|
1407
|
-
internal_metadata = InternalMetadata.new(
|
1414
|
+
connection_pool = ActiveRecord::Tasks::DatabaseTasks.migration_connection_pool
|
1415
|
+
schema_migration = SchemaMigration.new(connection_pool)
|
1416
|
+
internal_metadata = InternalMetadata.new(connection_pool)
|
1408
1417
|
|
1409
1418
|
MigrationContext.new(migrations_paths, schema_migration, internal_metadata).current_version
|
1410
1419
|
end
|
@@ -146,6 +146,11 @@ module ActiveRecord
|
|
146
146
|
# your own model for something else, you can set +inheritance_column+:
|
147
147
|
#
|
148
148
|
# self.inheritance_column = 'zoink'
|
149
|
+
#
|
150
|
+
# If you wish to disable single-table inheritance altogether you can set
|
151
|
+
# +inheritance_column+ to +nil+
|
152
|
+
#
|
153
|
+
# self.inheritance_column = nil
|
149
154
|
|
150
155
|
##
|
151
156
|
# :singleton-method: inheritance_column=
|
@@ -273,13 +278,13 @@ module ActiveRecord
|
|
273
278
|
@table_name = value
|
274
279
|
@quoted_table_name = nil
|
275
280
|
@arel_table = nil
|
276
|
-
@sequence_name = nil unless
|
281
|
+
@sequence_name = nil unless @explicit_sequence_name
|
277
282
|
@predicate_builder = nil
|
278
283
|
end
|
279
284
|
|
280
285
|
# Returns a quoted version of the table name, used to construct SQL statements.
|
281
286
|
def quoted_table_name
|
282
|
-
@quoted_table_name ||=
|
287
|
+
@quoted_table_name ||= adapter_class.quote_table_name(table_name)
|
283
288
|
end
|
284
289
|
|
285
290
|
# Computes the table name, (re)sets it internally, and returns it.
|
@@ -374,7 +379,7 @@ module ActiveRecord
|
|
374
379
|
|
375
380
|
def reset_sequence_name # :nodoc:
|
376
381
|
@explicit_sequence_name = false
|
377
|
-
@sequence_name =
|
382
|
+
@sequence_name = with_connection { |c| c.default_sequence_name(table_name, primary_key) }
|
378
383
|
end
|
379
384
|
|
380
385
|
# Sets the name of the sequence to use when generating ids to the given
|
@@ -399,75 +404,51 @@ module ActiveRecord
|
|
399
404
|
# Determines if the primary key values should be selected from their
|
400
405
|
# corresponding sequence before the insert statement.
|
401
406
|
def prefetch_primary_key?
|
402
|
-
|
407
|
+
with_connection { |c| c.prefetch_primary_key?(table_name) }
|
403
408
|
end
|
404
409
|
|
405
410
|
# Returns the next value that will be used as the primary key on
|
406
411
|
# an insert statement.
|
407
412
|
def next_sequence_value
|
408
|
-
|
413
|
+
with_connection { |c| c.next_sequence_value(sequence_name) }
|
409
414
|
end
|
410
415
|
|
411
416
|
# Indicates whether the table associated with this class exists
|
412
417
|
def table_exists?
|
413
|
-
|
418
|
+
schema_cache.data_source_exists?(table_name)
|
414
419
|
end
|
415
420
|
|
416
421
|
def attributes_builder # :nodoc:
|
417
|
-
|
422
|
+
@attributes_builder ||= begin
|
418
423
|
defaults = _default_attributes.except(*(column_names - [primary_key]))
|
419
|
-
|
424
|
+
ActiveModel::AttributeSet::Builder.new(attribute_types, defaults)
|
420
425
|
end
|
421
|
-
@attributes_builder
|
422
426
|
end
|
423
427
|
|
424
428
|
def columns_hash # :nodoc:
|
425
|
-
load_schema
|
429
|
+
load_schema unless @columns_hash
|
426
430
|
@columns_hash
|
427
431
|
end
|
428
432
|
|
429
433
|
def columns
|
430
|
-
load_schema
|
434
|
+
load_schema unless @columns
|
431
435
|
@columns ||= columns_hash.values.freeze
|
432
436
|
end
|
433
437
|
|
434
|
-
def _returning_columns_for_insert # :nodoc:
|
435
|
-
@_returning_columns_for_insert ||=
|
436
|
-
|
437
|
-
|
438
|
-
|
438
|
+
def _returning_columns_for_insert(connection) # :nodoc:
|
439
|
+
@_returning_columns_for_insert ||= begin
|
440
|
+
auto_populated_columns = columns.filter_map do |c|
|
441
|
+
c.name if connection.return_value_after_insert?(c)
|
442
|
+
end
|
439
443
|
|
440
|
-
|
441
|
-
|
442
|
-
@attribute_types ||= Hash.new(Type.default_value)
|
444
|
+
auto_populated_columns.empty? ? Array(primary_key) : auto_populated_columns
|
445
|
+
end
|
443
446
|
end
|
444
447
|
|
445
448
|
def yaml_encoder # :nodoc:
|
446
449
|
@yaml_encoder ||= ActiveModel::AttributeSet::YAMLEncoder.new(attribute_types)
|
447
450
|
end
|
448
451
|
|
449
|
-
# Returns the type of the attribute with the given name, after applying
|
450
|
-
# all modifiers. This method is the only valid source of information for
|
451
|
-
# anything related to the types of a model's attributes. This method will
|
452
|
-
# access the database and load the model's schema if it is required.
|
453
|
-
#
|
454
|
-
# The return value of this method will implement the interface described
|
455
|
-
# by ActiveModel::Type::Value (though the object itself may not subclass
|
456
|
-
# it).
|
457
|
-
#
|
458
|
-
# +attr_name+ The name of the attribute to retrieve the type for. Must be
|
459
|
-
# a string or a symbol.
|
460
|
-
def type_for_attribute(attr_name, &block)
|
461
|
-
attr_name = attr_name.to_s
|
462
|
-
attr_name = attribute_aliases[attr_name] || attr_name
|
463
|
-
|
464
|
-
if block
|
465
|
-
attribute_types.fetch(attr_name, &block)
|
466
|
-
else
|
467
|
-
attribute_types[attr_name]
|
468
|
-
end
|
469
|
-
end
|
470
|
-
|
471
452
|
# Returns the column object for the named attribute.
|
472
453
|
# Returns an ActiveRecord::ConnectionAdapters::NullColumn if the
|
473
454
|
# named attribute does not exist.
|
@@ -495,11 +476,6 @@ module ActiveRecord
|
|
495
476
|
@column_defaults ||= _default_attributes.deep_dup.to_hash.freeze
|
496
477
|
end
|
497
478
|
|
498
|
-
def _default_attributes # :nodoc:
|
499
|
-
load_schema
|
500
|
-
@default_attributes ||= ActiveModel::AttributeSet.new({})
|
501
|
-
end
|
502
|
-
|
503
479
|
# Returns an array of column names as strings.
|
504
480
|
def column_names
|
505
481
|
@column_names ||= columns.map(&:name).freeze
|
@@ -527,7 +503,7 @@ module ActiveRecord
|
|
527
503
|
# when just after creating a table you want to populate it with some default
|
528
504
|
# values, e.g.:
|
529
505
|
#
|
530
|
-
# class CreateJobLevels < ActiveRecord::Migration[7.
|
506
|
+
# class CreateJobLevels < ActiveRecord::Migration[7.2]
|
531
507
|
# def up
|
532
508
|
# create_table :job_levels do |t|
|
533
509
|
# t.integer :id
|
@@ -547,18 +523,20 @@ module ActiveRecord
|
|
547
523
|
# end
|
548
524
|
# end
|
549
525
|
def reset_column_information
|
550
|
-
|
526
|
+
connection_pool.active_connection&.clear_cache!
|
551
527
|
([self] + descendants).each(&:undefine_attribute_methods)
|
552
|
-
|
528
|
+
schema_cache.clear_data_source_cache!(table_name)
|
553
529
|
|
554
530
|
reload_schema_from_cache
|
555
531
|
initialize_find_by_cache
|
556
532
|
end
|
557
533
|
|
558
|
-
|
534
|
+
# Load the model's schema information either from the schema cache
|
535
|
+
# or directly from the database.
|
536
|
+
def load_schema
|
559
537
|
return if schema_loaded?
|
560
538
|
@load_schema_monitor.synchronize do
|
561
|
-
return if
|
539
|
+
return if schema_loaded?
|
562
540
|
|
563
541
|
load_schema!
|
564
542
|
|
@@ -579,9 +557,7 @@ module ActiveRecord
|
|
579
557
|
@arel_table = nil
|
580
558
|
@column_names = nil
|
581
559
|
@symbol_column_to_string_name_hash = nil
|
582
|
-
@attribute_types = nil
|
583
560
|
@content_columns = nil
|
584
|
-
@default_attributes = nil
|
585
561
|
@column_defaults = nil
|
586
562
|
@attributes_builder = nil
|
587
563
|
@columns = nil
|
@@ -607,7 +583,7 @@ module ActiveRecord
|
|
607
583
|
end
|
608
584
|
|
609
585
|
def schema_loaded?
|
610
|
-
|
586
|
+
@schema_loaded
|
611
587
|
end
|
612
588
|
|
613
589
|
def load_schema!
|
@@ -615,20 +591,11 @@ module ActiveRecord
|
|
615
591
|
raise ActiveRecord::TableNotSpecified, "#{self} has no table configured. Set one with #{self}.table_name="
|
616
592
|
end
|
617
593
|
|
618
|
-
columns_hash =
|
594
|
+
columns_hash = schema_cache.columns_hash(table_name)
|
619
595
|
columns_hash = columns_hash.except(*ignored_columns) unless ignored_columns.empty?
|
620
596
|
@columns_hash = columns_hash.freeze
|
621
|
-
|
622
|
-
|
623
|
-
type = _convert_type_from_options(type)
|
624
|
-
define_attribute(
|
625
|
-
name,
|
626
|
-
type,
|
627
|
-
default: column.default,
|
628
|
-
user_provided_default: false
|
629
|
-
)
|
630
|
-
alias_attribute :id_value, :id if name == "id"
|
631
|
-
end
|
597
|
+
|
598
|
+
super
|
632
599
|
end
|
633
600
|
|
634
601
|
# Guesses the table name, but does not decorate it with prefix and suffix information.
|
@@ -654,12 +621,14 @@ module ActiveRecord
|
|
654
621
|
end
|
655
622
|
end
|
656
623
|
|
657
|
-
def
|
624
|
+
def type_for_column(connection, column)
|
625
|
+
type = connection.lookup_cast_type_from_column(column)
|
626
|
+
|
658
627
|
if immutable_strings_by_default && type.respond_to?(:to_immutable_string)
|
659
|
-
type.to_immutable_string
|
660
|
-
else
|
661
|
-
type
|
628
|
+
type = type.to_immutable_string
|
662
629
|
end
|
630
|
+
|
631
|
+
type
|
663
632
|
end
|
664
633
|
end
|
665
634
|
end
|
@@ -421,10 +421,15 @@ module ActiveRecord
|
|
421
421
|
# update_only is true, and a <tt>:_destroy</tt> key set to a truthy value,
|
422
422
|
# then the existing record will be marked for destruction.
|
423
423
|
def assign_nested_attributes_for_one_to_one_association(association_name, attributes)
|
424
|
-
options = nested_attributes_options[association_name]
|
425
424
|
if attributes.respond_to?(:permitted?)
|
426
425
|
attributes = attributes.to_h
|
427
426
|
end
|
427
|
+
|
428
|
+
unless attributes.is_a?(Hash)
|
429
|
+
raise ArgumentError, "Hash expected for `#{association_name}` attributes, got #{attributes.class.name}"
|
430
|
+
end
|
431
|
+
|
432
|
+
options = nested_attributes_options[association_name]
|
428
433
|
attributes = attributes.with_indifferent_access
|
429
434
|
existing_record = send(association_name)
|
430
435
|
|
@@ -486,7 +491,7 @@ module ActiveRecord
|
|
486
491
|
end
|
487
492
|
|
488
493
|
unless attributes_collection.is_a?(Hash) || attributes_collection.is_a?(Array)
|
489
|
-
raise ArgumentError, "Hash or Array expected for
|
494
|
+
raise ArgumentError, "Hash or Array expected for `#{association_name}` attributes, got #{attributes_collection.class.name}"
|
490
495
|
end
|
491
496
|
|
492
497
|
check_record_limit!(options[:limit], attributes_collection)
|
@@ -509,7 +514,7 @@ module ActiveRecord
|
|
509
514
|
attribute_ids.empty? ? [] : association.scope.where(association.klass.primary_key => attribute_ids)
|
510
515
|
end
|
511
516
|
|
512
|
-
attributes_collection.
|
517
|
+
records = attributes_collection.map do |attributes|
|
513
518
|
if attributes.respond_to?(:permitted?)
|
514
519
|
attributes = attributes.to_h
|
515
520
|
end
|
@@ -532,11 +537,14 @@ module ActiveRecord
|
|
532
537
|
end
|
533
538
|
|
534
539
|
assign_to_or_mark_for_destruction(existing_record, attributes, options[:allow_destroy])
|
540
|
+
existing_record
|
535
541
|
end
|
536
542
|
else
|
537
543
|
raise_nested_attributes_record_not_found!(association_name, attributes["id"])
|
538
544
|
end
|
539
545
|
end
|
546
|
+
|
547
|
+
association.nested_attributes_target = records
|
540
548
|
end
|
541
549
|
|
542
550
|
# Takes in a limit and checks if the attributes_collection has too many
|