activerecord 4.2.9 → 5.2.8
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 +614 -1572
- 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 +263 -249
- data/lib/active_record/association_relation.rb +11 -6
- data/lib/active_record/associations/alias_tracker.rb +29 -35
- data/lib/active_record/associations/association.rb +77 -43
- data/lib/active_record/associations/association_scope.rb +106 -133
- data/lib/active_record/associations/belongs_to_association.rb +52 -41
- 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 +9 -22
- data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +42 -35
- 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 +139 -280
- data/lib/active_record/associations/collection_proxy.rb +231 -133
- data/lib/active_record/associations/foreign_association.rb +3 -1
- data/lib/active_record/associations/has_many_association.rb +34 -89
- data/lib/active_record/associations/has_many_through_association.rb +49 -76
- data/lib/active_record/associations/has_one_association.rb +38 -24
- data/lib/active_record/associations/has_one_through_association.rb +18 -9
- data/lib/active_record/associations/join_dependency/join_association.rb +40 -89
- 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 +133 -159
- data/lib/active_record/associations/preloader/association.rb +85 -120
- data/lib/active_record/associations/preloader/through_association.rb +85 -74
- data/lib/active_record/associations/preloader.rb +81 -91
- data/lib/active_record/associations/singular_association.rb +27 -34
- data/lib/active_record/associations/through_association.rb +38 -18
- data/lib/active_record/associations.rb +1732 -1597
- 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 +10 -8
- data/lib/active_record/attribute_methods/dirty.rb +94 -135
- 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 +58 -36
- data/lib/active_record/attribute_methods/write.rb +30 -45
- data/lib/active_record/attribute_methods.rb +166 -109
- data/lib/active_record/attributes.rb +201 -82
- data/lib/active_record/autosave_association.rb +94 -36
- data/lib/active_record/base.rb +57 -44
- 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 +24 -12
- data/lib/active_record/collection_cache_key.rb +53 -0
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +712 -290
- data/lib/active_record/connection_adapters/abstract/database_limits.rb +10 -5
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +237 -90
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +71 -21
- data/lib/active_record/connection_adapters/abstract/quoting.rb +118 -52
- data/lib/active_record/connection_adapters/abstract/savepoints.rb +5 -3
- data/lib/active_record/connection_adapters/abstract/schema_creation.rb +67 -46
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +318 -217
- data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +81 -36
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +570 -228
- data/lib/active_record/connection_adapters/abstract/transaction.rb +138 -70
- data/lib/active_record/connection_adapters/abstract_adapter.rb +325 -202
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +542 -593
- 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 +41 -188
- data/lib/active_record/connection_adapters/postgresql/column.rb +35 -11
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +45 -114
- data/lib/active_record/connection_adapters/postgresql/explain_pretty_printer.rb +44 -0
- data/lib/active_record/connection_adapters/postgresql/oid/array.rb +50 -58
- 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 +4 -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 -22
- data/lib/active_record/connection_adapters/postgresql/oid/decimal.rb +3 -1
- data/lib/active_record/connection_adapters/postgresql/oid/enum.rb +5 -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 -5
- data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +55 -53
- 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 +462 -284
- 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 +432 -323
- 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 -308
- 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 +178 -198
- data/lib/active_record/counter_cache.rb +79 -36
- data/lib/active_record/define_callbacks.rb +22 -0
- data/lib/active_record/dynamic_matchers.rb +87 -105
- data/lib/active_record/enum.rb +135 -88
- data/lib/active_record/errors.rb +179 -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 +10 -5
- data/lib/active_record/fixture_set/file.rb +35 -9
- data/lib/active_record/fixtures.rb +188 -132
- data/lib/active_record/gem_version.rb +4 -2
- 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 +21 -3
- data/lib/active_record/locale/en.yml +3 -2
- data/lib/active_record/locking/optimistic.rb +88 -96
- 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 +581 -282
- data/lib/active_record/model_schema.rb +290 -111
- data/lib/active_record/nested_attributes.rb +264 -222
- data/lib/active_record/no_touching.rb +7 -1
- data/lib/active_record/null_relation.rb +24 -37
- data/lib/active_record/persistence.rb +347 -119
- data/lib/active_record/query_cache.rb +13 -24
- data/lib/active_record/querying.rb +19 -17
- data/lib/active_record/railtie.rb +94 -32
- 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 +149 -156
- data/lib/active_record/readonly_attributes.rb +5 -4
- data/lib/active_record/reflection.rb +414 -267
- 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 +256 -248
- data/lib/active_record/relation/delegation.rb +67 -60
- data/lib/active_record/relation/finder_methods.rb +288 -239
- data/lib/active_record/relation/from_clause.rb +26 -0
- data/lib/active_record/relation/merger.rb +86 -86
- data/lib/active_record/relation/predicate_builder/array_handler.rb +24 -24
- 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 +116 -119
- data/lib/active_record/relation/query_attribute.rb +45 -0
- data/lib/active_record/relation/query_methods.rb +448 -393
- data/lib/active_record/relation/record_fetch_warning.rb +51 -0
- data/lib/active_record/relation/spawn_methods.rb +11 -13
- 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 -340
- 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 -16
- data/lib/active_record/scoping/default.rb +102 -85
- 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 +134 -96
- data/lib/active_record/tasks/mysql_database_tasks.rb +56 -100
- data/lib/active_record/tasks/postgresql_database_tasks.rb +83 -41
- 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 +199 -124
- 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 -45
- data/lib/active_record/type/date_time.rb +4 -49
- data/lib/active_record/type/decimal_without_scale.rb +6 -2
- data/lib/active_record/type/hash_lookup_type_map.rb +5 -3
- 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 +24 -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 +40 -41
- data/lib/active_record/validations.rb +38 -35
- data/lib/active_record/version.rb +3 -1
- data/lib/active_record.rb +34 -22
- 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 -3
- data/lib/rails/generators/active_record/migration/templates/{migration.rb → migration.rb.tt} +8 -1
- 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/model/templates/{module.rb → module.rb.tt} +0 -0
- data/lib/rails/generators/active_record.rb +7 -5
- metadata +72 -50
- 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 -163
- data/lib/active_record/attribute_set/builder.rb +0 -106
- data/lib/active_record/attribute_set.rb +0 -81
- 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 -31
- data/lib/active_record/type/decimal.rb +0 -64
- 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 -59
- 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 -40
- data/lib/active_record/type/time_value.rb +0 -38
- data/lib/active_record/type/value.rb +0 -110
@@ -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
|
152
|
+
msg = "Environment data not found in the schema. To resolve this issue, run: \n\n bin/rails db:environment:set"
|
42
153
|
if defined?(Rails.env)
|
43
|
-
super("
|
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:
|
@@ -314,7 +474,7 @@ module ActiveRecord
|
|
314
474
|
# To define a reversible migration, define the +change+ method in your
|
315
475
|
# migration like this:
|
316
476
|
#
|
317
|
-
# class TenderloveMigration < ActiveRecord::Migration
|
477
|
+
# class TenderloveMigration < ActiveRecord::Migration[5.0]
|
318
478
|
# def change
|
319
479
|
# create_table(:horses) do |t|
|
320
480
|
# t.column :content, :text
|
@@ -344,7 +504,7 @@ module ActiveRecord
|
|
344
504
|
# can't execute inside a transaction though, and for these situations
|
345
505
|
# you can turn the automatic transactions off.
|
346
506
|
#
|
347
|
-
# class ChangeEnum < ActiveRecord::Migration
|
507
|
+
# class ChangeEnum < ActiveRecord::Migration[5.0]
|
348
508
|
# disable_ddl_transaction!
|
349
509
|
#
|
350
510
|
# def up
|
@@ -355,11 +515,35 @@ module ActiveRecord
|
|
355
515
|
# Remember that you can still open your own transactions, even if you
|
356
516
|
# are in a Migration with <tt>self.disable_ddl_transaction!</tt>.
|
357
517
|
class Migration
|
358
|
-
autoload :CommandRecorder,
|
518
|
+
autoload :CommandRecorder, "active_record/migration/command_recorder"
|
519
|
+
autoload :Compatibility, "active_record/migration/compatibility"
|
359
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:
|
360
544
|
|
361
545
|
# This class is used to verify that all migrations have been run before
|
362
|
-
# 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
|
363
547
|
class CheckPending
|
364
548
|
def initialize(app)
|
365
549
|
@app = app
|
@@ -367,38 +551,42 @@ module ActiveRecord
|
|
367
551
|
end
|
368
552
|
|
369
553
|
def call(env)
|
370
|
-
|
371
|
-
|
372
|
-
|
373
|
-
|
374
|
-
@last_check = mtime
|
375
|
-
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
|
376
558
|
end
|
377
559
|
@app.call(env)
|
378
560
|
end
|
379
561
|
|
380
562
|
private
|
381
563
|
|
382
|
-
|
383
|
-
|
384
|
-
|
564
|
+
def connection
|
565
|
+
ActiveRecord::Base.connection
|
566
|
+
end
|
385
567
|
end
|
386
568
|
|
387
569
|
class << self
|
388
570
|
attr_accessor :delegate # :nodoc:
|
389
571
|
attr_accessor :disable_ddl_transaction # :nodoc:
|
390
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.
|
391
578
|
def check_pending!(connection = Base.connection)
|
392
|
-
raise ActiveRecord::PendingMigrationError if
|
579
|
+
raise ActiveRecord::PendingMigrationError if connection.migration_context.needs_migration?
|
393
580
|
end
|
394
581
|
|
395
582
|
def load_schema_if_pending!
|
396
|
-
if
|
397
|
-
#
|
398
|
-
|
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
|
399
587
|
current_config = Base.connection_config
|
400
588
|
Base.clear_all_connections!
|
401
|
-
system("bin/
|
589
|
+
system("bin/rails db:test:prepare")
|
402
590
|
# Establish a new connection, the old database may be gone (db:test:prepare uses purge)
|
403
591
|
Base.establish_connection(current_config)
|
404
592
|
end
|
@@ -413,7 +601,7 @@ module ActiveRecord
|
|
413
601
|
end
|
414
602
|
|
415
603
|
def method_missing(name, *args, &block) # :nodoc:
|
416
|
-
|
604
|
+
nearest_delegate.send(name, *args, &block)
|
417
605
|
end
|
418
606
|
|
419
607
|
def migrate(direction)
|
@@ -453,7 +641,7 @@ module ActiveRecord
|
|
453
641
|
# and create the table 'apples' on the way up, and the reverse
|
454
642
|
# on the way down.
|
455
643
|
#
|
456
|
-
# class FixTLMigration < ActiveRecord::Migration
|
644
|
+
# class FixTLMigration < ActiveRecord::Migration[5.0]
|
457
645
|
# def change
|
458
646
|
# revert do
|
459
647
|
# create_table(:horses) do |t|
|
@@ -470,9 +658,9 @@ module ActiveRecord
|
|
470
658
|
# Or equivalently, if +TenderloveMigration+ is defined as in the
|
471
659
|
# documentation for Migration:
|
472
660
|
#
|
473
|
-
# require_relative '
|
661
|
+
# require_relative '20121212123456_tenderlove_migration'
|
474
662
|
#
|
475
|
-
# class FixupTLMigration < ActiveRecord::Migration
|
663
|
+
# class FixupTLMigration < ActiveRecord::Migration[5.0]
|
476
664
|
# def change
|
477
665
|
# revert TenderloveMigration
|
478
666
|
#
|
@@ -486,13 +674,13 @@ module ActiveRecord
|
|
486
674
|
def revert(*migration_classes)
|
487
675
|
run(*migration_classes.reverse, revert: true) unless migration_classes.empty?
|
488
676
|
if block_given?
|
489
|
-
if
|
490
|
-
|
677
|
+
if connection.respond_to? :revert
|
678
|
+
connection.revert { yield }
|
491
679
|
else
|
492
|
-
recorder = CommandRecorder.new(
|
680
|
+
recorder = CommandRecorder.new(connection)
|
493
681
|
@connection = recorder
|
494
682
|
suppress_messages do
|
495
|
-
|
683
|
+
connection.revert { yield }
|
496
684
|
end
|
497
685
|
@connection = recorder.delegate
|
498
686
|
recorder.commands.each do |cmd, args, block|
|
@@ -503,10 +691,10 @@ module ActiveRecord
|
|
503
691
|
end
|
504
692
|
|
505
693
|
def reverting?
|
506
|
-
|
694
|
+
connection.respond_to?(:reverting) && connection.reverting
|
507
695
|
end
|
508
696
|
|
509
|
-
|
697
|
+
ReversibleBlockHelper = Struct.new(:reverting) do # :nodoc:
|
510
698
|
def up
|
511
699
|
yield unless reverting
|
512
700
|
end
|
@@ -525,7 +713,7 @@ module ActiveRecord
|
|
525
713
|
# when the three columns 'first_name', 'last_name' and 'full_name' exist,
|
526
714
|
# even when migrating down:
|
527
715
|
#
|
528
|
-
# class SplitNameMigration < ActiveRecord::Migration
|
716
|
+
# class SplitNameMigration < ActiveRecord::Migration[5.0]
|
529
717
|
# def change
|
530
718
|
# add_column :users, :first_name, :string
|
531
719
|
# add_column :users, :last_name, :string
|
@@ -544,7 +732,25 @@ module ActiveRecord
|
|
544
732
|
# end
|
545
733
|
def reversible
|
546
734
|
helper = ReversibleBlockHelper.new(reverting?)
|
547
|
-
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?
|
548
754
|
end
|
549
755
|
|
550
756
|
# Runs the given migration classes.
|
@@ -560,7 +766,7 @@ module ActiveRecord
|
|
560
766
|
revert { run(*migration_classes, direction: dir, revert: true) }
|
561
767
|
else
|
562
768
|
migration_classes.each do |migration_class|
|
563
|
-
migration_class.new.exec_migration(
|
769
|
+
migration_class.new.exec_migration(connection, dir)
|
564
770
|
end
|
565
771
|
end
|
566
772
|
end
|
@@ -586,7 +792,7 @@ module ActiveRecord
|
|
586
792
|
when :down then announce "reverting"
|
587
793
|
end
|
588
794
|
|
589
|
-
time
|
795
|
+
time = nil
|
590
796
|
ActiveRecord::Base.connection_pool.with_connection do |conn|
|
591
797
|
time = Benchmark.measure do
|
592
798
|
exec_migration(conn, direction)
|
@@ -614,7 +820,7 @@ module ActiveRecord
|
|
614
820
|
@connection = nil
|
615
821
|
end
|
616
822
|
|
617
|
-
def write(text="")
|
823
|
+
def write(text = "")
|
618
824
|
puts(text) if verbose
|
619
825
|
end
|
620
826
|
|
@@ -624,7 +830,7 @@ module ActiveRecord
|
|
624
830
|
write "== %s %s" % [text, "=" * length]
|
625
831
|
end
|
626
832
|
|
627
|
-
def say(message, subitem=false)
|
833
|
+
def say(message, subitem = false)
|
628
834
|
write "#{subitem ? " ->" : "--"} #{message}"
|
629
835
|
end
|
630
836
|
|
@@ -649,10 +855,10 @@ module ActiveRecord
|
|
649
855
|
end
|
650
856
|
|
651
857
|
def method_missing(method, *arguments, &block)
|
652
|
-
arg_list = arguments.map
|
858
|
+
arg_list = arguments.map(&:inspect) * ", "
|
653
859
|
|
654
860
|
say_with_time "#{method}(#{arg_list})" do
|
655
|
-
unless
|
861
|
+
unless connection.respond_to? :revert
|
656
862
|
unless arguments.empty? || [:execute, :enable_extension, :disable_extension].include?(method)
|
657
863
|
arguments[0] = proper_table_name(arguments.first, table_name_options)
|
658
864
|
if [:rename_table, :add_foreign_key].include?(method) ||
|
@@ -671,23 +877,25 @@ module ActiveRecord
|
|
671
877
|
|
672
878
|
FileUtils.mkdir_p(destination) unless File.exist?(destination)
|
673
879
|
|
674
|
-
destination_migrations = ActiveRecord::
|
880
|
+
destination_migrations = ActiveRecord::MigrationContext.new(destination).migrations
|
675
881
|
last = destination_migrations.last
|
676
882
|
sources.each do |scope, path|
|
677
|
-
source_migrations = ActiveRecord::
|
883
|
+
source_migrations = ActiveRecord::MigrationContext.new(path).migrations
|
678
884
|
|
679
885
|
source_migrations.each do |migration|
|
680
886
|
source = File.binread(migration.filename)
|
681
887
|
inserted_comment = "# This migration comes from #{scope} (originally #{migration.version})\n"
|
682
|
-
|
888
|
+
magic_comments = "".dup
|
889
|
+
loop do
|
683
890
|
# If we have a magic comment in the original migration,
|
684
891
|
# insert our comment after the first newline(end of the magic comment line)
|
685
892
|
# so the magic keep working.
|
686
893
|
# Note that magic comments must be at the first line(except sh-bang).
|
687
|
-
source
|
688
|
-
|
689
|
-
|
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
|
690
897
|
end
|
898
|
+
source = "#{magic_comments}#{inserted_comment}#{source}"
|
691
899
|
|
692
900
|
if duplicate = destination_migrations.detect { |m| m.name == migration.name }
|
693
901
|
if options[:on_skip] && duplicate.scope != scope.to_s
|
@@ -731,7 +939,9 @@ module ActiveRecord
|
|
731
939
|
end
|
732
940
|
end
|
733
941
|
|
734
|
-
|
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:
|
735
945
|
{
|
736
946
|
table_name_prefix: config.table_name_prefix,
|
737
947
|
table_name_suffix: config.table_name_suffix
|
@@ -739,19 +949,18 @@ module ActiveRecord
|
|
739
949
|
end
|
740
950
|
|
741
951
|
private
|
742
|
-
|
743
|
-
|
744
|
-
|
745
|
-
|
746
|
-
|
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
|
747
958
|
end
|
748
|
-
end
|
749
959
|
end
|
750
960
|
|
751
961
|
# MigrationProxy is used to defer loading of the actual migration classes
|
752
962
|
# until they are needed
|
753
|
-
|
754
|
-
|
963
|
+
MigrationProxy = Struct.new(:name, :version, :filename, :scope) do
|
755
964
|
def initialize(name, version, filename, scope)
|
756
965
|
super
|
757
966
|
@migration = nil
|
@@ -777,7 +986,6 @@ module ActiveRecord
|
|
777
986
|
require(File.expand_path(filename))
|
778
987
|
name.constantize.new(name, version)
|
779
988
|
end
|
780
|
-
|
781
989
|
end
|
782
990
|
|
783
991
|
class NullMigration < MigrationProxy #:nodoc:
|
@@ -790,156 +998,185 @@ module ActiveRecord
|
|
790
998
|
end
|
791
999
|
end
|
792
1000
|
|
793
|
-
class
|
794
|
-
|
795
|
-
attr_writer :migrations_paths
|
796
|
-
alias :migrations_path= :migrations_paths=
|
797
|
-
|
798
|
-
def migrate(migrations_paths, target_version = nil, &block)
|
799
|
-
case
|
800
|
-
when target_version.nil?
|
801
|
-
up(migrations_paths, target_version, &block)
|
802
|
-
when current_version == 0 && target_version == 0
|
803
|
-
[]
|
804
|
-
when current_version > target_version
|
805
|
-
down(migrations_paths, target_version, &block)
|
806
|
-
else
|
807
|
-
up(migrations_paths, target_version, &block)
|
808
|
-
end
|
809
|
-
end
|
1001
|
+
class MigrationContext # :nodoc:
|
1002
|
+
attr_reader :migrations_paths
|
810
1003
|
|
811
|
-
|
812
|
-
|
813
|
-
|
1004
|
+
def initialize(migrations_paths)
|
1005
|
+
@migrations_paths = migrations_paths
|
1006
|
+
end
|
814
1007
|
|
815
|
-
|
816
|
-
|
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)
|
817
1018
|
end
|
1019
|
+
end
|
1020
|
+
|
1021
|
+
def rollback(steps = 1)
|
1022
|
+
move(:down, steps)
|
1023
|
+
end
|
818
1024
|
|
819
|
-
|
820
|
-
|
821
|
-
|
1025
|
+
def forward(steps = 1)
|
1026
|
+
move(:up, steps)
|
1027
|
+
end
|
822
1028
|
|
823
|
-
|
1029
|
+
def up(target_version = nil)
|
1030
|
+
selected_migrations = if block_given?
|
1031
|
+
migrations.select { |m| yield m }
|
1032
|
+
else
|
1033
|
+
migrations
|
824
1034
|
end
|
825
1035
|
|
826
|
-
|
827
|
-
|
828
|
-
migrations.select! { |m| yield m } if block_given?
|
1036
|
+
Migrator.new(:up, selected_migrations, target_version).migrate
|
1037
|
+
end
|
829
1038
|
|
830
|
-
|
1039
|
+
def down(target_version = nil)
|
1040
|
+
selected_migrations = if block_given?
|
1041
|
+
migrations.select { |m| yield m }
|
1042
|
+
else
|
1043
|
+
migrations
|
831
1044
|
end
|
832
1045
|
|
833
|
-
|
834
|
-
|
835
|
-
end
|
1046
|
+
Migrator.new(:down, selected_migrations, target_version).migrate
|
1047
|
+
end
|
836
1048
|
|
837
|
-
|
838
|
-
|
839
|
-
|
1049
|
+
def run(direction, target_version)
|
1050
|
+
Migrator.new(direction, migrations, target_version).run
|
1051
|
+
end
|
840
1052
|
|
841
|
-
|
842
|
-
|
843
|
-
|
1053
|
+
def open
|
1054
|
+
Migrator.new(:up, migrations, nil)
|
1055
|
+
end
|
844
1056
|
|
845
|
-
|
846
|
-
|
847
|
-
|
848
|
-
|
849
|
-
|
850
|
-
end
|
1057
|
+
def get_all_versions
|
1058
|
+
if SchemaMigration.table_exists?
|
1059
|
+
SchemaMigration.all_versions.map(&:to_i)
|
1060
|
+
else
|
1061
|
+
[]
|
851
1062
|
end
|
1063
|
+
end
|
852
1064
|
|
853
|
-
|
854
|
-
|
855
|
-
|
1065
|
+
def current_version
|
1066
|
+
get_all_versions.max || 0
|
1067
|
+
rescue ActiveRecord::NoDatabaseError
|
1068
|
+
end
|
856
1069
|
|
857
|
-
|
858
|
-
|
859
|
-
|
1070
|
+
def needs_migration?
|
1071
|
+
(migrations.collect(&:version) - get_all_versions).size > 0
|
1072
|
+
end
|
860
1073
|
|
861
|
-
|
862
|
-
|
863
|
-
|
1074
|
+
def any_migrations?
|
1075
|
+
migrations.any?
|
1076
|
+
end
|
864
1077
|
|
865
|
-
|
866
|
-
|
867
|
-
|
1078
|
+
def last_migration #:nodoc:
|
1079
|
+
migrations.last || NullMigration.new
|
1080
|
+
end
|
868
1081
|
|
869
|
-
|
870
|
-
|
871
|
-
|
1082
|
+
def parse_migration_filename(filename) # :nodoc:
|
1083
|
+
File.basename(filename).scan(Migration::MigrationFilenameRegexp).first
|
1084
|
+
end
|
872
1085
|
|
873
|
-
|
874
|
-
|
875
|
-
|
876
|
-
|
877
|
-
|
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
|
878
1092
|
|
879
|
-
|
880
|
-
migrations_paths.first
|
1093
|
+
MigrationProxy.new(name, version, file, scope)
|
881
1094
|
end
|
882
1095
|
|
883
|
-
|
884
|
-
|
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 **********"]
|
885
1112
|
end
|
886
1113
|
|
887
|
-
|
888
|
-
|
1114
|
+
(db_list + file_list).sort_by { |_, version, _| version }
|
1115
|
+
end
|
889
1116
|
|
890
|
-
|
891
|
-
|
892
|
-
|
893
|
-
|
894
|
-
name = name.camelize
|
1117
|
+
def migration_files
|
1118
|
+
paths = Array(migrations_paths)
|
1119
|
+
Dir[*paths.flat_map { |path| "#{path}/**/[0-9]*_*.rb" }]
|
1120
|
+
end
|
895
1121
|
|
896
|
-
|
897
|
-
|
1122
|
+
def current_environment
|
1123
|
+
ActiveRecord::ConnectionHandling::DEFAULT_ENV.call
|
1124
|
+
end
|
898
1125
|
|
899
|
-
|
900
|
-
|
1126
|
+
def protected_environment?
|
1127
|
+
ActiveRecord::Base.protected_environments.include?(last_stored_environment) if last_stored_environment
|
1128
|
+
end
|
901
1129
|
|
902
|
-
|
903
|
-
|
1130
|
+
def last_stored_environment
|
1131
|
+
return nil if current_version == 0
|
1132
|
+
raise NoEnvironmentInSchemaError unless ActiveRecord::InternalMetadata.table_exists?
|
904
1133
|
|
905
|
-
|
1134
|
+
environment = ActiveRecord::InternalMetadata[:environment]
|
1135
|
+
raise NoEnvironmentInSchemaError unless environment
|
1136
|
+
environment
|
1137
|
+
end
|
906
1138
|
|
907
|
-
|
908
|
-
|
909
|
-
|
910
|
-
version = ActiveRecord::SchemaMigration.normalize_migration_number(version)
|
911
|
-
status = db_list.delete(version) ? "up" : "down"
|
912
|
-
[status, version, (name + scope).humanize]
|
913
|
-
end.compact
|
1139
|
+
private
|
1140
|
+
def move(direction, steps)
|
1141
|
+
migrator = Migrator.new(direction, migrations)
|
914
1142
|
|
915
|
-
|
916
|
-
|
1143
|
+
if current_version != 0 && !migrator.current_migration
|
1144
|
+
raise UnknownMigrationVersionError.new(current_version)
|
917
1145
|
end
|
918
1146
|
|
919
|
-
|
920
|
-
|
1147
|
+
start_index =
|
1148
|
+
if current_version == 0
|
1149
|
+
0
|
1150
|
+
else
|
1151
|
+
migrator.migrations.index(migrator.current_migration)
|
1152
|
+
end
|
921
1153
|
|
922
|
-
|
923
|
-
|
1154
|
+
finish = migrator.migrations[start_index + steps]
|
1155
|
+
version = finish ? finish.version : 0
|
1156
|
+
send(direction, version)
|
924
1157
|
end
|
1158
|
+
end
|
925
1159
|
|
926
|
-
|
1160
|
+
class Migrator # :nodoc:
|
1161
|
+
class << self
|
1162
|
+
attr_accessor :migrations_paths
|
927
1163
|
|
928
|
-
def
|
929
|
-
|
930
|
-
|
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
|
931
1170
|
|
932
|
-
|
933
|
-
|
934
|
-
|
935
|
-
send(direction, migrations_paths, version)
|
936
|
-
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
|
937
1174
|
end
|
938
1175
|
end
|
939
1176
|
|
940
|
-
|
941
|
-
raise StandardError.new("This database does not yet support migrations") unless Base.connection.supports_migrations?
|
1177
|
+
self.migrations_paths = ["db/migrate"]
|
942
1178
|
|
1179
|
+
def initialize(direction, migrations, target_version = nil)
|
943
1180
|
@direction = direction
|
944
1181
|
@target_version = target_version
|
945
1182
|
@migrated_versions = nil
|
@@ -947,7 +1184,8 @@ module ActiveRecord
|
|
947
1184
|
|
948
1185
|
validate(@migrations)
|
949
1186
|
|
950
|
-
|
1187
|
+
ActiveRecord::SchemaMigration.create_table
|
1188
|
+
ActiveRecord::InternalMetadata.create_table
|
951
1189
|
end
|
952
1190
|
|
953
1191
|
def current_version
|
@@ -960,32 +1198,18 @@ module ActiveRecord
|
|
960
1198
|
alias :current :current_migration
|
961
1199
|
|
962
1200
|
def run
|
963
|
-
|
964
|
-
|
965
|
-
|
966
|
-
|
967
|
-
execute_migration_in_transaction(migration, @direction)
|
968
|
-
rescue => e
|
969
|
-
canceled_msg = use_transaction?(migration) ? ", this migration was canceled" : ""
|
970
|
-
raise StandardError, "An error has occurred#{canceled_msg}:\n\n#{e}", e.backtrace
|
971
|
-
end
|
1201
|
+
if use_advisory_lock?
|
1202
|
+
with_advisory_lock { run_without_lock }
|
1203
|
+
else
|
1204
|
+
run_without_lock
|
972
1205
|
end
|
973
1206
|
end
|
974
1207
|
|
975
1208
|
def migrate
|
976
|
-
if
|
977
|
-
|
978
|
-
|
979
|
-
|
980
|
-
runnable.each do |migration|
|
981
|
-
Base.logger.info "Migrating to #{migration.name} (#{migration.version})" if Base.logger
|
982
|
-
|
983
|
-
begin
|
984
|
-
execute_migration_in_transaction(migration, @direction)
|
985
|
-
rescue => e
|
986
|
-
canceled_msg = use_transaction?(migration) ? "this and " : ""
|
987
|
-
raise StandardError, "An error has occurred, #{canceled_msg}all later migrations canceled:\n\n#{e}", e.backtrace
|
988
|
-
end
|
1209
|
+
if use_advisory_lock?
|
1210
|
+
with_advisory_lock { migrate_without_lock }
|
1211
|
+
else
|
1212
|
+
migrate_without_lock
|
989
1213
|
end
|
990
1214
|
end
|
991
1215
|
|
@@ -1010,70 +1234,145 @@ module ActiveRecord
|
|
1010
1234
|
end
|
1011
1235
|
|
1012
1236
|
def migrated
|
1013
|
-
@migrated_versions
|
1237
|
+
@migrated_versions || load_migrated
|
1014
1238
|
end
|
1015
1239
|
|
1016
|
-
|
1017
|
-
|
1018
|
-
migrated.include?(migration.version.to_i)
|
1240
|
+
def load_migrated
|
1241
|
+
@migrated_versions = Set.new(Base.connection.migration_context.get_all_versions)
|
1019
1242
|
end
|
1020
1243
|
|
1021
|
-
|
1022
|
-
|
1023
|
-
|
1024
|
-
|
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
|
1025
1254
|
end
|
1026
|
-
end
|
1027
1255
|
|
1028
|
-
|
1029
|
-
|
1030
|
-
|
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
|
1031
1261
|
|
1032
|
-
|
1033
|
-
|
1034
|
-
|
1262
|
+
result = runnable.each do |migration|
|
1263
|
+
execute_migration_in_transaction(migration, @direction)
|
1264
|
+
end
|
1035
1265
|
|
1036
|
-
|
1037
|
-
|
1038
|
-
|
1266
|
+
record_environment
|
1267
|
+
result
|
1268
|
+
end
|
1039
1269
|
|
1040
|
-
|
1041
|
-
|
1042
|
-
|
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
|
1043
1275
|
|
1044
|
-
|
1045
|
-
|
1046
|
-
|
1276
|
+
def ran?(migration)
|
1277
|
+
migrated.include?(migration.version.to_i)
|
1278
|
+
end
|
1047
1279
|
|
1048
|
-
|
1049
|
-
|
1050
|
-
|
1051
|
-
ActiveRecord::SchemaMigration.where(:version => version.to_s).delete_all
|
1052
|
-
else
|
1053
|
-
migrated << version
|
1054
|
-
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
|
1055
1283
|
end
|
1056
|
-
end
|
1057
1284
|
|
1058
|
-
|
1059
|
-
|
1060
|
-
|
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)
|
1061
1288
|
|
1062
|
-
|
1063
|
-
@direction == :down
|
1064
|
-
end
|
1289
|
+
Base.logger.info "Migrating to #{migration.name} (#{migration.version})" if Base.logger
|
1065
1290
|
|
1066
|
-
|
1067
|
-
|
1068
|
-
|
1069
|
-
|
1070
|
-
|
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
|
1071
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
|
1072
1370
|
end
|
1073
|
-
end
|
1074
1371
|
|
1075
|
-
|
1076
|
-
|
1077
|
-
|
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
|
1078
1377
|
end
|
1079
1378
|
end
|