activerecord 7.0.8.1 → 7.2.2.1
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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +642 -1925
- data/MIT-LICENSE +1 -1
- data/README.rdoc +29 -29
- data/examples/performance.rb +2 -2
- data/lib/active_record/aggregations.rb +16 -13
- data/lib/active_record/association_relation.rb +2 -2
- data/lib/active_record/associations/alias_tracker.rb +25 -19
- data/lib/active_record/associations/association.rb +35 -12
- data/lib/active_record/associations/association_scope.rb +16 -9
- data/lib/active_record/associations/belongs_to_association.rb +23 -8
- data/lib/active_record/associations/belongs_to_polymorphic_association.rb +3 -2
- data/lib/active_record/associations/builder/association.rb +3 -3
- data/lib/active_record/associations/builder/belongs_to.rb +22 -8
- data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +3 -7
- 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/builder/singular_association.rb +4 -0
- data/lib/active_record/associations/collection_association.rb +26 -14
- data/lib/active_record/associations/collection_proxy.rb +29 -11
- data/lib/active_record/associations/errors.rb +265 -0
- data/lib/active_record/associations/foreign_association.rb +10 -3
- data/lib/active_record/associations/has_many_association.rb +21 -14
- data/lib/active_record/associations/has_many_through_association.rb +17 -7
- data/lib/active_record/associations/has_one_association.rb +10 -3
- data/lib/active_record/associations/join_dependency/join_association.rb +30 -27
- data/lib/active_record/associations/join_dependency.rb +10 -10
- data/lib/active_record/associations/nested_error.rb +47 -0
- data/lib/active_record/associations/preloader/association.rb +33 -8
- 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/preloader.rb +13 -10
- data/lib/active_record/associations/singular_association.rb +7 -1
- data/lib/active_record/associations/through_association.rb +22 -11
- data/lib/active_record/associations.rb +354 -485
- data/lib/active_record/attribute_assignment.rb +0 -4
- data/lib/active_record/attribute_methods/before_type_cast.rb +17 -0
- data/lib/active_record/attribute_methods/composite_primary_key.rb +84 -0
- data/lib/active_record/attribute_methods/dirty.rb +53 -35
- data/lib/active_record/attribute_methods/primary_key.rb +45 -25
- data/lib/active_record/attribute_methods/query.rb +28 -16
- data/lib/active_record/attribute_methods/read.rb +8 -7
- data/lib/active_record/attribute_methods/serialization.rb +131 -32
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +11 -6
- data/lib/active_record/attribute_methods/write.rb +6 -6
- data/lib/active_record/attribute_methods.rb +148 -33
- data/lib/active_record/attributes.rb +64 -50
- data/lib/active_record/autosave_association.rb +69 -37
- data/lib/active_record/base.rb +9 -5
- data/lib/active_record/callbacks.rb +11 -25
- data/lib/active_record/coders/column_serializer.rb +61 -0
- data/lib/active_record/coders/json.rb +1 -1
- data/lib/active_record/coders/yaml_column.rb +70 -42
- data/lib/active_record/connection_adapters/abstract/connection_handler.rb +123 -131
- data/lib/active_record/connection_adapters/abstract/connection_pool/queue.rb +2 -0
- data/lib/active_record/connection_adapters/abstract/connection_pool/reaper.rb +4 -1
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +323 -88
- data/lib/active_record/connection_adapters/abstract/database_limits.rb +5 -0
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +160 -45
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +217 -63
- data/lib/active_record/connection_adapters/abstract/quoting.rb +72 -63
- data/lib/active_record/connection_adapters/abstract/savepoints.rb +4 -3
- data/lib/active_record/connection_adapters/abstract/schema_creation.rb +18 -4
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +137 -11
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +307 -129
- data/lib/active_record/connection_adapters/abstract/transaction.rb +367 -75
- data/lib/active_record/connection_adapters/abstract_adapter.rb +510 -111
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +278 -125
- data/lib/active_record/connection_adapters/column.rb +9 -0
- data/lib/active_record/connection_adapters/mysql/column.rb +1 -0
- data/lib/active_record/connection_adapters/mysql/database_statements.rb +26 -139
- data/lib/active_record/connection_adapters/mysql/quoting.rb +53 -54
- data/lib/active_record/connection_adapters/mysql/schema_creation.rb +9 -0
- data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +6 -0
- data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +1 -1
- data/lib/active_record/connection_adapters/mysql/schema_statements.rb +25 -13
- data/lib/active_record/connection_adapters/mysql2/database_statements.rb +152 -0
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +101 -68
- data/lib/active_record/connection_adapters/pool_config.rb +20 -10
- data/lib/active_record/connection_adapters/pool_manager.rb +19 -9
- data/lib/active_record/connection_adapters/postgresql/column.rb +14 -3
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +100 -43
- 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/money.rb +3 -2
- data/lib/active_record/connection_adapters/postgresql/oid/range.rb +11 -2
- data/lib/active_record/connection_adapters/postgresql/oid/timestamp_with_time_zone.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +14 -4
- data/lib/active_record/connection_adapters/postgresql/quoting.rb +65 -61
- data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +3 -9
- data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +76 -6
- data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +151 -2
- data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +53 -0
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +370 -63
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +367 -201
- data/lib/active_record/connection_adapters/schema_cache.rb +302 -79
- data/lib/active_record/connection_adapters/sqlite3/column.rb +62 -0
- data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +60 -43
- data/lib/active_record/connection_adapters/sqlite3/quoting.rb +45 -46
- data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +22 -0
- data/lib/active_record/connection_adapters/sqlite3/schema_definitions.rb +14 -0
- data/lib/active_record/connection_adapters/sqlite3/schema_dumper.rb +16 -0
- data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +50 -8
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +290 -110
- data/lib/active_record/connection_adapters/statement_pool.rb +7 -0
- data/lib/active_record/connection_adapters/trilogy/database_statements.rb +99 -0
- data/lib/active_record/connection_adapters/trilogy_adapter.rb +229 -0
- data/lib/active_record/connection_adapters.rb +124 -1
- data/lib/active_record/connection_handling.rb +96 -104
- data/lib/active_record/core.rb +251 -176
- data/lib/active_record/counter_cache.rb +68 -34
- data/lib/active_record/database_configurations/connection_url_resolver.rb +8 -3
- data/lib/active_record/database_configurations/database_config.rb +26 -5
- data/lib/active_record/database_configurations/hash_config.rb +52 -34
- data/lib/active_record/database_configurations/url_config.rb +37 -12
- data/lib/active_record/database_configurations.rb +87 -34
- data/lib/active_record/delegated_type.rb +39 -10
- data/lib/active_record/deprecator.rb +7 -0
- data/lib/active_record/destroy_association_async_job.rb +3 -1
- data/lib/active_record/dynamic_matchers.rb +2 -2
- data/lib/active_record/encryption/auto_filtered_parameters.rb +66 -0
- data/lib/active_record/encryption/cipher/aes256_gcm.rb +4 -1
- data/lib/active_record/encryption/config.rb +25 -1
- data/lib/active_record/encryption/configurable.rb +12 -19
- data/lib/active_record/encryption/context.rb +10 -3
- data/lib/active_record/encryption/contexts.rb +5 -1
- data/lib/active_record/encryption/derived_secret_key_provider.rb +8 -2
- data/lib/active_record/encryption/encryptable_record.rb +45 -21
- data/lib/active_record/encryption/encrypted_attribute_type.rb +47 -12
- data/lib/active_record/encryption/encryptor.rb +18 -3
- data/lib/active_record/encryption/extended_deterministic_queries.rb +66 -69
- data/lib/active_record/encryption/extended_deterministic_uniqueness_validator.rb +3 -3
- data/lib/active_record/encryption/key_generator.rb +12 -1
- data/lib/active_record/encryption/key_provider.rb +1 -1
- data/lib/active_record/encryption/message_pack_message_serializer.rb +76 -0
- data/lib/active_record/encryption/message_serializer.rb +6 -0
- data/lib/active_record/encryption/null_encryptor.rb +4 -0
- data/lib/active_record/encryption/properties.rb +3 -3
- data/lib/active_record/encryption/read_only_null_encryptor.rb +4 -0
- data/lib/active_record/encryption/scheme.rb +22 -21
- data/lib/active_record/encryption.rb +3 -0
- data/lib/active_record/enum.rb +129 -28
- data/lib/active_record/errors.rb +151 -31
- data/lib/active_record/explain.rb +21 -12
- data/lib/active_record/fixture_set/model_metadata.rb +14 -4
- data/lib/active_record/fixture_set/render_context.rb +2 -0
- data/lib/active_record/fixture_set/table_row.rb +29 -8
- data/lib/active_record/fixtures.rb +167 -97
- data/lib/active_record/future_result.rb +47 -8
- data/lib/active_record/gem_version.rb +3 -3
- data/lib/active_record/inheritance.rb +34 -18
- data/lib/active_record/insert_all.rb +72 -22
- data/lib/active_record/integration.rb +11 -8
- data/lib/active_record/internal_metadata.rb +124 -20
- data/lib/active_record/locking/optimistic.rb +8 -7
- data/lib/active_record/locking/pessimistic.rb +5 -2
- data/lib/active_record/log_subscriber.rb +18 -22
- data/lib/active_record/marshalling.rb +59 -0
- data/lib/active_record/message_pack.rb +124 -0
- data/lib/active_record/middleware/database_selector/resolver.rb +4 -0
- data/lib/active_record/middleware/database_selector.rb +6 -8
- data/lib/active_record/middleware/shard_selector.rb +3 -1
- data/lib/active_record/migration/command_recorder.rb +106 -8
- data/lib/active_record/migration/compatibility.rb +147 -5
- data/lib/active_record/migration/default_strategy.rb +22 -0
- data/lib/active_record/migration/execution_strategy.rb +19 -0
- data/lib/active_record/migration/pending_migration_connection.rb +21 -0
- data/lib/active_record/migration.rb +234 -117
- data/lib/active_record/model_schema.rb +90 -102
- data/lib/active_record/nested_attributes.rb +48 -11
- data/lib/active_record/normalization.rb +163 -0
- data/lib/active_record/persistence.rb +168 -339
- data/lib/active_record/promise.rb +84 -0
- data/lib/active_record/query_cache.rb +18 -25
- data/lib/active_record/query_logs.rb +92 -52
- data/lib/active_record/query_logs_formatter.rb +41 -0
- data/lib/active_record/querying.rb +33 -8
- data/lib/active_record/railtie.rb +129 -85
- data/lib/active_record/railties/controller_runtime.rb +22 -7
- data/lib/active_record/railties/databases.rake +145 -154
- data/lib/active_record/railties/job_runtime.rb +23 -0
- data/lib/active_record/readonly_attributes.rb +32 -5
- data/lib/active_record/reflection.rb +267 -69
- data/lib/active_record/relation/batches/batch_enumerator.rb +20 -5
- data/lib/active_record/relation/batches.rb +198 -63
- data/lib/active_record/relation/calculations.rb +250 -93
- data/lib/active_record/relation/delegation.rb +30 -19
- data/lib/active_record/relation/finder_methods.rb +93 -18
- data/lib/active_record/relation/merger.rb +6 -6
- data/lib/active_record/relation/predicate_builder/array_handler.rb +2 -2
- data/lib/active_record/relation/predicate_builder/association_query_value.rb +18 -3
- data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +10 -7
- data/lib/active_record/relation/predicate_builder/relation_handler.rb +5 -1
- data/lib/active_record/relation/predicate_builder.rb +28 -16
- data/lib/active_record/relation/query_attribute.rb +2 -1
- data/lib/active_record/relation/query_methods.rb +576 -107
- data/lib/active_record/relation/record_fetch_warning.rb +3 -0
- data/lib/active_record/relation/spawn_methods.rb +5 -4
- data/lib/active_record/relation/where_clause.rb +7 -19
- data/lib/active_record/relation.rb +580 -90
- data/lib/active_record/result.rb +49 -48
- data/lib/active_record/runtime_registry.rb +63 -1
- data/lib/active_record/sanitization.rb +70 -25
- data/lib/active_record/schema.rb +8 -7
- data/lib/active_record/schema_dumper.rb +63 -14
- data/lib/active_record/schema_migration.rb +75 -24
- data/lib/active_record/scoping/default.rb +15 -5
- data/lib/active_record/scoping/named.rb +3 -2
- data/lib/active_record/scoping.rb +2 -1
- data/lib/active_record/secure_password.rb +60 -0
- data/lib/active_record/secure_token.rb +21 -3
- data/lib/active_record/signed_id.rb +27 -6
- data/lib/active_record/statement_cache.rb +7 -7
- data/lib/active_record/store.rb +8 -8
- data/lib/active_record/suppressor.rb +3 -1
- data/lib/active_record/table_metadata.rb +1 -1
- data/lib/active_record/tasks/database_tasks.rb +190 -118
- data/lib/active_record/tasks/mysql_database_tasks.rb +15 -6
- data/lib/active_record/tasks/postgresql_database_tasks.rb +16 -13
- data/lib/active_record/tasks/sqlite_database_tasks.rb +16 -7
- data/lib/active_record/test_fixtures.rb +170 -155
- data/lib/active_record/testing/query_assertions.rb +121 -0
- data/lib/active_record/timestamp.rb +31 -17
- data/lib/active_record/token_for.rb +123 -0
- data/lib/active_record/touch_later.rb +12 -7
- data/lib/active_record/transaction.rb +132 -0
- data/lib/active_record/transactions.rb +106 -24
- data/lib/active_record/translation.rb +0 -2
- data/lib/active_record/type/adapter_specific_registry.rb +1 -8
- data/lib/active_record/type/internal/timezone.rb +7 -2
- data/lib/active_record/type/serialized.rb +1 -3
- data/lib/active_record/type/time.rb +4 -0
- data/lib/active_record/type_caster/connection.rb +4 -4
- data/lib/active_record/validations/absence.rb +1 -1
- data/lib/active_record/validations/associated.rb +9 -3
- data/lib/active_record/validations/numericality.rb +5 -4
- data/lib/active_record/validations/presence.rb +5 -28
- data/lib/active_record/validations/uniqueness.rb +61 -11
- data/lib/active_record/validations.rb +12 -5
- data/lib/active_record/version.rb +1 -1
- data/lib/active_record.rb +247 -33
- 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/errors.rb +10 -0
- data/lib/arel/factory_methods.rb +4 -0
- data/lib/arel/nodes/binary.rb +6 -7
- data/lib/arel/nodes/bound_sql_literal.rb +65 -0
- data/lib/arel/nodes/cte.rb +36 -0
- data/lib/arel/nodes/fragments.rb +35 -0
- data/lib/arel/nodes/homogeneous_in.rb +1 -9
- data/lib/arel/nodes/leading_join.rb +8 -0
- data/lib/arel/nodes/{and.rb → nary.rb} +5 -2
- data/lib/arel/nodes/node.rb +115 -5
- data/lib/arel/nodes/sql_literal.rb +13 -0
- data/lib/arel/nodes/table_alias.rb +4 -0
- data/lib/arel/nodes.rb +6 -2
- data/lib/arel/predications.rb +3 -1
- data/lib/arel/select_manager.rb +1 -1
- data/lib/arel/table.rb +9 -5
- 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 +17 -5
- data/lib/arel/visitors/postgresql.rb +1 -12
- data/lib/arel/visitors/sqlite.rb +25 -0
- data/lib/arel/visitors/to_sql.rb +112 -34
- data/lib/arel/visitors/visitor.rb +2 -2
- data/lib/arel.rb +21 -3
- data/lib/rails/generators/active_record/application_record/USAGE +8 -0
- data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb.tt +4 -1
- data/lib/rails/generators/active_record/migration.rb +3 -1
- data/lib/rails/generators/active_record/model/USAGE +113 -0
- data/lib/rails/generators/active_record/model/model_generator.rb +15 -6
- metadata +59 -17
- data/lib/active_record/connection_adapters/legacy_pool_manager.rb +0 -35
- data/lib/active_record/null_relation.rb +0 -63
@@ -7,6 +7,7 @@ require "active_support/core_ext/array/access"
|
|
7
7
|
require "active_support/core_ext/enumerable"
|
8
8
|
require "active_support/core_ext/module/attribute_accessors"
|
9
9
|
require "active_support/actionable_error"
|
10
|
+
require "active_record/migration/pending_migration_connection"
|
10
11
|
|
11
12
|
module ActiveRecord
|
12
13
|
class MigrationError < ActiveRecordError # :nodoc:
|
@@ -20,7 +21,7 @@ module ActiveRecord
|
|
20
21
|
# For example the following migration is not reversible.
|
21
22
|
# Rolling back this migration will raise an ActiveRecord::IrreversibleMigration error.
|
22
23
|
#
|
23
|
-
# class IrreversibleMigrationExample < ActiveRecord::Migration[7.
|
24
|
+
# class IrreversibleMigrationExample < ActiveRecord::Migration[7.2]
|
24
25
|
# def change
|
25
26
|
# create_table :distributors do |t|
|
26
27
|
# t.string :zipcode
|
@@ -38,7 +39,7 @@ module ActiveRecord
|
|
38
39
|
#
|
39
40
|
# 1. Define <tt>#up</tt> and <tt>#down</tt> methods instead of <tt>#change</tt>:
|
40
41
|
#
|
41
|
-
# class ReversibleMigrationExample < ActiveRecord::Migration[7.
|
42
|
+
# class ReversibleMigrationExample < ActiveRecord::Migration[7.2]
|
42
43
|
# def up
|
43
44
|
# create_table :distributors do |t|
|
44
45
|
# t.string :zipcode
|
@@ -63,7 +64,7 @@ module ActiveRecord
|
|
63
64
|
#
|
64
65
|
# 2. Use the #reversible method in <tt>#change</tt> method:
|
65
66
|
#
|
66
|
-
# class ReversibleMigrationExample < ActiveRecord::Migration[7.
|
67
|
+
# class ReversibleMigrationExample < ActiveRecord::Migration[7.2]
|
67
68
|
# def change
|
68
69
|
# create_table :distributors do |t|
|
69
70
|
# t.string :zipcode
|
@@ -130,6 +131,22 @@ module ActiveRecord
|
|
130
131
|
end
|
131
132
|
end
|
132
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
|
+
|
133
150
|
class PendingMigrationError < MigrationError # :nodoc:
|
134
151
|
include ActiveSupport::ActionableError
|
135
152
|
|
@@ -137,32 +154,37 @@ module ActiveRecord
|
|
137
154
|
ActiveRecord::Tasks::DatabaseTasks.migrate
|
138
155
|
|
139
156
|
if ActiveRecord.dump_schema_after_migration
|
140
|
-
ActiveRecord::Tasks::DatabaseTasks.
|
141
|
-
|
142
|
-
)
|
157
|
+
connection = ActiveRecord::Tasks::DatabaseTasks.migration_connection
|
158
|
+
ActiveRecord::Tasks::DatabaseTasks.dump_schema(connection.pool.db_config)
|
143
159
|
end
|
144
160
|
end
|
145
161
|
|
146
|
-
def initialize(message = nil)
|
147
|
-
|
162
|
+
def initialize(message = nil, pending_migrations: nil)
|
163
|
+
if pending_migrations.nil?
|
164
|
+
pending_migrations = connection_pool.migration_context.open.pending_migrations
|
165
|
+
end
|
166
|
+
|
167
|
+
super(message || detailed_migration_message(pending_migrations))
|
148
168
|
end
|
149
169
|
|
150
170
|
private
|
151
|
-
def detailed_migration_message
|
171
|
+
def detailed_migration_message(pending_migrations)
|
152
172
|
message = "Migrations are pending. To resolve this issue, run:\n\n bin/rails db:migrate"
|
153
|
-
message += " RAILS_ENV=#{::Rails.env}" if defined?(Rails.env)
|
173
|
+
message += " RAILS_ENV=#{::Rails.env}" if defined?(Rails.env) && !Rails.env.local?
|
154
174
|
message += "\n\n"
|
155
175
|
|
156
|
-
pending_migrations = ActiveRecord::Base.connection.migration_context.open.pending_migrations
|
157
|
-
|
158
176
|
message += "You have #{pending_migrations.size} pending #{pending_migrations.size > 1 ? 'migrations:' : 'migration:'}\n\n"
|
159
177
|
|
160
178
|
pending_migrations.each do |pending_migration|
|
161
|
-
message += "#{pending_migration.
|
179
|
+
message += "#{pending_migration.filename}\n"
|
162
180
|
end
|
163
181
|
|
164
182
|
message
|
165
183
|
end
|
184
|
+
|
185
|
+
def connection_pool
|
186
|
+
ActiveRecord::Tasks::DatabaseTasks.migration_connection_pool
|
187
|
+
end
|
166
188
|
end
|
167
189
|
|
168
190
|
class ConcurrentMigrationError < MigrationError # :nodoc:
|
@@ -228,7 +250,7 @@ module ActiveRecord
|
|
228
250
|
#
|
229
251
|
# Example of a simple migration:
|
230
252
|
#
|
231
|
-
# class AddSsl < ActiveRecord::Migration[7.
|
253
|
+
# class AddSsl < ActiveRecord::Migration[7.2]
|
232
254
|
# def up
|
233
255
|
# add_column :accounts, :ssl_enabled, :boolean, default: true
|
234
256
|
# end
|
@@ -248,7 +270,7 @@ module ActiveRecord
|
|
248
270
|
#
|
249
271
|
# Example of a more complex migration that also needs to initialize data:
|
250
272
|
#
|
251
|
-
# class AddSystemSettings < ActiveRecord::Migration[7.
|
273
|
+
# class AddSystemSettings < ActiveRecord::Migration[7.2]
|
252
274
|
# def up
|
253
275
|
# create_table :system_settings do |t|
|
254
276
|
# t.string :name
|
@@ -356,15 +378,16 @@ module ActiveRecord
|
|
356
378
|
# == Irreversible transformations
|
357
379
|
#
|
358
380
|
# Some transformations are destructive in a manner that cannot be reversed.
|
359
|
-
# Migrations of that kind should raise an
|
381
|
+
# Migrations of that kind should raise an ActiveRecord::IrreversibleMigration
|
360
382
|
# exception in their +down+ method.
|
361
383
|
#
|
362
|
-
# == Running migrations from within Rails
|
384
|
+
# == Running migrations from within \Rails
|
363
385
|
#
|
364
|
-
# The Rails package has several tools to help create and apply migrations.
|
386
|
+
# The \Rails package has several tools to help create and apply migrations.
|
365
387
|
#
|
366
388
|
# To generate a new migration, you can use
|
367
|
-
#
|
389
|
+
#
|
390
|
+
# $ bin/rails generate migration MyNewMigration
|
368
391
|
#
|
369
392
|
# where MyNewMigration is the name of your migration. The generator will
|
370
393
|
# create an empty migration file <tt>timestamp_my_new_migration.rb</tt>
|
@@ -373,10 +396,10 @@ module ActiveRecord
|
|
373
396
|
#
|
374
397
|
# There is a special syntactic shortcut to generate migrations that add fields to a table.
|
375
398
|
#
|
376
|
-
# bin/rails generate migration add_fieldname_to_tablename fieldname:string
|
399
|
+
# $ bin/rails generate migration add_fieldname_to_tablename fieldname:string
|
377
400
|
#
|
378
401
|
# This will generate the file <tt>timestamp_add_fieldname_to_tablename.rb</tt>, which will look like this:
|
379
|
-
# class AddFieldnameToTablename < ActiveRecord::Migration[7.
|
402
|
+
# class AddFieldnameToTablename < ActiveRecord::Migration[7.2]
|
380
403
|
# def change
|
381
404
|
# add_column :tablenames, :fieldname, :string
|
382
405
|
# end
|
@@ -395,14 +418,14 @@ module ActiveRecord
|
|
395
418
|
# wish to rollback last few migrations. <tt>bin/rails db:rollback STEP=2</tt> will rollback
|
396
419
|
# the latest two migrations.
|
397
420
|
#
|
398
|
-
# If any of the migrations throw an
|
421
|
+
# If any of the migrations throw an ActiveRecord::IrreversibleMigration exception,
|
399
422
|
# that step will fail and you'll have some manual work to do.
|
400
423
|
#
|
401
424
|
# == More examples
|
402
425
|
#
|
403
426
|
# Not all migrations change the schema. Some just fix the data:
|
404
427
|
#
|
405
|
-
# class RemoveEmptyTags < ActiveRecord::Migration[7.
|
428
|
+
# class RemoveEmptyTags < ActiveRecord::Migration[7.2]
|
406
429
|
# def up
|
407
430
|
# Tag.all.each { |tag| tag.destroy if tag.pages.empty? }
|
408
431
|
# end
|
@@ -415,7 +438,7 @@ module ActiveRecord
|
|
415
438
|
#
|
416
439
|
# Others remove columns when they migrate up instead of down:
|
417
440
|
#
|
418
|
-
# class RemoveUnnecessaryItemAttributes < ActiveRecord::Migration[7.
|
441
|
+
# class RemoveUnnecessaryItemAttributes < ActiveRecord::Migration[7.2]
|
419
442
|
# def up
|
420
443
|
# remove_column :items, :incomplete_items_count
|
421
444
|
# remove_column :items, :completed_items_count
|
@@ -429,7 +452,7 @@ module ActiveRecord
|
|
429
452
|
#
|
430
453
|
# And sometimes you need to do something in SQL not abstracted directly by migrations:
|
431
454
|
#
|
432
|
-
# class MakeJoinUnique < ActiveRecord::Migration[7.
|
455
|
+
# class MakeJoinUnique < ActiveRecord::Migration[7.2]
|
433
456
|
# def up
|
434
457
|
# execute "ALTER TABLE `pages_linked_pages` ADD UNIQUE `page_id_linked_page_id` (`page_id`,`linked_page_id`)"
|
435
458
|
# end
|
@@ -446,7 +469,7 @@ module ActiveRecord
|
|
446
469
|
# <tt>Base#reset_column_information</tt> in order to ensure that the model has the
|
447
470
|
# latest column data from after the new column was added. Example:
|
448
471
|
#
|
449
|
-
# class AddPeopleSalary < ActiveRecord::Migration[7.
|
472
|
+
# class AddPeopleSalary < ActiveRecord::Migration[7.2]
|
450
473
|
# def up
|
451
474
|
# add_column :people, :salary, :integer
|
452
475
|
# Person.reset_column_information
|
@@ -462,7 +485,7 @@ module ActiveRecord
|
|
462
485
|
# them to the console as they happen, along with benchmarks describing how
|
463
486
|
# long each step took.
|
464
487
|
#
|
465
|
-
# 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>.
|
466
489
|
#
|
467
490
|
# You can also insert your own messages and benchmarks by using the +say_with_time+
|
468
491
|
# method:
|
@@ -482,11 +505,15 @@ module ActiveRecord
|
|
482
505
|
#
|
483
506
|
# == Timestamped Migrations
|
484
507
|
#
|
485
|
-
# By default, Rails generates migrations that look like:
|
508
|
+
# By default, \Rails generates migrations that look like:
|
486
509
|
#
|
487
510
|
# 20080717013526_your_migration_name.rb
|
488
511
|
#
|
489
|
-
# 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
|
490
517
|
#
|
491
518
|
# If you'd prefer to use numeric prefixes, you can turn timestamped migrations
|
492
519
|
# off by setting:
|
@@ -504,7 +531,7 @@ module ActiveRecord
|
|
504
531
|
# To define a reversible migration, define the +change+ method in your
|
505
532
|
# migration like this:
|
506
533
|
#
|
507
|
-
# class TenderloveMigration < ActiveRecord::Migration[7.
|
534
|
+
# class TenderloveMigration < ActiveRecord::Migration[7.2]
|
508
535
|
# def change
|
509
536
|
# create_table(:horses) do |t|
|
510
537
|
# t.column :content, :text
|
@@ -521,11 +548,11 @@ module ActiveRecord
|
|
521
548
|
# as before.
|
522
549
|
#
|
523
550
|
# If a command cannot be reversed, an
|
524
|
-
#
|
551
|
+
# ActiveRecord::IrreversibleMigration exception will be raised when
|
525
552
|
# the migration is moving down.
|
526
553
|
#
|
527
554
|
# For a list of commands that are reversible, please see
|
528
|
-
#
|
555
|
+
# +ActiveRecord::Migration::CommandRecorder+.
|
529
556
|
#
|
530
557
|
# == Transactional Migrations
|
531
558
|
#
|
@@ -534,7 +561,7 @@ module ActiveRecord
|
|
534
561
|
# can't execute inside a transaction though, and for these situations
|
535
562
|
# you can turn the automatic transactions off.
|
536
563
|
#
|
537
|
-
# class ChangeEnum < ActiveRecord::Migration[7.
|
564
|
+
# class ChangeEnum < ActiveRecord::Migration[7.2]
|
538
565
|
# disable_ddl_transaction!
|
539
566
|
#
|
540
567
|
# def up
|
@@ -548,6 +575,8 @@ module ActiveRecord
|
|
548
575
|
autoload :CommandRecorder, "active_record/migration/command_recorder"
|
549
576
|
autoload :Compatibility, "active_record/migration/compatibility"
|
550
577
|
autoload :JoinTable, "active_record/migration/join_table"
|
578
|
+
autoload :ExecutionStrategy, "active_record/migration/execution_strategy"
|
579
|
+
autoload :DefaultStrategy, "active_record/migration/default_strategy"
|
551
580
|
|
552
581
|
# This must be defined before the inherited hook, below
|
553
582
|
class Current < Migration # :nodoc:
|
@@ -610,6 +639,13 @@ module ActiveRecord
|
|
610
639
|
|
611
640
|
MigrationFilenameRegexp = /\A([0-9]+)_([_a-z0-9]*)\.?([_a-z0-9]*)?\.rb\z/ # :nodoc:
|
612
641
|
|
642
|
+
def self.valid_version_format?(version_string) # :nodoc:
|
643
|
+
[
|
644
|
+
MigrationFilenameRegexp,
|
645
|
+
/\A\d(_?\d)*\z/ # integer with optional underscores
|
646
|
+
].any? { |pattern| pattern.match?(version_string) }
|
647
|
+
end
|
648
|
+
|
613
649
|
# This class is used to verify that all migrations have been run before
|
614
650
|
# loading a web page if <tt>config.active_record.migration_error</tt> is set to +:page_load+.
|
615
651
|
class CheckPending
|
@@ -624,7 +660,7 @@ module ActiveRecord
|
|
624
660
|
@mutex.synchronize do
|
625
661
|
@watcher ||= build_watcher do
|
626
662
|
@needs_check = true
|
627
|
-
ActiveRecord::Migration.
|
663
|
+
ActiveRecord::Migration.check_pending_migrations
|
628
664
|
@needs_check = false
|
629
665
|
end
|
630
666
|
|
@@ -640,12 +676,14 @@ module ActiveRecord
|
|
640
676
|
|
641
677
|
private
|
642
678
|
def build_watcher(&block)
|
643
|
-
|
679
|
+
current_environment = ActiveRecord::ConnectionHandling::DEFAULT_ENV.call
|
680
|
+
all_configs = ActiveRecord::Base.configurations.configs_for(env_name: current_environment)
|
681
|
+
paths = all_configs.flat_map { |config| config.migrations_paths || Migrator.migrations_paths }.uniq
|
644
682
|
@file_watcher.new([], paths.index_with(["rb"]), &block)
|
645
683
|
end
|
646
684
|
|
647
685
|
def connection
|
648
|
-
ActiveRecord::
|
686
|
+
ActiveRecord::Tasks::DatabaseTasks.migration_connection
|
649
687
|
end
|
650
688
|
end
|
651
689
|
|
@@ -657,32 +695,36 @@ module ActiveRecord
|
|
657
695
|
delegate || superclass.nearest_delegate
|
658
696
|
end
|
659
697
|
|
660
|
-
# Raises
|
661
|
-
|
662
|
-
|
663
|
-
|
698
|
+
# Raises ActiveRecord::PendingMigrationError error if any migrations are pending
|
699
|
+
# for all database configurations in an environment.
|
700
|
+
def check_all_pending!
|
701
|
+
pending_migrations = []
|
664
702
|
|
665
|
-
|
666
|
-
|
667
|
-
|
703
|
+
ActiveRecord::Tasks::DatabaseTasks.with_temporary_pool_for_each(env: env) do |pool|
|
704
|
+
if pending = pool.migration_context.open.pending_migrations
|
705
|
+
pending_migrations << pending
|
706
|
+
end
|
707
|
+
end
|
708
|
+
|
709
|
+
migrations = pending_migrations.flatten
|
668
710
|
|
669
|
-
|
670
|
-
|
711
|
+
if migrations.any?
|
712
|
+
raise ActiveRecord::PendingMigrationError.new(pending_migrations: migrations)
|
671
713
|
end
|
714
|
+
end
|
672
715
|
|
673
|
-
|
716
|
+
def load_schema_if_pending!
|
717
|
+
if any_schema_needs_update?
|
674
718
|
# Roundtrip to Rake to allow plugins to hook into database initialization.
|
675
719
|
root = defined?(ENGINE_ROOT) ? ENGINE_ROOT : Rails.root
|
720
|
+
|
676
721
|
FileUtils.cd(root) do
|
677
|
-
Base.clear_all_connections!
|
722
|
+
Base.connection_handler.clear_all_connections!(:all)
|
678
723
|
system("bin/rails db:test:prepare")
|
679
724
|
end
|
680
725
|
end
|
681
726
|
|
682
|
-
|
683
|
-
Base.establish_connection(current_db_config)
|
684
|
-
|
685
|
-
check_pending!
|
727
|
+
check_pending_migrations
|
686
728
|
end
|
687
729
|
|
688
730
|
def maintain_test_schema! # :nodoc:
|
@@ -691,10 +733,9 @@ module ActiveRecord
|
|
691
733
|
end
|
692
734
|
end
|
693
735
|
|
694
|
-
def method_missing(name,
|
695
|
-
nearest_delegate.send(name,
|
736
|
+
def method_missing(name, ...) # :nodoc:
|
737
|
+
nearest_delegate.send(name, ...)
|
696
738
|
end
|
697
|
-
ruby2_keywords(:method_missing)
|
698
739
|
|
699
740
|
def migrate(direction)
|
700
741
|
new.migrate direction
|
@@ -707,12 +748,55 @@ module ActiveRecord
|
|
707
748
|
def disable_ddl_transaction!
|
708
749
|
@disable_ddl_transaction = true
|
709
750
|
end
|
751
|
+
|
752
|
+
def check_pending_migrations # :nodoc:
|
753
|
+
migrations = pending_migrations
|
754
|
+
|
755
|
+
if migrations.any?
|
756
|
+
raise ActiveRecord::PendingMigrationError.new(pending_migrations: migrations)
|
757
|
+
end
|
758
|
+
end
|
759
|
+
|
760
|
+
private
|
761
|
+
def any_schema_needs_update?
|
762
|
+
!db_configs_in_current_env.all? do |db_config|
|
763
|
+
Tasks::DatabaseTasks.schema_up_to_date?(db_config, ActiveRecord.schema_format)
|
764
|
+
end
|
765
|
+
end
|
766
|
+
|
767
|
+
def db_configs_in_current_env
|
768
|
+
ActiveRecord::Base.configurations.configs_for(env_name: env)
|
769
|
+
end
|
770
|
+
|
771
|
+
def pending_migrations
|
772
|
+
pending_migrations = []
|
773
|
+
|
774
|
+
ActiveRecord::Base.configurations.configs_for(env_name: env).each do |db_config|
|
775
|
+
ActiveRecord::PendingMigrationConnection.with_temporary_pool(db_config) do |pool|
|
776
|
+
if pending = pool.migration_context.open.pending_migrations
|
777
|
+
pending_migrations << pending
|
778
|
+
end
|
779
|
+
end
|
780
|
+
end
|
781
|
+
|
782
|
+
pending_migrations.flatten
|
783
|
+
end
|
784
|
+
|
785
|
+
def env
|
786
|
+
ActiveRecord::ConnectionHandling::DEFAULT_ENV.call
|
787
|
+
end
|
710
788
|
end
|
711
789
|
|
712
790
|
def disable_ddl_transaction # :nodoc:
|
713
791
|
self.class.disable_ddl_transaction
|
714
792
|
end
|
715
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.
|
716
800
|
cattr_accessor :verbose
|
717
801
|
attr_accessor :name, :version
|
718
802
|
|
@@ -720,6 +804,11 @@ module ActiveRecord
|
|
720
804
|
@name = name
|
721
805
|
@version = version
|
722
806
|
@connection = nil
|
807
|
+
@pool = nil
|
808
|
+
end
|
809
|
+
|
810
|
+
def execution_strategy
|
811
|
+
@execution_strategy ||= ActiveRecord.migration_strategy.new(self)
|
723
812
|
end
|
724
813
|
|
725
814
|
self.verbose = true
|
@@ -733,7 +822,7 @@ module ActiveRecord
|
|
733
822
|
# and create the table 'apples' on the way up, and the reverse
|
734
823
|
# on the way down.
|
735
824
|
#
|
736
|
-
# class FixTLMigration < ActiveRecord::Migration[7.
|
825
|
+
# class FixTLMigration < ActiveRecord::Migration[7.2]
|
737
826
|
# def change
|
738
827
|
# revert do
|
739
828
|
# create_table(:horses) do |t|
|
@@ -752,7 +841,7 @@ module ActiveRecord
|
|
752
841
|
#
|
753
842
|
# require_relative "20121212123456_tenderlove_migration"
|
754
843
|
#
|
755
|
-
# class FixupTLMigration < ActiveRecord::Migration[7.
|
844
|
+
# class FixupTLMigration < ActiveRecord::Migration[7.2]
|
756
845
|
# def change
|
757
846
|
# revert TenderloveMigration
|
758
847
|
#
|
@@ -803,7 +892,7 @@ module ActiveRecord
|
|
803
892
|
# when the three columns 'first_name', 'last_name' and 'full_name' exist,
|
804
893
|
# even when migrating down:
|
805
894
|
#
|
806
|
-
# class SplitNameMigration < ActiveRecord::Migration[7.
|
895
|
+
# class SplitNameMigration < ActiveRecord::Migration[7.2]
|
807
896
|
# def change
|
808
897
|
# add_column :users, :first_name, :string
|
809
898
|
# add_column :users, :last_name, :string
|
@@ -831,7 +920,7 @@ module ActiveRecord
|
|
831
920
|
# In the following example, the new column +published+ will be given
|
832
921
|
# the value +true+ for all existing records.
|
833
922
|
#
|
834
|
-
# class AddPublishedToPosts < ActiveRecord::Migration[7.
|
923
|
+
# class AddPublishedToPosts < ActiveRecord::Migration[7.2]
|
835
924
|
# def change
|
836
925
|
# add_column :posts, :published, :boolean, default: false
|
837
926
|
# up_only do
|
@@ -884,7 +973,7 @@ module ActiveRecord
|
|
884
973
|
end
|
885
974
|
|
886
975
|
time = nil
|
887
|
-
ActiveRecord::
|
976
|
+
ActiveRecord::Tasks::DatabaseTasks.migration_connection.pool.with_connection do |conn|
|
888
977
|
time = Benchmark.measure do
|
889
978
|
exec_migration(conn, direction)
|
890
979
|
end
|
@@ -909,6 +998,7 @@ module ActiveRecord
|
|
909
998
|
end
|
910
999
|
ensure
|
911
1000
|
@connection = nil
|
1001
|
+
@execution_strategy = nil
|
912
1002
|
end
|
913
1003
|
|
914
1004
|
def write(text = "")
|
@@ -947,7 +1037,11 @@ module ActiveRecord
|
|
947
1037
|
end
|
948
1038
|
|
949
1039
|
def connection
|
950
|
-
@connection || ActiveRecord::
|
1040
|
+
@connection || ActiveRecord::Tasks::DatabaseTasks.migration_connection
|
1041
|
+
end
|
1042
|
+
|
1043
|
+
def connection_pool
|
1044
|
+
@pool || ActiveRecord::Tasks::DatabaseTasks.migration_connection_pool
|
951
1045
|
end
|
952
1046
|
|
953
1047
|
def method_missing(method, *arguments, &block)
|
@@ -961,22 +1055,23 @@ module ActiveRecord
|
|
961
1055
|
end
|
962
1056
|
end
|
963
1057
|
end
|
964
|
-
return super unless
|
965
|
-
|
1058
|
+
return super unless execution_strategy.respond_to?(method)
|
1059
|
+
execution_strategy.send(method, *arguments, &block)
|
966
1060
|
end
|
967
1061
|
end
|
968
1062
|
ruby2_keywords(:method_missing)
|
969
1063
|
|
970
1064
|
def copy(destination, sources, options = {})
|
971
1065
|
copied = []
|
972
|
-
schema_migration = options[:schema_migration] || ActiveRecord::SchemaMigration
|
973
1066
|
|
974
1067
|
FileUtils.mkdir_p(destination) unless File.exist?(destination)
|
1068
|
+
schema_migration = SchemaMigration::NullSchemaMigration.new
|
1069
|
+
internal_metadata = InternalMetadata::NullInternalMetadata.new
|
975
1070
|
|
976
|
-
destination_migrations = ActiveRecord::MigrationContext.new(destination, schema_migration).migrations
|
1071
|
+
destination_migrations = ActiveRecord::MigrationContext.new(destination, schema_migration, internal_metadata).migrations
|
977
1072
|
last = destination_migrations.last
|
978
1073
|
sources.each do |scope, path|
|
979
|
-
source_migrations = ActiveRecord::MigrationContext.new(path, schema_migration).migrations
|
1074
|
+
source_migrations = ActiveRecord::MigrationContext.new(path, schema_migration, internal_metadata).migrations
|
980
1075
|
|
981
1076
|
source_migrations.each do |migration|
|
982
1077
|
source = File.binread(migration.filename)
|
@@ -1037,7 +1132,7 @@ module ActiveRecord
|
|
1037
1132
|
if ActiveRecord.timestamped_migrations
|
1038
1133
|
[Time.now.utc.strftime("%Y%m%d%H%M%S"), "%.14d" % number].max
|
1039
1134
|
else
|
1040
|
-
|
1135
|
+
"%.3d" % number.to_i
|
1041
1136
|
end
|
1042
1137
|
end
|
1043
1138
|
|
@@ -1107,19 +1202,22 @@ module ActiveRecord
|
|
1107
1202
|
end
|
1108
1203
|
end
|
1109
1204
|
|
1205
|
+
# = \Migration \Context
|
1206
|
+
#
|
1110
1207
|
# MigrationContext sets the context in which a migration is run.
|
1111
1208
|
#
|
1112
1209
|
# A migration context requires the path to the migrations is set
|
1113
1210
|
# in the +migrations_paths+ parameter. Optionally a +schema_migration+
|
1114
|
-
# class can be provided.
|
1115
|
-
#
|
1116
|
-
#
|
1211
|
+
# class can be provided. Multiple database applications will instantiate
|
1212
|
+
# a +SchemaMigration+ object per database. From the Rake tasks, \Rails will
|
1213
|
+
# handle this for you.
|
1117
1214
|
class MigrationContext
|
1118
|
-
attr_reader :migrations_paths, :schema_migration
|
1215
|
+
attr_reader :migrations_paths, :schema_migration, :internal_metadata
|
1119
1216
|
|
1120
|
-
def initialize(migrations_paths, schema_migration =
|
1217
|
+
def initialize(migrations_paths, schema_migration = nil, internal_metadata = nil)
|
1121
1218
|
@migrations_paths = migrations_paths
|
1122
|
-
@schema_migration = schema_migration
|
1219
|
+
@schema_migration = schema_migration || SchemaMigration.new(connection_pool)
|
1220
|
+
@internal_metadata = internal_metadata || InternalMetadata.new(connection_pool)
|
1123
1221
|
end
|
1124
1222
|
|
1125
1223
|
# Runs the migrations in the +migrations_path+.
|
@@ -1163,7 +1261,7 @@ module ActiveRecord
|
|
1163
1261
|
migrations
|
1164
1262
|
end
|
1165
1263
|
|
1166
|
-
Migrator.new(:up, selected_migrations, schema_migration, target_version).migrate
|
1264
|
+
Migrator.new(:up, selected_migrations, schema_migration, internal_metadata, target_version).migrate
|
1167
1265
|
end
|
1168
1266
|
|
1169
1267
|
def down(target_version = nil, &block) # :nodoc:
|
@@ -1173,20 +1271,20 @@ module ActiveRecord
|
|
1173
1271
|
migrations
|
1174
1272
|
end
|
1175
1273
|
|
1176
|
-
Migrator.new(:down, selected_migrations, schema_migration, target_version).migrate
|
1274
|
+
Migrator.new(:down, selected_migrations, schema_migration, internal_metadata, target_version).migrate
|
1177
1275
|
end
|
1178
1276
|
|
1179
1277
|
def run(direction, target_version) # :nodoc:
|
1180
|
-
Migrator.new(direction, migrations, schema_migration, target_version).run
|
1278
|
+
Migrator.new(direction, migrations, schema_migration, internal_metadata, target_version).run
|
1181
1279
|
end
|
1182
1280
|
|
1183
1281
|
def open # :nodoc:
|
1184
|
-
Migrator.new(:up, migrations, schema_migration)
|
1282
|
+
Migrator.new(:up, migrations, schema_migration, internal_metadata)
|
1185
1283
|
end
|
1186
1284
|
|
1187
1285
|
def get_all_versions # :nodoc:
|
1188
1286
|
if schema_migration.table_exists?
|
1189
|
-
schema_migration.
|
1287
|
+
schema_migration.integer_versions
|
1190
1288
|
else
|
1191
1289
|
[]
|
1192
1290
|
end
|
@@ -1209,6 +1307,9 @@ module ActiveRecord
|
|
1209
1307
|
migrations = migration_files.map do |file|
|
1210
1308
|
version, name, scope = parse_migration_filename(file)
|
1211
1309
|
raise IllegalMigrationNameError.new(file) unless version
|
1310
|
+
if validate_timestamp? && !valid_migration_timestamp?(version)
|
1311
|
+
raise InvalidMigrationTimestampError.new(version, name)
|
1312
|
+
end
|
1212
1313
|
version = version.to_i
|
1213
1314
|
name = name.camelize
|
1214
1315
|
|
@@ -1224,6 +1325,9 @@ module ActiveRecord
|
|
1224
1325
|
file_list = migration_files.filter_map do |file|
|
1225
1326
|
version, name, scope = parse_migration_filename(file)
|
1226
1327
|
raise IllegalMigrationNameError.new(file) unless version
|
1328
|
+
if validate_timestamp? && !valid_migration_timestamp?(version)
|
1329
|
+
raise InvalidMigrationTimestampError.new(version, name)
|
1330
|
+
end
|
1227
1331
|
version = schema_migration.normalize_migration_number(version)
|
1228
1332
|
status = db_list.delete(version) ? "up" : "down"
|
1229
1333
|
[status, version, (name + scope).humanize]
|
@@ -1245,16 +1349,25 @@ module ActiveRecord
|
|
1245
1349
|
end
|
1246
1350
|
|
1247
1351
|
def last_stored_environment # :nodoc:
|
1248
|
-
|
1352
|
+
internal_metadata = connection_pool.internal_metadata
|
1353
|
+
return nil unless internal_metadata.enabled?
|
1249
1354
|
return nil if current_version == 0
|
1250
|
-
raise NoEnvironmentInSchemaError unless
|
1355
|
+
raise NoEnvironmentInSchemaError unless internal_metadata.table_exists?
|
1251
1356
|
|
1252
|
-
environment =
|
1357
|
+
environment = internal_metadata[:environment]
|
1253
1358
|
raise NoEnvironmentInSchemaError unless environment
|
1254
1359
|
environment
|
1255
1360
|
end
|
1256
1361
|
|
1257
1362
|
private
|
1363
|
+
def connection
|
1364
|
+
ActiveRecord::Tasks::DatabaseTasks.migration_connection
|
1365
|
+
end
|
1366
|
+
|
1367
|
+
def connection_pool
|
1368
|
+
ActiveRecord::Tasks::DatabaseTasks.migration_connection_pool
|
1369
|
+
end
|
1370
|
+
|
1258
1371
|
def migration_files
|
1259
1372
|
paths = Array(migrations_paths)
|
1260
1373
|
Dir[*paths.flat_map { |path| "#{path}/**/[0-9]*_*.rb" }]
|
@@ -1264,8 +1377,16 @@ module ActiveRecord
|
|
1264
1377
|
File.basename(filename).scan(Migration::MigrationFilenameRegexp).first
|
1265
1378
|
end
|
1266
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
|
+
|
1267
1388
|
def move(direction, steps)
|
1268
|
-
migrator = Migrator.new(direction, migrations, schema_migration)
|
1389
|
+
migrator = Migrator.new(direction, migrations, schema_migration, internal_metadata)
|
1269
1390
|
|
1270
1391
|
if current_version != 0 && !migrator.current_migration
|
1271
1392
|
raise UnknownMigrationVersionError.new(current_version)
|
@@ -1290,23 +1411,28 @@ module ActiveRecord
|
|
1290
1411
|
|
1291
1412
|
# For cases where a table doesn't exist like loading from schema cache
|
1292
1413
|
def current_version
|
1293
|
-
|
1414
|
+
connection_pool = ActiveRecord::Tasks::DatabaseTasks.migration_connection_pool
|
1415
|
+
schema_migration = SchemaMigration.new(connection_pool)
|
1416
|
+
internal_metadata = InternalMetadata.new(connection_pool)
|
1417
|
+
|
1418
|
+
MigrationContext.new(migrations_paths, schema_migration, internal_metadata).current_version
|
1294
1419
|
end
|
1295
1420
|
end
|
1296
1421
|
|
1297
1422
|
self.migrations_paths = ["db/migrate"]
|
1298
1423
|
|
1299
|
-
def initialize(direction, migrations, schema_migration, target_version = nil)
|
1424
|
+
def initialize(direction, migrations, schema_migration, internal_metadata, target_version = nil)
|
1300
1425
|
@direction = direction
|
1301
1426
|
@target_version = target_version
|
1302
1427
|
@migrated_versions = nil
|
1303
1428
|
@migrations = migrations
|
1304
1429
|
@schema_migration = schema_migration
|
1430
|
+
@internal_metadata = internal_metadata
|
1305
1431
|
|
1306
1432
|
validate(@migrations)
|
1307
1433
|
|
1308
1434
|
@schema_migration.create_table
|
1309
|
-
|
1435
|
+
@internal_metadata.create_table
|
1310
1436
|
end
|
1311
1437
|
|
1312
1438
|
def current_version
|
@@ -1359,18 +1485,21 @@ module ActiveRecord
|
|
1359
1485
|
end
|
1360
1486
|
|
1361
1487
|
def load_migrated
|
1362
|
-
@migrated_versions = Set.new(@schema_migration.
|
1488
|
+
@migrated_versions = Set.new(@schema_migration.integer_versions)
|
1363
1489
|
end
|
1364
1490
|
|
1365
1491
|
private
|
1492
|
+
def connection
|
1493
|
+
ActiveRecord::Tasks::DatabaseTasks.migration_connection
|
1494
|
+
end
|
1495
|
+
|
1366
1496
|
# Used for running a specific migration.
|
1367
1497
|
def run_without_lock
|
1368
1498
|
migration = migrations.detect { |m| m.version == @target_version }
|
1369
1499
|
raise UnknownMigrationVersionError.new(@target_version) if migration.nil?
|
1370
|
-
result = execute_migration_in_transaction(migration)
|
1371
1500
|
|
1372
1501
|
record_environment
|
1373
|
-
|
1502
|
+
execute_migration_in_transaction(migration)
|
1374
1503
|
end
|
1375
1504
|
|
1376
1505
|
# Used for running multiple migrations up to or down to a certain value.
|
@@ -1379,15 +1508,15 @@ module ActiveRecord
|
|
1379
1508
|
raise UnknownMigrationVersionError.new(@target_version)
|
1380
1509
|
end
|
1381
1510
|
|
1382
|
-
result = runnable.each(&method(:execute_migration_in_transaction))
|
1383
1511
|
record_environment
|
1384
|
-
|
1512
|
+
runnable.each(&method(:execute_migration_in_transaction))
|
1385
1513
|
end
|
1386
1514
|
|
1387
1515
|
# Stores the current environment in the database.
|
1388
1516
|
def record_environment
|
1389
1517
|
return if down?
|
1390
|
-
|
1518
|
+
|
1519
|
+
@internal_metadata[:environment] = connection.pool.db_config.env_name
|
1391
1520
|
end
|
1392
1521
|
|
1393
1522
|
def ran?(migration)
|
@@ -1439,10 +1568,10 @@ module ActiveRecord
|
|
1439
1568
|
def record_version_state_after_migrating(version)
|
1440
1569
|
if down?
|
1441
1570
|
migrated.delete(version)
|
1442
|
-
@schema_migration.
|
1571
|
+
@schema_migration.delete_version(version.to_s)
|
1443
1572
|
else
|
1444
1573
|
migrated << version
|
1445
|
-
@schema_migration.
|
1574
|
+
@schema_migration.create_version(version.to_s)
|
1446
1575
|
end
|
1447
1576
|
end
|
1448
1577
|
|
@@ -1457,50 +1586,38 @@ module ActiveRecord
|
|
1457
1586
|
# Wrap the migration in a transaction only if supported by the adapter.
|
1458
1587
|
def ddl_transaction(migration, &block)
|
1459
1588
|
if use_transaction?(migration)
|
1460
|
-
|
1589
|
+
connection.transaction(&block)
|
1461
1590
|
else
|
1462
1591
|
yield
|
1463
1592
|
end
|
1464
1593
|
end
|
1465
1594
|
|
1466
1595
|
def use_transaction?(migration)
|
1467
|
-
!migration.disable_ddl_transaction &&
|
1596
|
+
!migration.disable_ddl_transaction && connection.supports_ddl_transactions?
|
1468
1597
|
end
|
1469
1598
|
|
1470
1599
|
def use_advisory_lock?
|
1471
|
-
|
1600
|
+
connection.advisory_locks_enabled?
|
1472
1601
|
end
|
1473
1602
|
|
1474
1603
|
def with_advisory_lock
|
1475
1604
|
lock_id = generate_migrator_advisory_lock_id
|
1476
1605
|
|
1477
|
-
|
1478
|
-
|
1479
|
-
|
1480
|
-
|
1481
|
-
yield
|
1482
|
-
ensure
|
1483
|
-
if got_lock && !connection.release_advisory_lock(lock_id)
|
1484
|
-
raise ConcurrentMigrationError.new(
|
1485
|
-
ConcurrentMigrationError::RELEASE_LOCK_FAILED_MESSAGE
|
1486
|
-
)
|
1487
|
-
end
|
1488
|
-
end
|
1489
|
-
end
|
1490
|
-
|
1491
|
-
def with_advisory_lock_connection(&block)
|
1492
|
-
pool = ActiveRecord::ConnectionAdapters::ConnectionHandler.new.establish_connection(
|
1493
|
-
ActiveRecord::Base.connection_db_config
|
1494
|
-
)
|
1495
|
-
|
1496
|
-
pool.with_connection(&block)
|
1606
|
+
got_lock = connection.get_advisory_lock(lock_id)
|
1607
|
+
raise ConcurrentMigrationError unless got_lock
|
1608
|
+
load_migrated # reload schema_migrations to be sure it wasn't changed by another process before we got the lock
|
1609
|
+
yield
|
1497
1610
|
ensure
|
1498
|
-
|
1611
|
+
if got_lock && !connection.release_advisory_lock(lock_id)
|
1612
|
+
raise ConcurrentMigrationError.new(
|
1613
|
+
ConcurrentMigrationError::RELEASE_LOCK_FAILED_MESSAGE
|
1614
|
+
)
|
1615
|
+
end
|
1499
1616
|
end
|
1500
1617
|
|
1501
1618
|
MIGRATOR_SALT = 2053462845
|
1502
1619
|
def generate_migrator_advisory_lock_id
|
1503
|
-
db_name_hash = Zlib.crc32(
|
1620
|
+
db_name_hash = Zlib.crc32(connection.current_database)
|
1504
1621
|
MIGRATOR_SALT * db_name_hash
|
1505
1622
|
end
|
1506
1623
|
end
|