activerecord 4.2.0 → 5.2.8.1
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of activerecord might be problematic. Click here for more details.
- checksums.yaml +5 -5
- data/CHANGELOG.md +640 -928
- data/MIT-LICENSE +2 -2
- data/README.rdoc +10 -11
- data/examples/performance.rb +32 -31
- data/examples/simple.rb +5 -4
- data/lib/active_record/aggregations.rb +264 -247
- data/lib/active_record/association_relation.rb +24 -6
- data/lib/active_record/associations/alias_tracker.rb +29 -35
- data/lib/active_record/associations/association.rb +87 -41
- data/lib/active_record/associations/association_scope.rb +106 -132
- data/lib/active_record/associations/belongs_to_association.rb +55 -36
- data/lib/active_record/associations/belongs_to_polymorphic_association.rb +8 -8
- data/lib/active_record/associations/builder/association.rb +29 -38
- data/lib/active_record/associations/builder/belongs_to.rb +77 -30
- data/lib/active_record/associations/builder/collection_association.rb +14 -23
- data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +50 -39
- data/lib/active_record/associations/builder/has_many.rb +6 -4
- data/lib/active_record/associations/builder/has_one.rb +13 -6
- data/lib/active_record/associations/builder/singular_association.rb +15 -11
- data/lib/active_record/associations/collection_association.rb +145 -266
- data/lib/active_record/associations/collection_proxy.rb +242 -138
- data/lib/active_record/associations/foreign_association.rb +13 -0
- data/lib/active_record/associations/has_many_association.rb +35 -75
- data/lib/active_record/associations/has_many_through_association.rb +51 -69
- data/lib/active_record/associations/has_one_association.rb +39 -24
- data/lib/active_record/associations/has_one_through_association.rb +18 -9
- data/lib/active_record/associations/join_dependency/join_association.rb +40 -81
- data/lib/active_record/associations/join_dependency/join_base.rb +10 -9
- data/lib/active_record/associations/join_dependency/join_part.rb +12 -12
- data/lib/active_record/associations/join_dependency.rb +134 -154
- data/lib/active_record/associations/preloader/association.rb +85 -116
- data/lib/active_record/associations/preloader/through_association.rb +85 -74
- data/lib/active_record/associations/preloader.rb +83 -93
- data/lib/active_record/associations/singular_association.rb +27 -40
- data/lib/active_record/associations/through_association.rb +48 -23
- data/lib/active_record/associations.rb +1732 -1596
- data/lib/active_record/attribute_assignment.rb +58 -182
- data/lib/active_record/attribute_decorators.rb +39 -15
- data/lib/active_record/attribute_methods/before_type_cast.rb +12 -5
- data/lib/active_record/attribute_methods/dirty.rb +94 -125
- data/lib/active_record/attribute_methods/primary_key.rb +86 -71
- data/lib/active_record/attribute_methods/query.rb +4 -2
- data/lib/active_record/attribute_methods/read.rb +45 -63
- data/lib/active_record/attribute_methods/serialization.rb +40 -20
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +62 -36
- data/lib/active_record/attribute_methods/write.rb +31 -46
- data/lib/active_record/attribute_methods.rb +170 -117
- data/lib/active_record/attributes.rb +201 -74
- data/lib/active_record/autosave_association.rb +118 -45
- data/lib/active_record/base.rb +60 -48
- data/lib/active_record/callbacks.rb +97 -57
- data/lib/active_record/coders/json.rb +3 -1
- data/lib/active_record/coders/yaml_column.rb +37 -13
- data/lib/active_record/collection_cache_key.rb +53 -0
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +712 -284
- data/lib/active_record/connection_adapters/abstract/database_limits.rb +10 -5
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +254 -87
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +72 -22
- data/lib/active_record/connection_adapters/abstract/quoting.rb +119 -52
- data/lib/active_record/connection_adapters/abstract/savepoints.rb +6 -4
- data/lib/active_record/connection_adapters/abstract/schema_creation.rb +67 -46
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +328 -217
- data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +81 -36
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +617 -212
- data/lib/active_record/connection_adapters/abstract/transaction.rb +139 -75
- data/lib/active_record/connection_adapters/abstract_adapter.rb +332 -191
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +567 -563
- data/lib/active_record/connection_adapters/column.rb +50 -41
- data/lib/active_record/connection_adapters/connection_specification.rb +147 -135
- data/lib/active_record/connection_adapters/determine_if_preparable_visitor.rb +33 -0
- data/lib/active_record/connection_adapters/mysql/column.rb +27 -0
- data/lib/active_record/connection_adapters/mysql/database_statements.rb +140 -0
- data/lib/active_record/connection_adapters/mysql/explain_pretty_printer.rb +72 -0
- data/lib/active_record/connection_adapters/mysql/quoting.rb +44 -0
- data/lib/active_record/connection_adapters/mysql/schema_creation.rb +73 -0
- data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +87 -0
- data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +80 -0
- data/lib/active_record/connection_adapters/mysql/schema_statements.rb +148 -0
- data/lib/active_record/connection_adapters/mysql/type_metadata.rb +35 -0
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +42 -195
- data/lib/active_record/connection_adapters/postgresql/column.rb +35 -11
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +46 -115
- data/lib/active_record/connection_adapters/postgresql/explain_pretty_printer.rb +44 -0
- data/lib/active_record/connection_adapters/postgresql/oid/array.rb +50 -57
- data/lib/active_record/connection_adapters/postgresql/oid/bit.rb +10 -6
- data/lib/active_record/connection_adapters/postgresql/oid/bit_varying.rb +2 -0
- data/lib/active_record/connection_adapters/postgresql/oid/bytea.rb +5 -2
- data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +5 -1
- data/lib/active_record/connection_adapters/postgresql/oid/date.rb +13 -1
- data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +9 -13
- data/lib/active_record/connection_adapters/postgresql/oid/decimal.rb +3 -1
- data/lib/active_record/connection_adapters/postgresql/oid/enum.rb +7 -3
- data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +31 -19
- data/lib/active_record/connection_adapters/postgresql/oid/inet.rb +2 -0
- data/lib/active_record/connection_adapters/postgresql/oid/jsonb.rb +3 -11
- data/lib/active_record/connection_adapters/postgresql/oid/legacy_point.rb +45 -0
- data/lib/active_record/connection_adapters/postgresql/oid/money.rb +7 -9
- data/lib/active_record/connection_adapters/postgresql/oid/{integer.rb → oid.rb} +6 -2
- data/lib/active_record/connection_adapters/postgresql/oid/point.rb +33 -11
- data/lib/active_record/connection_adapters/postgresql/oid/range.rb +52 -34
- data/lib/active_record/connection_adapters/postgresql/oid/specialized_string.rb +4 -1
- data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +65 -51
- data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +5 -3
- data/lib/active_record/connection_adapters/postgresql/oid/vector.rb +3 -1
- data/lib/active_record/connection_adapters/postgresql/oid/xml.rb +3 -1
- data/lib/active_record/connection_adapters/postgresql/oid.rb +23 -25
- data/lib/active_record/connection_adapters/postgresql/quoting.rb +107 -47
- data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +27 -14
- data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +65 -0
- data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +144 -90
- data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +50 -0
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +466 -280
- data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +39 -0
- data/lib/active_record/connection_adapters/postgresql/utils.rb +12 -8
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +439 -330
- data/lib/active_record/connection_adapters/schema_cache.rb +48 -24
- data/lib/active_record/connection_adapters/sql_type_metadata.rb +34 -0
- data/lib/active_record/connection_adapters/sqlite3/explain_pretty_printer.rb +21 -0
- data/lib/active_record/connection_adapters/sqlite3/quoting.rb +67 -0
- data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +17 -0
- data/lib/active_record/connection_adapters/sqlite3/schema_definitions.rb +19 -0
- data/lib/active_record/connection_adapters/sqlite3/schema_dumper.rb +18 -0
- data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +106 -0
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +269 -324
- data/lib/active_record/connection_adapters/statement_pool.rb +34 -13
- data/lib/active_record/connection_handling.rb +40 -27
- data/lib/active_record/core.rb +205 -202
- data/lib/active_record/counter_cache.rb +80 -37
- data/lib/active_record/define_callbacks.rb +22 -0
- data/lib/active_record/dynamic_matchers.rb +87 -105
- data/lib/active_record/enum.rb +136 -90
- data/lib/active_record/errors.rb +180 -52
- data/lib/active_record/explain.rb +23 -11
- data/lib/active_record/explain_registry.rb +4 -2
- data/lib/active_record/explain_subscriber.rb +11 -6
- data/lib/active_record/fixture_set/file.rb +35 -9
- data/lib/active_record/fixtures.rb +193 -135
- data/lib/active_record/gem_version.rb +5 -3
- data/lib/active_record/inheritance.rb +148 -112
- data/lib/active_record/integration.rb +70 -28
- data/lib/active_record/internal_metadata.rb +45 -0
- data/lib/active_record/legacy_yaml_adapter.rb +48 -0
- data/lib/active_record/locale/en.yml +3 -2
- data/lib/active_record/locking/optimistic.rb +92 -98
- data/lib/active_record/locking/pessimistic.rb +15 -3
- data/lib/active_record/log_subscriber.rb +95 -33
- data/lib/active_record/migration/command_recorder.rb +133 -90
- data/lib/active_record/migration/compatibility.rb +217 -0
- data/lib/active_record/migration/join_table.rb +8 -6
- data/lib/active_record/migration.rb +594 -267
- data/lib/active_record/model_schema.rb +292 -111
- data/lib/active_record/nested_attributes.rb +266 -214
- data/lib/active_record/no_touching.rb +8 -2
- data/lib/active_record/null_relation.rb +24 -37
- data/lib/active_record/persistence.rb +350 -119
- data/lib/active_record/query_cache.rb +13 -24
- data/lib/active_record/querying.rb +19 -17
- data/lib/active_record/railtie.rb +117 -35
- data/lib/active_record/railties/console_sandbox.rb +2 -0
- data/lib/active_record/railties/controller_runtime.rb +9 -3
- data/lib/active_record/railties/databases.rake +160 -174
- data/lib/active_record/readonly_attributes.rb +5 -4
- data/lib/active_record/reflection.rb +447 -288
- data/lib/active_record/relation/batches/batch_enumerator.rb +69 -0
- data/lib/active_record/relation/batches.rb +204 -55
- data/lib/active_record/relation/calculations.rb +259 -244
- data/lib/active_record/relation/delegation.rb +67 -60
- data/lib/active_record/relation/finder_methods.rb +290 -253
- data/lib/active_record/relation/from_clause.rb +26 -0
- data/lib/active_record/relation/merger.rb +91 -68
- data/lib/active_record/relation/predicate_builder/array_handler.rb +24 -23
- data/lib/active_record/relation/predicate_builder/association_query_value.rb +46 -0
- data/lib/active_record/relation/predicate_builder/base_handler.rb +19 -0
- data/lib/active_record/relation/predicate_builder/basic_object_handler.rb +20 -0
- data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +56 -0
- data/lib/active_record/relation/predicate_builder/range_handler.rb +42 -0
- data/lib/active_record/relation/predicate_builder/relation_handler.rb +7 -1
- data/lib/active_record/relation/predicate_builder.rb +118 -92
- data/lib/active_record/relation/query_attribute.rb +45 -0
- data/lib/active_record/relation/query_methods.rb +446 -389
- data/lib/active_record/relation/record_fetch_warning.rb +51 -0
- data/lib/active_record/relation/spawn_methods.rb +18 -16
- data/lib/active_record/relation/where_clause.rb +186 -0
- data/lib/active_record/relation/where_clause_factory.rb +34 -0
- data/lib/active_record/relation.rb +287 -339
- data/lib/active_record/result.rb +54 -36
- data/lib/active_record/runtime_registry.rb +6 -4
- data/lib/active_record/sanitization.rb +155 -124
- data/lib/active_record/schema.rb +30 -24
- data/lib/active_record/schema_dumper.rb +91 -87
- data/lib/active_record/schema_migration.rb +19 -19
- data/lib/active_record/scoping/default.rb +102 -84
- data/lib/active_record/scoping/named.rb +81 -32
- data/lib/active_record/scoping.rb +45 -26
- data/lib/active_record/secure_token.rb +40 -0
- data/lib/active_record/serialization.rb +5 -5
- data/lib/active_record/statement_cache.rb +45 -35
- data/lib/active_record/store.rb +42 -36
- data/lib/active_record/suppressor.rb +61 -0
- data/lib/active_record/table_metadata.rb +82 -0
- data/lib/active_record/tasks/database_tasks.rb +136 -95
- data/lib/active_record/tasks/mysql_database_tasks.rb +59 -89
- data/lib/active_record/tasks/postgresql_database_tasks.rb +84 -31
- data/lib/active_record/tasks/sqlite_database_tasks.rb +44 -16
- data/lib/active_record/timestamp.rb +70 -38
- data/lib/active_record/touch_later.rb +64 -0
- data/lib/active_record/transactions.rb +208 -123
- data/lib/active_record/translation.rb +2 -0
- data/lib/active_record/type/adapter_specific_registry.rb +136 -0
- data/lib/active_record/type/date.rb +4 -41
- data/lib/active_record/type/date_time.rb +4 -38
- data/lib/active_record/type/decimal_without_scale.rb +6 -2
- data/lib/active_record/type/hash_lookup_type_map.rb +13 -5
- data/lib/active_record/type/internal/timezone.rb +17 -0
- data/lib/active_record/type/json.rb +30 -0
- data/lib/active_record/type/serialized.rb +30 -15
- data/lib/active_record/type/text.rb +2 -2
- data/lib/active_record/type/time.rb +11 -16
- data/lib/active_record/type/type_map.rb +15 -17
- data/lib/active_record/type/unsigned_integer.rb +9 -7
- data/lib/active_record/type.rb +79 -23
- data/lib/active_record/type_caster/connection.rb +33 -0
- data/lib/active_record/type_caster/map.rb +23 -0
- data/lib/active_record/type_caster.rb +9 -0
- data/lib/active_record/validations/absence.rb +25 -0
- data/lib/active_record/validations/associated.rb +13 -4
- data/lib/active_record/validations/length.rb +26 -0
- data/lib/active_record/validations/presence.rb +14 -13
- data/lib/active_record/validations/uniqueness.rb +41 -32
- data/lib/active_record/validations.rb +38 -35
- data/lib/active_record/version.rb +3 -1
- data/lib/active_record.rb +36 -21
- data/lib/rails/generators/active_record/application_record/application_record_generator.rb +27 -0
- data/lib/rails/generators/active_record/application_record/templates/application_record.rb.tt +5 -0
- data/lib/rails/generators/active_record/migration/migration_generator.rb +43 -35
- data/lib/rails/generators/active_record/migration/templates/{create_table_migration.rb → create_table_migration.rb.tt} +8 -6
- data/lib/rails/generators/active_record/migration/templates/{migration.rb → migration.rb.tt} +8 -7
- data/lib/rails/generators/active_record/migration.rb +18 -1
- data/lib/rails/generators/active_record/model/model_generator.rb +18 -22
- data/lib/rails/generators/active_record/model/templates/{model.rb → model.rb.tt} +3 -0
- data/lib/rails/generators/active_record.rb +7 -5
- metadata +77 -53
- data/lib/active_record/associations/preloader/belongs_to.rb +0 -17
- data/lib/active_record/associations/preloader/collection_association.rb +0 -24
- data/lib/active_record/associations/preloader/has_many.rb +0 -17
- data/lib/active_record/associations/preloader/has_many_through.rb +0 -19
- data/lib/active_record/associations/preloader/has_one.rb +0 -23
- data/lib/active_record/associations/preloader/has_one_through.rb +0 -9
- data/lib/active_record/associations/preloader/singular_association.rb +0 -21
- data/lib/active_record/attribute.rb +0 -149
- data/lib/active_record/attribute_set/builder.rb +0 -86
- data/lib/active_record/attribute_set.rb +0 -77
- data/lib/active_record/connection_adapters/mysql_adapter.rb +0 -491
- data/lib/active_record/connection_adapters/postgresql/array_parser.rb +0 -93
- data/lib/active_record/connection_adapters/postgresql/oid/float.rb +0 -21
- data/lib/active_record/connection_adapters/postgresql/oid/infinity.rb +0 -13
- data/lib/active_record/connection_adapters/postgresql/oid/json.rb +0 -35
- data/lib/active_record/connection_adapters/postgresql/oid/time.rb +0 -11
- data/lib/active_record/railties/jdbcmysql_error.rb +0 -16
- data/lib/active_record/serializers/xml_serializer.rb +0 -193
- data/lib/active_record/type/big_integer.rb +0 -13
- data/lib/active_record/type/binary.rb +0 -50
- data/lib/active_record/type/boolean.rb +0 -30
- data/lib/active_record/type/decimal.rb +0 -40
- data/lib/active_record/type/decorator.rb +0 -14
- data/lib/active_record/type/float.rb +0 -19
- data/lib/active_record/type/integer.rb +0 -55
- data/lib/active_record/type/mutable.rb +0 -16
- data/lib/active_record/type/numeric.rb +0 -36
- data/lib/active_record/type/string.rb +0 -36
- data/lib/active_record/type/time_value.rb +0 -38
- data/lib/active_record/type/value.rb +0 -101
- /data/lib/rails/generators/active_record/model/templates/{module.rb → module.rb.tt} +0 -0
@@ -1,5 +1,8 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "set"
|
4
|
+
require "zlib"
|
1
5
|
require "active_support/core_ext/module/attribute_accessors"
|
2
|
-
require 'set'
|
3
6
|
|
4
7
|
module ActiveRecord
|
5
8
|
class MigrationError < ActiveRecordError#:nodoc:
|
@@ -9,40 +12,171 @@ module ActiveRecord
|
|
9
12
|
end
|
10
13
|
end
|
11
14
|
|
12
|
-
# Exception that can be raised to stop migrations from
|
15
|
+
# Exception that can be raised to stop migrations from being rolled back.
|
16
|
+
# For example the following migration is not reversible.
|
17
|
+
# Rolling back this migration will raise an ActiveRecord::IrreversibleMigration error.
|
18
|
+
#
|
19
|
+
# class IrreversibleMigrationExample < ActiveRecord::Migration[5.0]
|
20
|
+
# def change
|
21
|
+
# create_table :distributors do |t|
|
22
|
+
# t.string :zipcode
|
23
|
+
# end
|
24
|
+
#
|
25
|
+
# execute <<-SQL
|
26
|
+
# ALTER TABLE distributors
|
27
|
+
# ADD CONSTRAINT zipchk
|
28
|
+
# CHECK (char_length(zipcode) = 5) NO INHERIT;
|
29
|
+
# SQL
|
30
|
+
# end
|
31
|
+
# end
|
32
|
+
#
|
33
|
+
# There are two ways to mitigate this problem.
|
34
|
+
#
|
35
|
+
# 1. Define <tt>#up</tt> and <tt>#down</tt> methods instead of <tt>#change</tt>:
|
36
|
+
#
|
37
|
+
# class ReversibleMigrationExample < ActiveRecord::Migration[5.0]
|
38
|
+
# def up
|
39
|
+
# create_table :distributors do |t|
|
40
|
+
# t.string :zipcode
|
41
|
+
# end
|
42
|
+
#
|
43
|
+
# execute <<-SQL
|
44
|
+
# ALTER TABLE distributors
|
45
|
+
# ADD CONSTRAINT zipchk
|
46
|
+
# CHECK (char_length(zipcode) = 5) NO INHERIT;
|
47
|
+
# SQL
|
48
|
+
# end
|
49
|
+
#
|
50
|
+
# def down
|
51
|
+
# execute <<-SQL
|
52
|
+
# ALTER TABLE distributors
|
53
|
+
# DROP CONSTRAINT zipchk
|
54
|
+
# SQL
|
55
|
+
#
|
56
|
+
# drop_table :distributors
|
57
|
+
# end
|
58
|
+
# end
|
59
|
+
#
|
60
|
+
# 2. Use the #reversible method in <tt>#change</tt> method:
|
61
|
+
#
|
62
|
+
# class ReversibleMigrationExample < ActiveRecord::Migration[5.0]
|
63
|
+
# def change
|
64
|
+
# create_table :distributors do |t|
|
65
|
+
# t.string :zipcode
|
66
|
+
# end
|
67
|
+
#
|
68
|
+
# reversible do |dir|
|
69
|
+
# dir.up do
|
70
|
+
# execute <<-SQL
|
71
|
+
# ALTER TABLE distributors
|
72
|
+
# ADD CONSTRAINT zipchk
|
73
|
+
# CHECK (char_length(zipcode) = 5) NO INHERIT;
|
74
|
+
# SQL
|
75
|
+
# end
|
76
|
+
#
|
77
|
+
# dir.down do
|
78
|
+
# execute <<-SQL
|
79
|
+
# ALTER TABLE distributors
|
80
|
+
# DROP CONSTRAINT zipchk
|
81
|
+
# SQL
|
82
|
+
# end
|
83
|
+
# end
|
84
|
+
# end
|
85
|
+
# end
|
13
86
|
class IrreversibleMigration < MigrationError
|
14
87
|
end
|
15
88
|
|
16
89
|
class DuplicateMigrationVersionError < MigrationError#:nodoc:
|
17
|
-
def initialize(version)
|
18
|
-
|
90
|
+
def initialize(version = nil)
|
91
|
+
if version
|
92
|
+
super("Multiple migrations have the version number #{version}.")
|
93
|
+
else
|
94
|
+
super("Duplicate migration version error.")
|
95
|
+
end
|
19
96
|
end
|
20
97
|
end
|
21
98
|
|
22
99
|
class DuplicateMigrationNameError < MigrationError#:nodoc:
|
23
|
-
def initialize(name)
|
24
|
-
|
100
|
+
def initialize(name = nil)
|
101
|
+
if name
|
102
|
+
super("Multiple migrations have the name #{name}.")
|
103
|
+
else
|
104
|
+
super("Duplicate migration name.")
|
105
|
+
end
|
25
106
|
end
|
26
107
|
end
|
27
108
|
|
28
109
|
class UnknownMigrationVersionError < MigrationError #:nodoc:
|
29
|
-
def initialize(version)
|
30
|
-
|
110
|
+
def initialize(version = nil)
|
111
|
+
if version
|
112
|
+
super("No migration with version number #{version}.")
|
113
|
+
else
|
114
|
+
super("Unknown migration version.")
|
115
|
+
end
|
31
116
|
end
|
32
117
|
end
|
33
118
|
|
34
119
|
class IllegalMigrationNameError < MigrationError#:nodoc:
|
35
|
-
def initialize(name)
|
36
|
-
|
120
|
+
def initialize(name = nil)
|
121
|
+
if name
|
122
|
+
super("Illegal name for migration file: #{name}\n\t(only lower case letters, numbers, and '_' allowed).")
|
123
|
+
else
|
124
|
+
super("Illegal name for migration.")
|
125
|
+
end
|
37
126
|
end
|
38
127
|
end
|
39
128
|
|
40
129
|
class PendingMigrationError < MigrationError#:nodoc:
|
130
|
+
def initialize(message = nil)
|
131
|
+
if !message && defined?(Rails.env)
|
132
|
+
super("Migrations are pending. To resolve this issue, run:\n\n bin/rails db:migrate RAILS_ENV=#{::Rails.env}")
|
133
|
+
elsif !message
|
134
|
+
super("Migrations are pending. To resolve this issue, run:\n\n bin/rails db:migrate")
|
135
|
+
else
|
136
|
+
super
|
137
|
+
end
|
138
|
+
end
|
139
|
+
end
|
140
|
+
|
141
|
+
class ConcurrentMigrationError < MigrationError #:nodoc:
|
142
|
+
DEFAULT_MESSAGE = "Cannot run migrations because another migration process is currently running.".freeze
|
143
|
+
RELEASE_LOCK_FAILED_MESSAGE = "Failed to release advisory lock".freeze
|
144
|
+
|
145
|
+
def initialize(message = DEFAULT_MESSAGE)
|
146
|
+
super
|
147
|
+
end
|
148
|
+
end
|
149
|
+
|
150
|
+
class NoEnvironmentInSchemaError < MigrationError #:nodoc:
|
41
151
|
def initialize
|
42
|
-
|
43
|
-
|
152
|
+
msg = "Environment data not found in the schema. To resolve this issue, run: \n\n bin/rails db:environment:set"
|
153
|
+
if defined?(Rails.env)
|
154
|
+
super("#{msg} RAILS_ENV=#{::Rails.env}")
|
44
155
|
else
|
45
|
-
super(
|
156
|
+
super(msg)
|
157
|
+
end
|
158
|
+
end
|
159
|
+
end
|
160
|
+
|
161
|
+
class ProtectedEnvironmentError < ActiveRecordError #:nodoc:
|
162
|
+
def initialize(env = "production")
|
163
|
+
msg = "You are attempting to run a destructive action against your '#{env}' database.\n".dup
|
164
|
+
msg << "If you are sure you want to continue, run the same command with the environment variable:\n"
|
165
|
+
msg << "DISABLE_DATABASE_ENVIRONMENT_CHECK=1"
|
166
|
+
super(msg)
|
167
|
+
end
|
168
|
+
end
|
169
|
+
|
170
|
+
class EnvironmentMismatchError < ActiveRecordError
|
171
|
+
def initialize(current: nil, stored: nil)
|
172
|
+
msg = "You are attempting to modify a database that was last run in `#{ stored }` environment.\n".dup
|
173
|
+
msg << "You are running in `#{ current }` environment. "
|
174
|
+
msg << "If you are sure you want to continue, first set the environment using:\n\n"
|
175
|
+
msg << " bin/rails db:environment:set"
|
176
|
+
if defined?(Rails.env)
|
177
|
+
super("#{msg} RAILS_ENV=#{::Rails.env}\n\n")
|
178
|
+
else
|
179
|
+
super("#{msg}\n\n")
|
46
180
|
end
|
47
181
|
end
|
48
182
|
end
|
@@ -59,7 +193,7 @@ module ActiveRecord
|
|
59
193
|
#
|
60
194
|
# Example of a simple migration:
|
61
195
|
#
|
62
|
-
# class AddSsl < ActiveRecord::Migration
|
196
|
+
# class AddSsl < ActiveRecord::Migration[5.0]
|
63
197
|
# def up
|
64
198
|
# add_column :accounts, :ssl_enabled, :boolean, default: true
|
65
199
|
# end
|
@@ -79,7 +213,7 @@ module ActiveRecord
|
|
79
213
|
#
|
80
214
|
# Example of a more complex migration that also needs to initialize data:
|
81
215
|
#
|
82
|
-
# class AddSystemSettings < ActiveRecord::Migration
|
216
|
+
# class AddSystemSettings < ActiveRecord::Migration[5.0]
|
83
217
|
# def up
|
84
218
|
# create_table :system_settings do |t|
|
85
219
|
# t.string :name
|
@@ -106,17 +240,18 @@ module ActiveRecord
|
|
106
240
|
#
|
107
241
|
# == Available transformations
|
108
242
|
#
|
243
|
+
# === Creation
|
244
|
+
#
|
245
|
+
# * <tt>create_join_table(table_1, table_2, options)</tt>: Creates a join
|
246
|
+
# table having its name as the lexical order of the first two
|
247
|
+
# arguments. See
|
248
|
+
# ActiveRecord::ConnectionAdapters::SchemaStatements#create_join_table for
|
249
|
+
# details.
|
109
250
|
# * <tt>create_table(name, options)</tt>: Creates a table called +name+ and
|
110
251
|
# makes the table object available to a block that can then add columns to it,
|
111
252
|
# following the same format as +add_column+. See example above. The options hash
|
112
253
|
# is for fragments like "DEFAULT CHARSET=UTF-8" that are appended to the create
|
113
254
|
# table definition.
|
114
|
-
# * <tt>drop_table(name)</tt>: Drops the table called +name+.
|
115
|
-
# * <tt>change_table(name, options)</tt>: Allows to make column alterations to
|
116
|
-
# the table called +name+. It makes the table object available to a block that
|
117
|
-
# can then add/remove columns, indexes or foreign keys to it.
|
118
|
-
# * <tt>rename_table(old_name, new_name)</tt>: Renames the table called +old_name+
|
119
|
-
# to +new_name+.
|
120
255
|
# * <tt>add_column(table_name, column_name, type, options)</tt>: Adds a new column
|
121
256
|
# to the table called +table_name+
|
122
257
|
# named +column_name+ specified to be one of the following types:
|
@@ -127,21 +262,61 @@ module ActiveRecord
|
|
127
262
|
# Other options include <tt>:limit</tt> and <tt>:null</tt> (e.g.
|
128
263
|
# <tt>{ limit: 50, null: false }</tt>) -- see
|
129
264
|
# ActiveRecord::ConnectionAdapters::TableDefinition#column for details.
|
130
|
-
# * <tt>
|
131
|
-
#
|
132
|
-
#
|
133
|
-
# the column to a different type using the same parameters as add_column.
|
134
|
-
# * <tt>remove_column(table_name, column_name, type, options)</tt>: Removes the column
|
135
|
-
# named +column_name+ from the table called +table_name+.
|
265
|
+
# * <tt>add_foreign_key(from_table, to_table, options)</tt>: Adds a new
|
266
|
+
# foreign key. +from_table+ is the table with the key column, +to_table+ contains
|
267
|
+
# the referenced primary key.
|
136
268
|
# * <tt>add_index(table_name, column_names, options)</tt>: Adds a new index
|
137
269
|
# with the name of the column. Other options include
|
138
270
|
# <tt>:name</tt>, <tt>:unique</tt> (e.g.
|
139
271
|
# <tt>{ name: 'users_name_index', unique: true }</tt>) and <tt>:order</tt>
|
140
272
|
# (e.g. <tt>{ order: { name: :desc } }</tt>).
|
141
|
-
# * <tt>
|
142
|
-
#
|
273
|
+
# * <tt>add_reference(:table_name, :reference_name)</tt>: Adds a new column
|
274
|
+
# +reference_name_id+ by default an integer. See
|
275
|
+
# ActiveRecord::ConnectionAdapters::SchemaStatements#add_reference for details.
|
276
|
+
# * <tt>add_timestamps(table_name, options)</tt>: Adds timestamps (+created_at+
|
277
|
+
# and +updated_at+) columns to +table_name+.
|
278
|
+
#
|
279
|
+
# === Modification
|
280
|
+
#
|
281
|
+
# * <tt>change_column(table_name, column_name, type, options)</tt>: Changes
|
282
|
+
# the column to a different type using the same parameters as add_column.
|
283
|
+
# * <tt>change_column_default(table_name, column_name, default_or_changes)</tt>:
|
284
|
+
# Sets a default value for +column_name+ defined by +default_or_changes+ on
|
285
|
+
# +table_name+. Passing a hash containing <tt>:from</tt> and <tt>:to</tt>
|
286
|
+
# as +default_or_changes+ will make this change reversible in the migration.
|
287
|
+
# * <tt>change_column_null(table_name, column_name, null, default = nil)</tt>:
|
288
|
+
# Sets or removes a +NOT NULL+ constraint on +column_name+. The +null+ flag
|
289
|
+
# indicates whether the value can be +NULL+. See
|
290
|
+
# ActiveRecord::ConnectionAdapters::SchemaStatements#change_column_null for
|
291
|
+
# details.
|
292
|
+
# * <tt>change_table(name, options)</tt>: Allows to make column alterations to
|
293
|
+
# the table called +name+. It makes the table object available to a block that
|
294
|
+
# can then add/remove columns, indexes or foreign keys to it.
|
295
|
+
# * <tt>rename_column(table_name, column_name, new_column_name)</tt>: Renames
|
296
|
+
# a column but keeps the type and content.
|
297
|
+
# * <tt>rename_index(table_name, old_name, new_name)</tt>: Renames an index.
|
298
|
+
# * <tt>rename_table(old_name, new_name)</tt>: Renames the table called +old_name+
|
299
|
+
# to +new_name+.
|
300
|
+
#
|
301
|
+
# === Deletion
|
302
|
+
#
|
303
|
+
# * <tt>drop_table(name)</tt>: Drops the table called +name+.
|
304
|
+
# * <tt>drop_join_table(table_1, table_2, options)</tt>: Drops the join table
|
305
|
+
# specified by the given arguments.
|
306
|
+
# * <tt>remove_column(table_name, column_name, type, options)</tt>: Removes the column
|
307
|
+
# named +column_name+ from the table called +table_name+.
|
308
|
+
# * <tt>remove_columns(table_name, *column_names)</tt>: Removes the given
|
309
|
+
# columns from the table definition.
|
310
|
+
# * <tt>remove_foreign_key(from_table, options_or_to_table)</tt>: Removes the
|
311
|
+
# given foreign key from the table called +table_name+.
|
312
|
+
# * <tt>remove_index(table_name, column: column_names)</tt>: Removes the index
|
313
|
+
# specified by +column_names+.
|
143
314
|
# * <tt>remove_index(table_name, name: index_name)</tt>: Removes the index
|
144
315
|
# specified by +index_name+.
|
316
|
+
# * <tt>remove_reference(table_name, ref_name, options)</tt>: Removes the
|
317
|
+
# reference(s) on +table_name+ specified by +ref_name+.
|
318
|
+
# * <tt>remove_timestamps(table_name, options)</tt>: Removes the timestamp
|
319
|
+
# columns (+created_at+ and +updated_at+) from the table definition.
|
145
320
|
#
|
146
321
|
# == Irreversible transformations
|
147
322
|
#
|
@@ -165,24 +340,24 @@ module ActiveRecord
|
|
165
340
|
#
|
166
341
|
# rails generate migration add_fieldname_to_tablename fieldname:string
|
167
342
|
#
|
168
|
-
# This will generate the file <tt>timestamp_add_fieldname_to_tablename</tt>, which will look like this:
|
169
|
-
# class AddFieldnameToTablename < ActiveRecord::Migration
|
343
|
+
# This will generate the file <tt>timestamp_add_fieldname_to_tablename.rb</tt>, which will look like this:
|
344
|
+
# class AddFieldnameToTablename < ActiveRecord::Migration[5.0]
|
170
345
|
# def change
|
171
|
-
# add_column :tablenames, :
|
346
|
+
# add_column :tablenames, :fieldname, :string
|
172
347
|
# end
|
173
348
|
# end
|
174
349
|
#
|
175
350
|
# To run migrations against the currently configured database, use
|
176
|
-
# <tt>
|
351
|
+
# <tt>rails db:migrate</tt>. This will update the database by running all of the
|
177
352
|
# pending migrations, creating the <tt>schema_migrations</tt> table
|
178
353
|
# (see "About the schema_migrations table" section below) if missing. It will also
|
179
354
|
# invoke the db:schema:dump task, which will update your db/schema.rb file
|
180
355
|
# to match the structure of your database.
|
181
356
|
#
|
182
357
|
# To roll the database back to a previous migration version, use
|
183
|
-
# <tt>
|
358
|
+
# <tt>rails db:rollback VERSION=X</tt> where <tt>X</tt> is the version to which
|
184
359
|
# you wish to downgrade. Alternatively, you can also use the STEP option if you
|
185
|
-
# wish to rollback last few migrations. <tt>
|
360
|
+
# wish to rollback last few migrations. <tt>rails db:rollback STEP=2</tt> will rollback
|
186
361
|
# the latest two migrations.
|
187
362
|
#
|
188
363
|
# If any of the migrations throw an <tt>ActiveRecord::IrreversibleMigration</tt> exception,
|
@@ -197,7 +372,7 @@ module ActiveRecord
|
|
197
372
|
#
|
198
373
|
# Not all migrations change the schema. Some just fix the data:
|
199
374
|
#
|
200
|
-
# class RemoveEmptyTags < ActiveRecord::Migration
|
375
|
+
# class RemoveEmptyTags < ActiveRecord::Migration[5.0]
|
201
376
|
# def up
|
202
377
|
# Tag.all.each { |tag| tag.destroy if tag.pages.empty? }
|
203
378
|
# end
|
@@ -210,7 +385,7 @@ module ActiveRecord
|
|
210
385
|
#
|
211
386
|
# Others remove columns when they migrate up instead of down:
|
212
387
|
#
|
213
|
-
# class RemoveUnnecessaryItemAttributes < ActiveRecord::Migration
|
388
|
+
# class RemoveUnnecessaryItemAttributes < ActiveRecord::Migration[5.0]
|
214
389
|
# def up
|
215
390
|
# remove_column :items, :incomplete_items_count
|
216
391
|
# remove_column :items, :completed_items_count
|
@@ -224,7 +399,7 @@ module ActiveRecord
|
|
224
399
|
#
|
225
400
|
# And sometimes you need to do something in SQL not abstracted directly by migrations:
|
226
401
|
#
|
227
|
-
# class MakeJoinUnique < ActiveRecord::Migration
|
402
|
+
# class MakeJoinUnique < ActiveRecord::Migration[5.0]
|
228
403
|
# def up
|
229
404
|
# execute "ALTER TABLE `pages_linked_pages` ADD UNIQUE `page_id_linked_page_id` (`page_id`,`linked_page_id`)"
|
230
405
|
# end
|
@@ -241,7 +416,7 @@ module ActiveRecord
|
|
241
416
|
# <tt>Base#reset_column_information</tt> in order to ensure that the model has the
|
242
417
|
# latest column data from after the new column was added. Example:
|
243
418
|
#
|
244
|
-
# class AddPeopleSalary < ActiveRecord::Migration
|
419
|
+
# class AddPeopleSalary < ActiveRecord::Migration[5.0]
|
245
420
|
# def up
|
246
421
|
# add_column :people, :salary, :integer
|
247
422
|
# Person.reset_column_information
|
@@ -275,21 +450,6 @@ module ActiveRecord
|
|
275
450
|
# The phrase "Updating salaries..." would then be printed, along with the
|
276
451
|
# benchmark for the block when the block completes.
|
277
452
|
#
|
278
|
-
# == About the schema_migrations table
|
279
|
-
#
|
280
|
-
# Rails versions 2.0 and prior used to create a table called
|
281
|
-
# <tt>schema_info</tt> when using migrations. This table contained the
|
282
|
-
# version of the schema as of the last applied migration.
|
283
|
-
#
|
284
|
-
# Starting with Rails 2.1, the <tt>schema_info</tt> table is
|
285
|
-
# (automatically) replaced by the <tt>schema_migrations</tt> table, which
|
286
|
-
# contains the version numbers of all the migrations applied.
|
287
|
-
#
|
288
|
-
# As a result, it is now possible to add migration files that are numbered
|
289
|
-
# lower than the current schema version: when migrating up, those
|
290
|
-
# never-applied "interleaved" migrations will be automatically applied, and
|
291
|
-
# when migrating down, never-applied "interleaved" migrations will be skipped.
|
292
|
-
#
|
293
453
|
# == Timestamped Migrations
|
294
454
|
#
|
295
455
|
# By default, Rails generates migrations that look like:
|
@@ -307,15 +467,14 @@ module ActiveRecord
|
|
307
467
|
#
|
308
468
|
# == Reversible Migrations
|
309
469
|
#
|
310
|
-
# Starting with Rails 3.1, you will be able to define reversible migrations.
|
311
470
|
# Reversible migrations are migrations that know how to go +down+ for you.
|
312
|
-
# You simply supply the +up+ logic, and the Migration system
|
471
|
+
# You simply supply the +up+ logic, and the Migration system figures out
|
313
472
|
# how to execute the down commands for you.
|
314
473
|
#
|
315
474
|
# To define a reversible migration, define the +change+ method in your
|
316
475
|
# migration like this:
|
317
476
|
#
|
318
|
-
# class TenderloveMigration < ActiveRecord::Migration
|
477
|
+
# class TenderloveMigration < ActiveRecord::Migration[5.0]
|
319
478
|
# def change
|
320
479
|
# create_table(:horses) do |t|
|
321
480
|
# t.column :content, :text
|
@@ -345,7 +504,7 @@ module ActiveRecord
|
|
345
504
|
# can't execute inside a transaction though, and for these situations
|
346
505
|
# you can turn the automatic transactions off.
|
347
506
|
#
|
348
|
-
# class ChangeEnum < ActiveRecord::Migration
|
507
|
+
# class ChangeEnum < ActiveRecord::Migration[5.0]
|
349
508
|
# disable_ddl_transaction!
|
350
509
|
#
|
351
510
|
# def up
|
@@ -356,11 +515,35 @@ module ActiveRecord
|
|
356
515
|
# Remember that you can still open your own transactions, even if you
|
357
516
|
# are in a Migration with <tt>self.disable_ddl_transaction!</tt>.
|
358
517
|
class Migration
|
359
|
-
autoload :CommandRecorder,
|
518
|
+
autoload :CommandRecorder, "active_record/migration/command_recorder"
|
519
|
+
autoload :Compatibility, "active_record/migration/compatibility"
|
360
520
|
|
521
|
+
# This must be defined before the inherited hook, below
|
522
|
+
class Current < Migration # :nodoc:
|
523
|
+
end
|
524
|
+
|
525
|
+
def self.inherited(subclass) # :nodoc:
|
526
|
+
super
|
527
|
+
if subclass.superclass == Migration
|
528
|
+
raise StandardError, "Directly inheriting from ActiveRecord::Migration is not supported. " \
|
529
|
+
"Please specify the Rails release the migration was written for:\n" \
|
530
|
+
"\n" \
|
531
|
+
" class #{subclass} < ActiveRecord::Migration[4.2]"
|
532
|
+
end
|
533
|
+
end
|
534
|
+
|
535
|
+
def self.[](version)
|
536
|
+
Compatibility.find(version)
|
537
|
+
end
|
538
|
+
|
539
|
+
def self.current_version
|
540
|
+
ActiveRecord::VERSION::STRING.to_f
|
541
|
+
end
|
542
|
+
|
543
|
+
MigrationFilenameRegexp = /\A([0-9]+)_([_a-z0-9]*)\.?([_a-z0-9]*)?\.rb\z/ # :nodoc:
|
361
544
|
|
362
545
|
# This class is used to verify that all migrations have been run before
|
363
|
-
# loading a web page if config.active_record.migration_error is set to :page_load
|
546
|
+
# loading a web page if <tt>config.active_record.migration_error</tt> is set to :page_load
|
364
547
|
class CheckPending
|
365
548
|
def initialize(app)
|
366
549
|
@app = app
|
@@ -368,38 +551,42 @@ module ActiveRecord
|
|
368
551
|
end
|
369
552
|
|
370
553
|
def call(env)
|
371
|
-
|
372
|
-
|
373
|
-
|
374
|
-
|
375
|
-
@last_check = mtime
|
376
|
-
end
|
554
|
+
mtime = ActiveRecord::Base.connection.migration_context.last_migration.mtime.to_i
|
555
|
+
if @last_check < mtime
|
556
|
+
ActiveRecord::Migration.check_pending!(connection)
|
557
|
+
@last_check = mtime
|
377
558
|
end
|
378
559
|
@app.call(env)
|
379
560
|
end
|
380
561
|
|
381
562
|
private
|
382
563
|
|
383
|
-
|
384
|
-
|
385
|
-
|
564
|
+
def connection
|
565
|
+
ActiveRecord::Base.connection
|
566
|
+
end
|
386
567
|
end
|
387
568
|
|
388
569
|
class << self
|
389
570
|
attr_accessor :delegate # :nodoc:
|
390
571
|
attr_accessor :disable_ddl_transaction # :nodoc:
|
391
572
|
|
573
|
+
def nearest_delegate # :nodoc:
|
574
|
+
delegate || superclass.nearest_delegate
|
575
|
+
end
|
576
|
+
|
577
|
+
# Raises <tt>ActiveRecord::PendingMigrationError</tt> error if any migrations are pending.
|
392
578
|
def check_pending!(connection = Base.connection)
|
393
|
-
raise ActiveRecord::PendingMigrationError if
|
579
|
+
raise ActiveRecord::PendingMigrationError if connection.migration_context.needs_migration?
|
394
580
|
end
|
395
581
|
|
396
582
|
def load_schema_if_pending!
|
397
|
-
if
|
398
|
-
#
|
399
|
-
|
583
|
+
if Base.connection.migration_context.needs_migration? || !Base.connection.migration_context.any_migrations?
|
584
|
+
# Roundtrip to Rake to allow plugins to hook into database initialization.
|
585
|
+
root = defined?(ENGINE_ROOT) ? ENGINE_ROOT : Rails.root
|
586
|
+
FileUtils.cd(root) do
|
400
587
|
current_config = Base.connection_config
|
401
588
|
Base.clear_all_connections!
|
402
|
-
system("bin/
|
589
|
+
system("bin/rails db:test:prepare")
|
403
590
|
# Establish a new connection, the old database may be gone (db:test:prepare uses purge)
|
404
591
|
Base.establish_connection(current_config)
|
405
592
|
end
|
@@ -414,14 +601,17 @@ module ActiveRecord
|
|
414
601
|
end
|
415
602
|
|
416
603
|
def method_missing(name, *args, &block) # :nodoc:
|
417
|
-
|
604
|
+
nearest_delegate.send(name, *args, &block)
|
418
605
|
end
|
419
606
|
|
420
607
|
def migrate(direction)
|
421
608
|
new.migrate direction
|
422
609
|
end
|
423
610
|
|
424
|
-
# Disable
|
611
|
+
# Disable the transaction wrapping this migration.
|
612
|
+
# You can still create your own transactions even after calling #disable_ddl_transaction!
|
613
|
+
#
|
614
|
+
# For more details read the {"Transactional Migrations" section above}[rdoc-ref:Migration].
|
425
615
|
def disable_ddl_transaction!
|
426
616
|
@disable_ddl_transaction = true
|
427
617
|
end
|
@@ -451,7 +641,7 @@ module ActiveRecord
|
|
451
641
|
# and create the table 'apples' on the way up, and the reverse
|
452
642
|
# on the way down.
|
453
643
|
#
|
454
|
-
# class FixTLMigration < ActiveRecord::Migration
|
644
|
+
# class FixTLMigration < ActiveRecord::Migration[5.0]
|
455
645
|
# def change
|
456
646
|
# revert do
|
457
647
|
# create_table(:horses) do |t|
|
@@ -468,9 +658,9 @@ module ActiveRecord
|
|
468
658
|
# Or equivalently, if +TenderloveMigration+ is defined as in the
|
469
659
|
# documentation for Migration:
|
470
660
|
#
|
471
|
-
# require_relative '
|
661
|
+
# require_relative '20121212123456_tenderlove_migration'
|
472
662
|
#
|
473
|
-
# class FixupTLMigration < ActiveRecord::Migration
|
663
|
+
# class FixupTLMigration < ActiveRecord::Migration[5.0]
|
474
664
|
# def change
|
475
665
|
# revert TenderloveMigration
|
476
666
|
#
|
@@ -484,13 +674,13 @@ module ActiveRecord
|
|
484
674
|
def revert(*migration_classes)
|
485
675
|
run(*migration_classes.reverse, revert: true) unless migration_classes.empty?
|
486
676
|
if block_given?
|
487
|
-
if
|
488
|
-
|
677
|
+
if connection.respond_to? :revert
|
678
|
+
connection.revert { yield }
|
489
679
|
else
|
490
|
-
recorder = CommandRecorder.new(
|
680
|
+
recorder = CommandRecorder.new(connection)
|
491
681
|
@connection = recorder
|
492
682
|
suppress_messages do
|
493
|
-
|
683
|
+
connection.revert { yield }
|
494
684
|
end
|
495
685
|
@connection = recorder.delegate
|
496
686
|
recorder.commands.each do |cmd, args, block|
|
@@ -501,10 +691,10 @@ module ActiveRecord
|
|
501
691
|
end
|
502
692
|
|
503
693
|
def reverting?
|
504
|
-
|
694
|
+
connection.respond_to?(:reverting) && connection.reverting
|
505
695
|
end
|
506
696
|
|
507
|
-
|
697
|
+
ReversibleBlockHelper = Struct.new(:reverting) do # :nodoc:
|
508
698
|
def up
|
509
699
|
yield unless reverting
|
510
700
|
end
|
@@ -523,7 +713,7 @@ module ActiveRecord
|
|
523
713
|
# when the three columns 'first_name', 'last_name' and 'full_name' exist,
|
524
714
|
# even when migrating down:
|
525
715
|
#
|
526
|
-
# class SplitNameMigration < ActiveRecord::Migration
|
716
|
+
# class SplitNameMigration < ActiveRecord::Migration[5.0]
|
527
717
|
# def change
|
528
718
|
# add_column :users, :first_name, :string
|
529
719
|
# add_column :users, :last_name, :string
|
@@ -542,7 +732,25 @@ module ActiveRecord
|
|
542
732
|
# end
|
543
733
|
def reversible
|
544
734
|
helper = ReversibleBlockHelper.new(reverting?)
|
545
|
-
execute_block{ yield helper }
|
735
|
+
execute_block { yield helper }
|
736
|
+
end
|
737
|
+
|
738
|
+
# Used to specify an operation that is only run when migrating up
|
739
|
+
# (for example, populating a new column with its initial values).
|
740
|
+
#
|
741
|
+
# In the following example, the new column +published+ will be given
|
742
|
+
# the value +true+ for all existing records.
|
743
|
+
#
|
744
|
+
# class AddPublishedToPosts < ActiveRecord::Migration[5.2]
|
745
|
+
# def change
|
746
|
+
# add_column :posts, :published, :boolean, default: false
|
747
|
+
# up_only do
|
748
|
+
# execute "update posts set published = 'true'"
|
749
|
+
# end
|
750
|
+
# end
|
751
|
+
# end
|
752
|
+
def up_only
|
753
|
+
execute_block { yield } unless reverting?
|
546
754
|
end
|
547
755
|
|
548
756
|
# Runs the given migration classes.
|
@@ -558,7 +766,7 @@ module ActiveRecord
|
|
558
766
|
revert { run(*migration_classes, direction: dir, revert: true) }
|
559
767
|
else
|
560
768
|
migration_classes.each do |migration_class|
|
561
|
-
migration_class.new.exec_migration(
|
769
|
+
migration_class.new.exec_migration(connection, dir)
|
562
770
|
end
|
563
771
|
end
|
564
772
|
end
|
@@ -584,7 +792,7 @@ module ActiveRecord
|
|
584
792
|
when :down then announce "reverting"
|
585
793
|
end
|
586
794
|
|
587
|
-
time
|
795
|
+
time = nil
|
588
796
|
ActiveRecord::Base.connection_pool.with_connection do |conn|
|
589
797
|
time = Benchmark.measure do
|
590
798
|
exec_migration(conn, direction)
|
@@ -612,7 +820,7 @@ module ActiveRecord
|
|
612
820
|
@connection = nil
|
613
821
|
end
|
614
822
|
|
615
|
-
def write(text="")
|
823
|
+
def write(text = "")
|
616
824
|
puts(text) if verbose
|
617
825
|
end
|
618
826
|
|
@@ -622,7 +830,7 @@ module ActiveRecord
|
|
622
830
|
write "== %s %s" % [text, "=" * length]
|
623
831
|
end
|
624
832
|
|
625
|
-
def say(message, subitem=false)
|
833
|
+
def say(message, subitem = false)
|
626
834
|
write "#{subitem ? " ->" : "--"} #{message}"
|
627
835
|
end
|
628
836
|
|
@@ -647,13 +855,14 @@ module ActiveRecord
|
|
647
855
|
end
|
648
856
|
|
649
857
|
def method_missing(method, *arguments, &block)
|
650
|
-
arg_list = arguments.map
|
858
|
+
arg_list = arguments.map(&:inspect) * ", "
|
651
859
|
|
652
860
|
say_with_time "#{method}(#{arg_list})" do
|
653
|
-
unless
|
861
|
+
unless connection.respond_to? :revert
|
654
862
|
unless arguments.empty? || [:execute, :enable_extension, :disable_extension].include?(method)
|
655
863
|
arguments[0] = proper_table_name(arguments.first, table_name_options)
|
656
|
-
if [:rename_table, :add_foreign_key].include?(method)
|
864
|
+
if [:rename_table, :add_foreign_key].include?(method) ||
|
865
|
+
(method == :remove_foreign_key && !arguments.second.is_a?(Hash))
|
657
866
|
arguments[1] = proper_table_name(arguments.second, table_name_options)
|
658
867
|
end
|
659
868
|
end
|
@@ -668,23 +877,25 @@ module ActiveRecord
|
|
668
877
|
|
669
878
|
FileUtils.mkdir_p(destination) unless File.exist?(destination)
|
670
879
|
|
671
|
-
destination_migrations = ActiveRecord::
|
880
|
+
destination_migrations = ActiveRecord::MigrationContext.new(destination).migrations
|
672
881
|
last = destination_migrations.last
|
673
882
|
sources.each do |scope, path|
|
674
|
-
source_migrations = ActiveRecord::
|
883
|
+
source_migrations = ActiveRecord::MigrationContext.new(path).migrations
|
675
884
|
|
676
885
|
source_migrations.each do |migration|
|
677
886
|
source = File.binread(migration.filename)
|
678
887
|
inserted_comment = "# This migration comes from #{scope} (originally #{migration.version})\n"
|
679
|
-
|
888
|
+
magic_comments = "".dup
|
889
|
+
loop do
|
680
890
|
# If we have a magic comment in the original migration,
|
681
891
|
# insert our comment after the first newline(end of the magic comment line)
|
682
892
|
# so the magic keep working.
|
683
893
|
# Note that magic comments must be at the first line(except sh-bang).
|
684
|
-
source
|
685
|
-
|
686
|
-
|
894
|
+
source.sub!(/\A(?:#.*\b(?:en)?coding:\s*\S+|#\s*frozen_string_literal:\s*(?:true|false)).*\n/) do |magic_comment|
|
895
|
+
magic_comments << magic_comment; ""
|
896
|
+
end || break
|
687
897
|
end
|
898
|
+
source = "#{magic_comments}#{inserted_comment}#{source}"
|
688
899
|
|
689
900
|
if duplicate = destination_migrations.detect { |m| m.name == migration.name }
|
690
901
|
if options[:on_skip] && duplicate.scope != scope.to_s
|
@@ -728,7 +939,9 @@ module ActiveRecord
|
|
728
939
|
end
|
729
940
|
end
|
730
941
|
|
731
|
-
|
942
|
+
# Builds a hash for use in ActiveRecord::Migration#proper_table_name using
|
943
|
+
# the Active Record object's table_name prefix and suffix
|
944
|
+
def table_name_options(config = ActiveRecord::Base) #:nodoc:
|
732
945
|
{
|
733
946
|
table_name_prefix: config.table_name_prefix,
|
734
947
|
table_name_suffix: config.table_name_suffix
|
@@ -736,19 +949,18 @@ module ActiveRecord
|
|
736
949
|
end
|
737
950
|
|
738
951
|
private
|
739
|
-
|
740
|
-
|
741
|
-
|
742
|
-
|
743
|
-
|
952
|
+
def execute_block
|
953
|
+
if connection.respond_to? :execute_block
|
954
|
+
super # use normal delegation to record the block
|
955
|
+
else
|
956
|
+
yield
|
957
|
+
end
|
744
958
|
end
|
745
|
-
end
|
746
959
|
end
|
747
960
|
|
748
961
|
# MigrationProxy is used to defer loading of the actual migration classes
|
749
962
|
# until they are needed
|
750
|
-
|
751
|
-
|
963
|
+
MigrationProxy = Struct.new(:name, :version, :filename, :scope) do
|
752
964
|
def initialize(name, version, filename, scope)
|
753
965
|
super
|
754
966
|
@migration = nil
|
@@ -774,7 +986,6 @@ module ActiveRecord
|
|
774
986
|
require(File.expand_path(filename))
|
775
987
|
name.constantize.new(name, version)
|
776
988
|
end
|
777
|
-
|
778
989
|
end
|
779
990
|
|
780
991
|
class NullMigration < MigrationProxy #:nodoc:
|
@@ -787,131 +998,185 @@ module ActiveRecord
|
|
787
998
|
end
|
788
999
|
end
|
789
1000
|
|
790
|
-
class
|
791
|
-
|
792
|
-
attr_writer :migrations_paths
|
793
|
-
alias :migrations_path= :migrations_paths=
|
794
|
-
|
795
|
-
def migrate(migrations_paths, target_version = nil, &block)
|
796
|
-
case
|
797
|
-
when target_version.nil?
|
798
|
-
up(migrations_paths, target_version, &block)
|
799
|
-
when current_version == 0 && target_version == 0
|
800
|
-
[]
|
801
|
-
when current_version > target_version
|
802
|
-
down(migrations_paths, target_version, &block)
|
803
|
-
else
|
804
|
-
up(migrations_paths, target_version, &block)
|
805
|
-
end
|
806
|
-
end
|
1001
|
+
class MigrationContext # :nodoc:
|
1002
|
+
attr_reader :migrations_paths
|
807
1003
|
|
808
|
-
|
809
|
-
|
810
|
-
|
1004
|
+
def initialize(migrations_paths)
|
1005
|
+
@migrations_paths = migrations_paths
|
1006
|
+
end
|
811
1007
|
|
812
|
-
|
813
|
-
|
1008
|
+
def migrate(target_version = nil, &block)
|
1009
|
+
case
|
1010
|
+
when target_version.nil?
|
1011
|
+
up(target_version, &block)
|
1012
|
+
when current_version == 0 && target_version == 0
|
1013
|
+
[]
|
1014
|
+
when current_version > target_version
|
1015
|
+
down(target_version, &block)
|
1016
|
+
else
|
1017
|
+
up(target_version, &block)
|
814
1018
|
end
|
1019
|
+
end
|
1020
|
+
|
1021
|
+
def rollback(steps = 1)
|
1022
|
+
move(:down, steps)
|
1023
|
+
end
|
815
1024
|
|
816
|
-
|
817
|
-
|
818
|
-
|
1025
|
+
def forward(steps = 1)
|
1026
|
+
move(:up, steps)
|
1027
|
+
end
|
819
1028
|
|
820
|
-
|
1029
|
+
def up(target_version = nil)
|
1030
|
+
selected_migrations = if block_given?
|
1031
|
+
migrations.select { |m| yield m }
|
1032
|
+
else
|
1033
|
+
migrations
|
821
1034
|
end
|
822
1035
|
|
823
|
-
|
824
|
-
|
825
|
-
migrations.select! { |m| yield m } if block_given?
|
1036
|
+
Migrator.new(:up, selected_migrations, target_version).migrate
|
1037
|
+
end
|
826
1038
|
|
827
|
-
|
1039
|
+
def down(target_version = nil)
|
1040
|
+
selected_migrations = if block_given?
|
1041
|
+
migrations.select { |m| yield m }
|
1042
|
+
else
|
1043
|
+
migrations
|
828
1044
|
end
|
829
1045
|
|
830
|
-
|
831
|
-
|
832
|
-
end
|
1046
|
+
Migrator.new(:down, selected_migrations, target_version).migrate
|
1047
|
+
end
|
833
1048
|
|
834
|
-
|
835
|
-
|
836
|
-
|
1049
|
+
def run(direction, target_version)
|
1050
|
+
Migrator.new(direction, migrations, target_version).run
|
1051
|
+
end
|
837
1052
|
|
838
|
-
|
839
|
-
|
840
|
-
|
1053
|
+
def open
|
1054
|
+
Migrator.new(:up, migrations, nil)
|
1055
|
+
end
|
841
1056
|
|
842
|
-
|
843
|
-
|
844
|
-
|
845
|
-
|
846
|
-
|
847
|
-
end
|
1057
|
+
def get_all_versions
|
1058
|
+
if SchemaMigration.table_exists?
|
1059
|
+
SchemaMigration.all_versions.map(&:to_i)
|
1060
|
+
else
|
1061
|
+
[]
|
848
1062
|
end
|
1063
|
+
end
|
849
1064
|
|
850
|
-
|
851
|
-
|
852
|
-
|
1065
|
+
def current_version
|
1066
|
+
get_all_versions.max || 0
|
1067
|
+
rescue ActiveRecord::NoDatabaseError
|
1068
|
+
end
|
853
1069
|
|
854
|
-
|
855
|
-
|
856
|
-
|
1070
|
+
def needs_migration?
|
1071
|
+
(migrations.collect(&:version) - get_all_versions).size > 0
|
1072
|
+
end
|
857
1073
|
|
858
|
-
|
859
|
-
|
860
|
-
|
1074
|
+
def any_migrations?
|
1075
|
+
migrations.any?
|
1076
|
+
end
|
861
1077
|
|
862
|
-
|
863
|
-
|
864
|
-
|
1078
|
+
def last_migration #:nodoc:
|
1079
|
+
migrations.last || NullMigration.new
|
1080
|
+
end
|
865
1081
|
|
866
|
-
|
867
|
-
|
868
|
-
|
1082
|
+
def parse_migration_filename(filename) # :nodoc:
|
1083
|
+
File.basename(filename).scan(Migration::MigrationFilenameRegexp).first
|
1084
|
+
end
|
869
1085
|
|
870
|
-
|
871
|
-
|
872
|
-
|
873
|
-
|
1086
|
+
def migrations
|
1087
|
+
migrations = migration_files.map do |file|
|
1088
|
+
version, name, scope = parse_migration_filename(file)
|
1089
|
+
raise IllegalMigrationNameError.new(file) unless version
|
1090
|
+
version = version.to_i
|
1091
|
+
name = name.camelize
|
1092
|
+
|
1093
|
+
MigrationProxy.new(name, version, file, scope)
|
874
1094
|
end
|
875
1095
|
|
876
|
-
|
877
|
-
|
1096
|
+
migrations.sort_by(&:version)
|
1097
|
+
end
|
1098
|
+
|
1099
|
+
def migrations_status
|
1100
|
+
db_list = ActiveRecord::SchemaMigration.normalized_versions
|
1101
|
+
|
1102
|
+
file_list = migration_files.map do |file|
|
1103
|
+
version, name, scope = parse_migration_filename(file)
|
1104
|
+
raise IllegalMigrationNameError.new(file) unless version
|
1105
|
+
version = ActiveRecord::SchemaMigration.normalize_migration_number(version)
|
1106
|
+
status = db_list.delete(version) ? "up" : "down"
|
1107
|
+
[status, version, (name + scope).humanize]
|
1108
|
+
end.compact
|
1109
|
+
|
1110
|
+
db_list.map! do |version|
|
1111
|
+
["up", version, "********** NO FILE **********"]
|
878
1112
|
end
|
879
1113
|
|
880
|
-
|
881
|
-
|
1114
|
+
(db_list + file_list).sort_by { |_, version, _| version }
|
1115
|
+
end
|
882
1116
|
|
883
|
-
|
1117
|
+
def migration_files
|
1118
|
+
paths = Array(migrations_paths)
|
1119
|
+
Dir[*paths.flat_map { |path| "#{path}/**/[0-9]*_*.rb" }]
|
1120
|
+
end
|
884
1121
|
|
885
|
-
|
886
|
-
|
1122
|
+
def current_environment
|
1123
|
+
ActiveRecord::ConnectionHandling::DEFAULT_ENV.call
|
1124
|
+
end
|
887
1125
|
|
888
|
-
|
889
|
-
|
890
|
-
|
1126
|
+
def protected_environment?
|
1127
|
+
ActiveRecord::Base.protected_environments.include?(last_stored_environment) if last_stored_environment
|
1128
|
+
end
|
1129
|
+
|
1130
|
+
def last_stored_environment
|
1131
|
+
return nil if current_version == 0
|
1132
|
+
raise NoEnvironmentInSchemaError unless ActiveRecord::InternalMetadata.table_exists?
|
1133
|
+
|
1134
|
+
environment = ActiveRecord::InternalMetadata[:environment]
|
1135
|
+
raise NoEnvironmentInSchemaError unless environment
|
1136
|
+
environment
|
1137
|
+
end
|
891
1138
|
|
892
|
-
|
1139
|
+
private
|
1140
|
+
def move(direction, steps)
|
1141
|
+
migrator = Migrator.new(direction, migrations)
|
1142
|
+
|
1143
|
+
if current_version != 0 && !migrator.current_migration
|
1144
|
+
raise UnknownMigrationVersionError.new(current_version)
|
893
1145
|
end
|
894
1146
|
|
895
|
-
|
1147
|
+
start_index =
|
1148
|
+
if current_version == 0
|
1149
|
+
0
|
1150
|
+
else
|
1151
|
+
migrator.migrations.index(migrator.current_migration)
|
1152
|
+
end
|
1153
|
+
|
1154
|
+
finish = migrator.migrations[start_index + steps]
|
1155
|
+
version = finish ? finish.version : 0
|
1156
|
+
send(direction, version)
|
896
1157
|
end
|
1158
|
+
end
|
897
1159
|
|
898
|
-
|
1160
|
+
class Migrator # :nodoc:
|
1161
|
+
class << self
|
1162
|
+
attr_accessor :migrations_paths
|
899
1163
|
|
900
|
-
def
|
901
|
-
|
902
|
-
|
1164
|
+
def migrations_path=(path)
|
1165
|
+
ActiveSupport::Deprecation.warn \
|
1166
|
+
"`ActiveRecord::Migrator.migrations_path=` is now deprecated and will be removed in Rails 6.0. " \
|
1167
|
+
"You can set the `migrations_paths` on the `connection` instead through the `database.yml`."
|
1168
|
+
self.migrations_paths = [path]
|
1169
|
+
end
|
903
1170
|
|
904
|
-
|
905
|
-
|
906
|
-
|
907
|
-
send(direction, migrations_paths, version)
|
908
|
-
end
|
1171
|
+
# For cases where a table doesn't exist like loading from schema cache
|
1172
|
+
def current_version
|
1173
|
+
MigrationContext.new(migrations_paths).current_version
|
909
1174
|
end
|
910
1175
|
end
|
911
1176
|
|
912
|
-
|
913
|
-
raise StandardError.new("This database does not yet support migrations") unless Base.connection.supports_migrations?
|
1177
|
+
self.migrations_paths = ["db/migrate"]
|
914
1178
|
|
1179
|
+
def initialize(direction, migrations, target_version = nil)
|
915
1180
|
@direction = direction
|
916
1181
|
@target_version = target_version
|
917
1182
|
@migrated_versions = nil
|
@@ -919,7 +1184,8 @@ module ActiveRecord
|
|
919
1184
|
|
920
1185
|
validate(@migrations)
|
921
1186
|
|
922
|
-
|
1187
|
+
ActiveRecord::SchemaMigration.create_table
|
1188
|
+
ActiveRecord::InternalMetadata.create_table
|
923
1189
|
end
|
924
1190
|
|
925
1191
|
def current_version
|
@@ -932,32 +1198,18 @@ module ActiveRecord
|
|
932
1198
|
alias :current :current_migration
|
933
1199
|
|
934
1200
|
def run
|
935
|
-
|
936
|
-
|
937
|
-
|
938
|
-
|
939
|
-
execute_migration_in_transaction(migration, @direction)
|
940
|
-
rescue => e
|
941
|
-
canceled_msg = use_transaction?(migration) ? ", this migration was canceled" : ""
|
942
|
-
raise StandardError, "An error has occurred#{canceled_msg}:\n\n#{e}", e.backtrace
|
943
|
-
end
|
1201
|
+
if use_advisory_lock?
|
1202
|
+
with_advisory_lock { run_without_lock }
|
1203
|
+
else
|
1204
|
+
run_without_lock
|
944
1205
|
end
|
945
1206
|
end
|
946
1207
|
|
947
1208
|
def migrate
|
948
|
-
if
|
949
|
-
|
950
|
-
|
951
|
-
|
952
|
-
runnable.each do |migration|
|
953
|
-
Base.logger.info "Migrating to #{migration.name} (#{migration.version})" if Base.logger
|
954
|
-
|
955
|
-
begin
|
956
|
-
execute_migration_in_transaction(migration, @direction)
|
957
|
-
rescue => e
|
958
|
-
canceled_msg = use_transaction?(migration) ? "this and " : ""
|
959
|
-
raise StandardError, "An error has occurred, #{canceled_msg}all later migrations canceled:\n\n#{e}", e.backtrace
|
960
|
-
end
|
1209
|
+
if use_advisory_lock?
|
1210
|
+
with_advisory_lock { migrate_without_lock }
|
1211
|
+
else
|
1212
|
+
migrate_without_lock
|
961
1213
|
end
|
962
1214
|
end
|
963
1215
|
|
@@ -982,70 +1234,145 @@ module ActiveRecord
|
|
982
1234
|
end
|
983
1235
|
|
984
1236
|
def migrated
|
985
|
-
@migrated_versions
|
1237
|
+
@migrated_versions || load_migrated
|
986
1238
|
end
|
987
1239
|
|
988
|
-
|
989
|
-
|
990
|
-
migrated.include?(migration.version.to_i)
|
1240
|
+
def load_migrated
|
1241
|
+
@migrated_versions = Set.new(Base.connection.migration_context.get_all_versions)
|
991
1242
|
end
|
992
1243
|
|
993
|
-
|
994
|
-
|
995
|
-
|
996
|
-
|
1244
|
+
private
|
1245
|
+
|
1246
|
+
# Used for running a specific migration.
|
1247
|
+
def run_without_lock
|
1248
|
+
migration = migrations.detect { |m| m.version == @target_version }
|
1249
|
+
raise UnknownMigrationVersionError.new(@target_version) if migration.nil?
|
1250
|
+
result = execute_migration_in_transaction(migration, @direction)
|
1251
|
+
|
1252
|
+
record_environment
|
1253
|
+
result
|
997
1254
|
end
|
998
|
-
end
|
999
1255
|
|
1000
|
-
|
1001
|
-
|
1002
|
-
|
1256
|
+
# Used for running multiple migrations up to or down to a certain value.
|
1257
|
+
def migrate_without_lock
|
1258
|
+
if invalid_target?
|
1259
|
+
raise UnknownMigrationVersionError.new(@target_version)
|
1260
|
+
end
|
1003
1261
|
|
1004
|
-
|
1005
|
-
|
1006
|
-
|
1262
|
+
result = runnable.each do |migration|
|
1263
|
+
execute_migration_in_transaction(migration, @direction)
|
1264
|
+
end
|
1007
1265
|
|
1008
|
-
|
1009
|
-
|
1010
|
-
|
1266
|
+
record_environment
|
1267
|
+
result
|
1268
|
+
end
|
1011
1269
|
|
1012
|
-
|
1013
|
-
|
1014
|
-
|
1270
|
+
# Stores the current environment in the database.
|
1271
|
+
def record_environment
|
1272
|
+
return if down?
|
1273
|
+
ActiveRecord::InternalMetadata[:environment] = ActiveRecord::Base.connection.migration_context.current_environment
|
1274
|
+
end
|
1015
1275
|
|
1016
|
-
|
1017
|
-
|
1018
|
-
|
1276
|
+
def ran?(migration)
|
1277
|
+
migrated.include?(migration.version.to_i)
|
1278
|
+
end
|
1019
1279
|
|
1020
|
-
|
1021
|
-
|
1022
|
-
|
1023
|
-
ActiveRecord::SchemaMigration.where(:version => version.to_s).delete_all
|
1024
|
-
else
|
1025
|
-
migrated << version
|
1026
|
-
ActiveRecord::SchemaMigration.create!(:version => version.to_s)
|
1280
|
+
# Return true if a valid version is not provided.
|
1281
|
+
def invalid_target?
|
1282
|
+
@target_version && @target_version != 0 && !target
|
1027
1283
|
end
|
1028
|
-
end
|
1029
1284
|
|
1030
|
-
|
1031
|
-
|
1032
|
-
|
1285
|
+
def execute_migration_in_transaction(migration, direction)
|
1286
|
+
return if down? && !migrated.include?(migration.version.to_i)
|
1287
|
+
return if up? && migrated.include?(migration.version.to_i)
|
1033
1288
|
|
1034
|
-
|
1035
|
-
@direction == :down
|
1036
|
-
end
|
1289
|
+
Base.logger.info "Migrating to #{migration.name} (#{migration.version})" if Base.logger
|
1037
1290
|
|
1038
|
-
|
1039
|
-
|
1040
|
-
|
1041
|
-
|
1042
|
-
|
1291
|
+
ddl_transaction(migration) do
|
1292
|
+
migration.migrate(direction)
|
1293
|
+
record_version_state_after_migrating(migration.version)
|
1294
|
+
end
|
1295
|
+
rescue => e
|
1296
|
+
msg = "An error has occurred, ".dup
|
1297
|
+
msg << "this and " if use_transaction?(migration)
|
1298
|
+
msg << "all later migrations canceled:\n\n#{e}"
|
1299
|
+
raise StandardError, msg, e.backtrace
|
1300
|
+
end
|
1301
|
+
|
1302
|
+
def target
|
1303
|
+
migrations.detect { |m| m.version == @target_version }
|
1304
|
+
end
|
1305
|
+
|
1306
|
+
def finish
|
1307
|
+
migrations.index(target) || migrations.size - 1
|
1308
|
+
end
|
1309
|
+
|
1310
|
+
def start
|
1311
|
+
up? ? 0 : (migrations.index(current) || 0)
|
1312
|
+
end
|
1313
|
+
|
1314
|
+
def validate(migrations)
|
1315
|
+
name, = migrations.group_by(&:name).find { |_, v| v.length > 1 }
|
1316
|
+
raise DuplicateMigrationNameError.new(name) if name
|
1317
|
+
|
1318
|
+
version, = migrations.group_by(&:version).find { |_, v| v.length > 1 }
|
1319
|
+
raise DuplicateMigrationVersionError.new(version) if version
|
1320
|
+
end
|
1321
|
+
|
1322
|
+
def record_version_state_after_migrating(version)
|
1323
|
+
if down?
|
1324
|
+
migrated.delete(version)
|
1325
|
+
ActiveRecord::SchemaMigration.where(version: version.to_s).delete_all
|
1326
|
+
else
|
1327
|
+
migrated << version
|
1328
|
+
ActiveRecord::SchemaMigration.create!(version: version.to_s)
|
1329
|
+
end
|
1330
|
+
end
|
1331
|
+
|
1332
|
+
def up?
|
1333
|
+
@direction == :up
|
1334
|
+
end
|
1335
|
+
|
1336
|
+
def down?
|
1337
|
+
@direction == :down
|
1338
|
+
end
|
1339
|
+
|
1340
|
+
# Wrap the migration in a transaction only if supported by the adapter.
|
1341
|
+
def ddl_transaction(migration)
|
1342
|
+
if use_transaction?(migration)
|
1343
|
+
Base.transaction { yield }
|
1344
|
+
else
|
1345
|
+
yield
|
1346
|
+
end
|
1347
|
+
end
|
1348
|
+
|
1349
|
+
def use_transaction?(migration)
|
1350
|
+
!migration.disable_ddl_transaction && Base.connection.supports_ddl_transactions?
|
1351
|
+
end
|
1352
|
+
|
1353
|
+
def use_advisory_lock?
|
1354
|
+
Base.connection.supports_advisory_locks?
|
1355
|
+
end
|
1356
|
+
|
1357
|
+
def with_advisory_lock
|
1358
|
+
lock_id = generate_migrator_advisory_lock_id
|
1359
|
+
connection = Base.connection
|
1360
|
+
got_lock = connection.get_advisory_lock(lock_id)
|
1361
|
+
raise ConcurrentMigrationError unless got_lock
|
1362
|
+
load_migrated # reload schema_migrations to be sure it wasn't changed by another process before we got the lock
|
1043
1363
|
yield
|
1364
|
+
ensure
|
1365
|
+
if got_lock && !connection.release_advisory_lock(lock_id)
|
1366
|
+
raise ConcurrentMigrationError.new(
|
1367
|
+
ConcurrentMigrationError::RELEASE_LOCK_FAILED_MESSAGE
|
1368
|
+
)
|
1369
|
+
end
|
1044
1370
|
end
|
1045
|
-
end
|
1046
1371
|
|
1047
|
-
|
1048
|
-
|
1049
|
-
|
1372
|
+
MIGRATOR_SALT = 2053462845
|
1373
|
+
def generate_migrator_advisory_lock_id
|
1374
|
+
db_name_hash = Zlib.crc32(Base.connection.current_database)
|
1375
|
+
MIGRATOR_SALT * db_name_hash
|
1376
|
+
end
|
1050
1377
|
end
|
1051
1378
|
end
|