activerecord 4.2.11.3 → 5.0.7.2
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 +4 -4
- data/CHANGELOG.md +1638 -1132
- data/MIT-LICENSE +2 -2
- data/README.rdoc +7 -8
- data/examples/performance.rb +2 -3
- data/examples/simple.rb +0 -1
- data/lib/active_record.rb +7 -2
- data/lib/active_record/aggregations.rb +34 -21
- data/lib/active_record/association_relation.rb +7 -4
- data/lib/active_record/associations.rb +347 -218
- data/lib/active_record/associations/alias_tracker.rb +19 -16
- data/lib/active_record/associations/association.rb +22 -10
- data/lib/active_record/associations/association_scope.rb +75 -104
- data/lib/active_record/associations/belongs_to_association.rb +21 -32
- data/lib/active_record/associations/builder/association.rb +28 -34
- data/lib/active_record/associations/builder/belongs_to.rb +43 -18
- data/lib/active_record/associations/builder/collection_association.rb +7 -19
- data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +16 -11
- data/lib/active_record/associations/builder/has_many.rb +4 -4
- data/lib/active_record/associations/builder/has_one.rb +11 -6
- data/lib/active_record/associations/builder/singular_association.rb +13 -11
- data/lib/active_record/associations/collection_association.rb +85 -69
- data/lib/active_record/associations/collection_proxy.rb +104 -46
- data/lib/active_record/associations/foreign_association.rb +1 -1
- data/lib/active_record/associations/has_many_association.rb +21 -78
- data/lib/active_record/associations/has_many_through_association.rb +6 -47
- data/lib/active_record/associations/has_one_association.rb +12 -5
- data/lib/active_record/associations/join_dependency.rb +38 -22
- data/lib/active_record/associations/join_dependency/join_association.rb +15 -14
- data/lib/active_record/associations/join_dependency/join_part.rb +2 -2
- data/lib/active_record/associations/preloader.rb +14 -4
- data/lib/active_record/associations/preloader/association.rb +52 -71
- data/lib/active_record/associations/preloader/collection_association.rb +0 -7
- data/lib/active_record/associations/preloader/has_many_through.rb +1 -1
- data/lib/active_record/associations/preloader/has_one.rb +0 -8
- data/lib/active_record/associations/preloader/singular_association.rb +0 -1
- data/lib/active_record/associations/preloader/through_association.rb +36 -17
- data/lib/active_record/associations/singular_association.rb +13 -1
- data/lib/active_record/associations/through_association.rb +12 -4
- data/lib/active_record/attribute.rb +69 -19
- data/lib/active_record/attribute/user_provided_default.rb +28 -0
- data/lib/active_record/attribute_assignment.rb +19 -140
- data/lib/active_record/attribute_decorators.rb +6 -5
- data/lib/active_record/attribute_methods.rb +69 -44
- data/lib/active_record/attribute_methods/before_type_cast.rb +1 -1
- data/lib/active_record/attribute_methods/dirty.rb +46 -86
- data/lib/active_record/attribute_methods/primary_key.rb +16 -3
- data/lib/active_record/attribute_methods/query.rb +2 -2
- data/lib/active_record/attribute_methods/read.rb +31 -59
- data/lib/active_record/attribute_methods/serialization.rb +13 -16
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +61 -14
- data/lib/active_record/attribute_methods/write.rb +13 -37
- data/lib/active_record/attribute_mutation_tracker.rb +70 -0
- data/lib/active_record/attribute_set.rb +32 -3
- data/lib/active_record/attribute_set/builder.rb +42 -16
- data/lib/active_record/attributes.rb +199 -81
- data/lib/active_record/autosave_association.rb +54 -17
- data/lib/active_record/base.rb +32 -23
- data/lib/active_record/callbacks.rb +39 -43
- data/lib/active_record/coders/json.rb +1 -1
- data/lib/active_record/coders/yaml_column.rb +20 -8
- data/lib/active_record/collection_cache_key.rb +50 -0
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +467 -189
- data/lib/active_record/connection_adapters/abstract/database_limits.rb +3 -3
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +66 -62
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +39 -4
- data/lib/active_record/connection_adapters/abstract/quoting.rb +86 -13
- data/lib/active_record/connection_adapters/abstract/savepoints.rb +3 -3
- data/lib/active_record/connection_adapters/abstract/schema_creation.rb +61 -39
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +236 -188
- data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +72 -17
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +407 -156
- data/lib/active_record/connection_adapters/abstract/transaction.rb +51 -34
- data/lib/active_record/connection_adapters/abstract_adapter.rb +177 -71
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +433 -399
- data/lib/active_record/connection_adapters/column.rb +28 -43
- data/lib/active_record/connection_adapters/connection_specification.rb +15 -27
- data/lib/active_record/connection_adapters/determine_if_preparable_visitor.rb +22 -0
- data/lib/active_record/connection_adapters/mysql/column.rb +50 -0
- data/lib/active_record/connection_adapters/mysql/database_statements.rb +108 -0
- data/lib/active_record/connection_adapters/mysql/explain_pretty_printer.rb +70 -0
- data/lib/active_record/connection_adapters/mysql/quoting.rb +51 -0
- data/lib/active_record/connection_adapters/mysql/schema_creation.rb +67 -0
- data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +93 -0
- data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +54 -0
- data/lib/active_record/connection_adapters/mysql/type_metadata.rb +32 -0
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +25 -166
- data/lib/active_record/connection_adapters/postgresql/column.rb +33 -11
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +18 -72
- data/lib/active_record/connection_adapters/postgresql/explain_pretty_printer.rb +42 -0
- data/lib/active_record/connection_adapters/postgresql/oid.rb +1 -6
- data/lib/active_record/connection_adapters/postgresql/oid/array.rb +37 -57
- data/lib/active_record/connection_adapters/postgresql/oid/bit.rb +3 -3
- data/lib/active_record/connection_adapters/postgresql/oid/bytea.rb +2 -2
- data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +3 -1
- data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +7 -22
- data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +13 -3
- data/lib/active_record/connection_adapters/postgresql/oid/json.rb +1 -26
- data/lib/active_record/connection_adapters/postgresql/oid/jsonb.rb +2 -2
- data/lib/active_record/connection_adapters/postgresql/oid/money.rb +0 -4
- data/lib/active_record/connection_adapters/postgresql/oid/point.rb +4 -4
- data/lib/active_record/connection_adapters/postgresql/oid/rails_5_1_point.rb +50 -0
- data/lib/active_record/connection_adapters/postgresql/oid/range.rb +31 -17
- data/lib/active_record/connection_adapters/postgresql/oid/specialized_string.rb +0 -4
- data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +2 -2
- data/lib/active_record/connection_adapters/postgresql/oid/vector.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/oid/xml.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/quoting.rb +56 -19
- data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +29 -10
- data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +107 -79
- data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +47 -0
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +250 -154
- data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +35 -0
- data/lib/active_record/connection_adapters/postgresql/utils.rb +2 -2
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +264 -170
- data/lib/active_record/connection_adapters/schema_cache.rb +36 -23
- data/lib/active_record/connection_adapters/sql_type_metadata.rb +32 -0
- data/lib/active_record/connection_adapters/sqlite3/explain_pretty_printer.rb +19 -0
- data/lib/active_record/connection_adapters/sqlite3/quoting.rb +48 -0
- data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +22 -0
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +151 -194
- data/lib/active_record/connection_adapters/statement_pool.rb +31 -12
- data/lib/active_record/connection_handling.rb +37 -14
- data/lib/active_record/core.rb +92 -108
- data/lib/active_record/counter_cache.rb +13 -24
- data/lib/active_record/dynamic_matchers.rb +1 -20
- data/lib/active_record/enum.rb +116 -76
- data/lib/active_record/errors.rb +87 -48
- data/lib/active_record/explain.rb +20 -9
- data/lib/active_record/explain_registry.rb +1 -1
- data/lib/active_record/explain_subscriber.rb +1 -1
- data/lib/active_record/fixture_set/file.rb +26 -5
- data/lib/active_record/fixtures.rb +77 -41
- data/lib/active_record/gem_version.rb +4 -4
- data/lib/active_record/inheritance.rb +32 -40
- data/lib/active_record/integration.rb +17 -14
- data/lib/active_record/internal_metadata.rb +56 -0
- data/lib/active_record/legacy_yaml_adapter.rb +18 -2
- data/lib/active_record/locale/en.yml +3 -2
- data/lib/active_record/locking/optimistic.rb +15 -15
- data/lib/active_record/locking/pessimistic.rb +1 -1
- data/lib/active_record/log_subscriber.rb +48 -24
- data/lib/active_record/migration.rb +362 -111
- data/lib/active_record/migration/command_recorder.rb +59 -18
- data/lib/active_record/migration/compatibility.rb +126 -0
- data/lib/active_record/model_schema.rb +270 -73
- data/lib/active_record/nested_attributes.rb +58 -29
- data/lib/active_record/no_touching.rb +4 -0
- data/lib/active_record/null_relation.rb +16 -8
- data/lib/active_record/persistence.rb +152 -90
- data/lib/active_record/query_cache.rb +18 -23
- data/lib/active_record/querying.rb +12 -11
- data/lib/active_record/railtie.rb +23 -16
- data/lib/active_record/railties/controller_runtime.rb +1 -1
- data/lib/active_record/railties/databases.rake +52 -41
- data/lib/active_record/readonly_attributes.rb +1 -1
- data/lib/active_record/reflection.rb +302 -115
- data/lib/active_record/relation.rb +187 -120
- data/lib/active_record/relation/batches.rb +141 -36
- data/lib/active_record/relation/batches/batch_enumerator.rb +67 -0
- data/lib/active_record/relation/calculations.rb +92 -117
- data/lib/active_record/relation/delegation.rb +8 -20
- data/lib/active_record/relation/finder_methods.rb +173 -89
- data/lib/active_record/relation/from_clause.rb +32 -0
- data/lib/active_record/relation/merger.rb +16 -42
- data/lib/active_record/relation/predicate_builder.rb +120 -107
- data/lib/active_record/relation/predicate_builder/array_handler.rb +11 -16
- data/lib/active_record/relation/predicate_builder/association_query_handler.rb +88 -0
- data/lib/active_record/relation/predicate_builder/base_handler.rb +17 -0
- data/lib/active_record/relation/predicate_builder/basic_object_handler.rb +17 -0
- data/lib/active_record/relation/predicate_builder/class_handler.rb +27 -0
- data/lib/active_record/relation/predicate_builder/polymorphic_array_handler.rb +57 -0
- data/lib/active_record/relation/predicate_builder/range_handler.rb +33 -0
- data/lib/active_record/relation/predicate_builder/relation_handler.rb +1 -1
- data/lib/active_record/relation/query_attribute.rb +19 -0
- data/lib/active_record/relation/query_methods.rb +308 -244
- data/lib/active_record/relation/record_fetch_warning.rb +49 -0
- data/lib/active_record/relation/spawn_methods.rb +4 -7
- data/lib/active_record/relation/where_clause.rb +174 -0
- data/lib/active_record/relation/where_clause_factory.rb +38 -0
- data/lib/active_record/result.rb +11 -4
- data/lib/active_record/runtime_registry.rb +1 -1
- data/lib/active_record/sanitization.rb +105 -66
- data/lib/active_record/schema.rb +26 -22
- data/lib/active_record/schema_dumper.rb +54 -37
- data/lib/active_record/schema_migration.rb +11 -14
- data/lib/active_record/scoping.rb +34 -16
- data/lib/active_record/scoping/default.rb +28 -10
- data/lib/active_record/scoping/named.rb +59 -26
- data/lib/active_record/secure_token.rb +38 -0
- data/lib/active_record/serialization.rb +3 -5
- data/lib/active_record/statement_cache.rb +17 -15
- data/lib/active_record/store.rb +8 -3
- data/lib/active_record/suppressor.rb +58 -0
- data/lib/active_record/table_metadata.rb +69 -0
- data/lib/active_record/tasks/database_tasks.rb +66 -49
- data/lib/active_record/tasks/mysql_database_tasks.rb +6 -14
- data/lib/active_record/tasks/postgresql_database_tasks.rb +12 -3
- data/lib/active_record/tasks/sqlite_database_tasks.rb +5 -1
- data/lib/active_record/timestamp.rb +20 -9
- data/lib/active_record/touch_later.rb +63 -0
- data/lib/active_record/transactions.rb +139 -57
- data/lib/active_record/type.rb +66 -17
- data/lib/active_record/type/adapter_specific_registry.rb +130 -0
- data/lib/active_record/type/date.rb +2 -45
- data/lib/active_record/type/date_time.rb +2 -49
- data/lib/active_record/type/internal/abstract_json.rb +33 -0
- data/lib/active_record/type/internal/timezone.rb +15 -0
- data/lib/active_record/type/serialized.rb +15 -14
- data/lib/active_record/type/time.rb +10 -16
- data/lib/active_record/type/type_map.rb +4 -4
- data/lib/active_record/type_caster.rb +7 -0
- data/lib/active_record/type_caster/connection.rb +29 -0
- data/lib/active_record/type_caster/map.rb +19 -0
- data/lib/active_record/validations.rb +33 -32
- data/lib/active_record/validations/absence.rb +23 -0
- data/lib/active_record/validations/associated.rb +10 -3
- data/lib/active_record/validations/length.rb +24 -0
- data/lib/active_record/validations/presence.rb +11 -12
- data/lib/active_record/validations/uniqueness.rb +33 -33
- data/lib/rails/generators/active_record/migration.rb +15 -0
- data/lib/rails/generators/active_record/migration/migration_generator.rb +8 -5
- data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb +8 -3
- data/lib/rails/generators/active_record/migration/templates/migration.rb +8 -1
- data/lib/rails/generators/active_record/model/model_generator.rb +33 -16
- data/lib/rails/generators/active_record/model/templates/application_record.rb +5 -0
- data/lib/rails/generators/active_record/model/templates/model.rb +3 -0
- metadata +58 -34
- data/lib/active_record/connection_adapters/mysql_adapter.rb +0 -498
- data/lib/active_record/connection_adapters/postgresql/array_parser.rb +0 -93
- data/lib/active_record/connection_adapters/postgresql/oid/date.rb +0 -11
- 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/integer.rb +0 -11
- data/lib/active_record/connection_adapters/postgresql/oid/time.rb +0 -11
- 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/decimal_without_scale.rb +0 -11
- 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/text.rb +0 -11
- data/lib/active_record/type/time_value.rb +0 -38
- data/lib/active_record/type/unsigned_integer.rb +0 -15
- data/lib/active_record/type/value.rb +0 -110
@@ -1,5 +1,6 @@
|
|
1
|
+
require "set"
|
2
|
+
require "zlib"
|
1
3
|
require "active_support/core_ext/module/attribute_accessors"
|
2
|
-
require 'set'
|
3
4
|
|
4
5
|
module ActiveRecord
|
5
6
|
class MigrationError < ActiveRecordError#:nodoc:
|
@@ -9,40 +10,170 @@ module ActiveRecord
|
|
9
10
|
end
|
10
11
|
end
|
11
12
|
|
12
|
-
# Exception that can be raised to stop migrations from
|
13
|
+
# Exception that can be raised to stop migrations from being rolled back.
|
14
|
+
# For example the following migration is not reversible.
|
15
|
+
# Rolling back this migration will raise an ActiveRecord::IrreversibleMigration error.
|
16
|
+
#
|
17
|
+
# class IrreversibleMigrationExample < ActiveRecord::Migration[5.0]
|
18
|
+
# def change
|
19
|
+
# create_table :distributors do |t|
|
20
|
+
# t.string :zipcode
|
21
|
+
# end
|
22
|
+
#
|
23
|
+
# execute <<-SQL
|
24
|
+
# ALTER TABLE distributors
|
25
|
+
# ADD CONSTRAINT zipchk
|
26
|
+
# CHECK (char_length(zipcode) = 5) NO INHERIT;
|
27
|
+
# SQL
|
28
|
+
# end
|
29
|
+
# end
|
30
|
+
#
|
31
|
+
# There are two ways to mitigate this problem.
|
32
|
+
#
|
33
|
+
# 1. Define <tt>#up</tt> and <tt>#down</tt> methods instead of <tt>#change</tt>:
|
34
|
+
#
|
35
|
+
# class ReversibleMigrationExample < ActiveRecord::Migration[5.0]
|
36
|
+
# def up
|
37
|
+
# create_table :distributors do |t|
|
38
|
+
# t.string :zipcode
|
39
|
+
# end
|
40
|
+
#
|
41
|
+
# execute <<-SQL
|
42
|
+
# ALTER TABLE distributors
|
43
|
+
# ADD CONSTRAINT zipchk
|
44
|
+
# CHECK (char_length(zipcode) = 5) NO INHERIT;
|
45
|
+
# SQL
|
46
|
+
# end
|
47
|
+
#
|
48
|
+
# def down
|
49
|
+
# execute <<-SQL
|
50
|
+
# ALTER TABLE distributors
|
51
|
+
# DROP CONSTRAINT zipchk
|
52
|
+
# SQL
|
53
|
+
#
|
54
|
+
# drop_table :distributors
|
55
|
+
# end
|
56
|
+
# end
|
57
|
+
#
|
58
|
+
# 2. Use the #reversible method in <tt>#change</tt> method:
|
59
|
+
#
|
60
|
+
# class ReversibleMigrationExample < ActiveRecord::Migration[5.0]
|
61
|
+
# def change
|
62
|
+
# create_table :distributors do |t|
|
63
|
+
# t.string :zipcode
|
64
|
+
# end
|
65
|
+
#
|
66
|
+
# reversible do |dir|
|
67
|
+
# dir.up do
|
68
|
+
# execute <<-SQL
|
69
|
+
# ALTER TABLE distributors
|
70
|
+
# ADD CONSTRAINT zipchk
|
71
|
+
# CHECK (char_length(zipcode) = 5) NO INHERIT;
|
72
|
+
# SQL
|
73
|
+
# end
|
74
|
+
#
|
75
|
+
# dir.down do
|
76
|
+
# execute <<-SQL
|
77
|
+
# ALTER TABLE distributors
|
78
|
+
# DROP CONSTRAINT zipchk
|
79
|
+
# SQL
|
80
|
+
# end
|
81
|
+
# end
|
82
|
+
# end
|
83
|
+
# end
|
13
84
|
class IrreversibleMigration < MigrationError
|
14
85
|
end
|
15
86
|
|
16
87
|
class DuplicateMigrationVersionError < MigrationError#:nodoc:
|
17
|
-
def initialize(version)
|
18
|
-
|
88
|
+
def initialize(version = nil)
|
89
|
+
if version
|
90
|
+
super("Multiple migrations have the version number #{version}.")
|
91
|
+
else
|
92
|
+
super("Duplicate migration version error.")
|
93
|
+
end
|
19
94
|
end
|
20
95
|
end
|
21
96
|
|
22
97
|
class DuplicateMigrationNameError < MigrationError#:nodoc:
|
23
|
-
def initialize(name)
|
24
|
-
|
98
|
+
def initialize(name = nil)
|
99
|
+
if name
|
100
|
+
super("Multiple migrations have the name #{name}.")
|
101
|
+
else
|
102
|
+
super("Duplicate migration name.")
|
103
|
+
end
|
25
104
|
end
|
26
105
|
end
|
27
106
|
|
28
107
|
class UnknownMigrationVersionError < MigrationError #:nodoc:
|
29
|
-
def initialize(version)
|
30
|
-
|
108
|
+
def initialize(version = nil)
|
109
|
+
if version
|
110
|
+
super("No migration with version number #{version}.")
|
111
|
+
else
|
112
|
+
super("Unknown migration version.")
|
113
|
+
end
|
31
114
|
end
|
32
115
|
end
|
33
116
|
|
34
117
|
class IllegalMigrationNameError < MigrationError#:nodoc:
|
35
|
-
def initialize(name)
|
36
|
-
|
118
|
+
def initialize(name = nil)
|
119
|
+
if name
|
120
|
+
super("Illegal name for migration file: #{name}\n\t(only lower case letters, numbers, and '_' allowed).")
|
121
|
+
else
|
122
|
+
super("Illegal name for migration.")
|
123
|
+
end
|
37
124
|
end
|
38
125
|
end
|
39
126
|
|
40
127
|
class PendingMigrationError < MigrationError#:nodoc:
|
128
|
+
def initialize(message = nil)
|
129
|
+
if !message && defined?(Rails.env)
|
130
|
+
super("Migrations are pending. To resolve this issue, run:\n\n bin/rails db:migrate RAILS_ENV=#{::Rails.env}")
|
131
|
+
elsif !message
|
132
|
+
super("Migrations are pending. To resolve this issue, run:\n\n bin/rails db:migrate")
|
133
|
+
else
|
134
|
+
super
|
135
|
+
end
|
136
|
+
end
|
137
|
+
end
|
138
|
+
|
139
|
+
class ConcurrentMigrationError < MigrationError #:nodoc:
|
140
|
+
DEFAULT_MESSAGE = "Cannot run migrations because another migration process is currently running.".freeze
|
141
|
+
|
142
|
+
def initialize(message = DEFAULT_MESSAGE)
|
143
|
+
super
|
144
|
+
end
|
145
|
+
end
|
146
|
+
|
147
|
+
class NoEnvironmentInSchemaError < MigrationError #:nodoc:
|
41
148
|
def initialize
|
149
|
+
msg = "Environment data not found in the schema. To resolve this issue, run: \n\n bin/rails db:environment:set"
|
150
|
+
if defined?(Rails.env)
|
151
|
+
super("#{msg} RAILS_ENV=#{::Rails.env}")
|
152
|
+
else
|
153
|
+
super(msg)
|
154
|
+
end
|
155
|
+
end
|
156
|
+
end
|
157
|
+
|
158
|
+
class ProtectedEnvironmentError < ActiveRecordError #:nodoc:
|
159
|
+
def initialize(env = "production")
|
160
|
+
msg = "You are attempting to run a destructive action against your '#{env}' database.\n"
|
161
|
+
msg << "If you are sure you want to continue, run the same command with the environment variable:\n"
|
162
|
+
msg << "DISABLE_DATABASE_ENVIRONMENT_CHECK=1"
|
163
|
+
super(msg)
|
164
|
+
end
|
165
|
+
end
|
166
|
+
|
167
|
+
class EnvironmentMismatchError < ActiveRecordError
|
168
|
+
def initialize(current: nil, stored: nil)
|
169
|
+
msg = "You are attempting to modify a database that was last run in `#{ stored }` environment.\n"
|
170
|
+
msg << "You are running in `#{ current }` environment. "
|
171
|
+
msg << "If you are sure you want to continue, first set the environment using:\n\n"
|
172
|
+
msg << " bin/rails db:environment:set"
|
42
173
|
if defined?(Rails.env)
|
43
|
-
super("
|
174
|
+
super("#{msg} RAILS_ENV=#{::Rails.env}\n\n")
|
44
175
|
else
|
45
|
-
super("
|
176
|
+
super("#{msg}\n\n")
|
46
177
|
end
|
47
178
|
end
|
48
179
|
end
|
@@ -59,7 +190,7 @@ module ActiveRecord
|
|
59
190
|
#
|
60
191
|
# Example of a simple migration:
|
61
192
|
#
|
62
|
-
# class AddSsl < ActiveRecord::Migration
|
193
|
+
# class AddSsl < ActiveRecord::Migration[5.0]
|
63
194
|
# def up
|
64
195
|
# add_column :accounts, :ssl_enabled, :boolean, default: true
|
65
196
|
# end
|
@@ -79,7 +210,7 @@ module ActiveRecord
|
|
79
210
|
#
|
80
211
|
# Example of a more complex migration that also needs to initialize data:
|
81
212
|
#
|
82
|
-
# class AddSystemSettings < ActiveRecord::Migration
|
213
|
+
# class AddSystemSettings < ActiveRecord::Migration[5.0]
|
83
214
|
# def up
|
84
215
|
# create_table :system_settings do |t|
|
85
216
|
# t.string :name
|
@@ -106,17 +237,18 @@ module ActiveRecord
|
|
106
237
|
#
|
107
238
|
# == Available transformations
|
108
239
|
#
|
240
|
+
# === Creation
|
241
|
+
#
|
242
|
+
# * <tt>create_join_table(table_1, table_2, options)</tt>: Creates a join
|
243
|
+
# table having its name as the lexical order of the first two
|
244
|
+
# arguments. See
|
245
|
+
# ActiveRecord::ConnectionAdapters::SchemaStatements#create_join_table for
|
246
|
+
# details.
|
109
247
|
# * <tt>create_table(name, options)</tt>: Creates a table called +name+ and
|
110
248
|
# makes the table object available to a block that can then add columns to it,
|
111
249
|
# following the same format as +add_column+. See example above. The options hash
|
112
250
|
# is for fragments like "DEFAULT CHARSET=UTF-8" that are appended to the create
|
113
251
|
# 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
252
|
# * <tt>add_column(table_name, column_name, type, options)</tt>: Adds a new column
|
121
253
|
# to the table called +table_name+
|
122
254
|
# named +column_name+ specified to be one of the following types:
|
@@ -127,21 +259,59 @@ module ActiveRecord
|
|
127
259
|
# Other options include <tt>:limit</tt> and <tt>:null</tt> (e.g.
|
128
260
|
# <tt>{ limit: 50, null: false }</tt>) -- see
|
129
261
|
# 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+.
|
262
|
+
# * <tt>add_foreign_key(from_table, to_table, options)</tt>: Adds a new
|
263
|
+
# foreign key. +from_table+ is the table with the key column, +to_table+ contains
|
264
|
+
# the referenced primary key.
|
136
265
|
# * <tt>add_index(table_name, column_names, options)</tt>: Adds a new index
|
137
266
|
# with the name of the column. Other options include
|
138
267
|
# <tt>:name</tt>, <tt>:unique</tt> (e.g.
|
139
268
|
# <tt>{ name: 'users_name_index', unique: true }</tt>) and <tt>:order</tt>
|
140
269
|
# (e.g. <tt>{ order: { name: :desc } }</tt>).
|
141
|
-
# * <tt>
|
142
|
-
#
|
270
|
+
# * <tt>add_reference(:table_name, :reference_name)</tt>: Adds a new column
|
271
|
+
# +reference_name_id+ by default an integer. See
|
272
|
+
# ActiveRecord::ConnectionAdapters::SchemaStatements#add_reference for details.
|
273
|
+
# * <tt>add_timestamps(table_name, options)</tt>: Adds timestamps (+created_at+
|
274
|
+
# and +updated_at+) columns to +table_name+.
|
275
|
+
#
|
276
|
+
# === Modification
|
277
|
+
#
|
278
|
+
# * <tt>change_column(table_name, column_name, type, options)</tt>: Changes
|
279
|
+
# the column to a different type using the same parameters as add_column.
|
280
|
+
# * <tt>change_column_default(table_name, column_name, default)</tt>: Sets a
|
281
|
+
# default value for +column_name+ defined by +default+ on +table_name+.
|
282
|
+
# * <tt>change_column_null(table_name, column_name, null, default = nil)</tt>:
|
283
|
+
# Sets or removes a +NOT NULL+ constraint on +column_name+. The +null+ flag
|
284
|
+
# indicates whether the value can be +NULL+. See
|
285
|
+
# ActiveRecord::ConnectionAdapters::SchemaStatements#change_column_null for
|
286
|
+
# details.
|
287
|
+
# * <tt>change_table(name, options)</tt>: Allows to make column alterations to
|
288
|
+
# the table called +name+. It makes the table object available to a block that
|
289
|
+
# can then add/remove columns, indexes or foreign keys to it.
|
290
|
+
# * <tt>rename_column(table_name, column_name, new_column_name)</tt>: Renames
|
291
|
+
# a column but keeps the type and content.
|
292
|
+
# * <tt>rename_index(table_name, old_name, new_name)</tt>: Renames an index.
|
293
|
+
# * <tt>rename_table(old_name, new_name)</tt>: Renames the table called +old_name+
|
294
|
+
# to +new_name+.
|
295
|
+
#
|
296
|
+
# === Deletion
|
297
|
+
#
|
298
|
+
# * <tt>drop_table(name)</tt>: Drops the table called +name+.
|
299
|
+
# * <tt>drop_join_table(table_1, table_2, options)</tt>: Drops the join table
|
300
|
+
# specified by the given arguments.
|
301
|
+
# * <tt>remove_column(table_name, column_name, type, options)</tt>: Removes the column
|
302
|
+
# named +column_name+ from the table called +table_name+.
|
303
|
+
# * <tt>remove_columns(table_name, *column_names)</tt>: Removes the given
|
304
|
+
# columns from the table definition.
|
305
|
+
# * <tt>remove_foreign_key(from_table, options_or_to_table)</tt>: Removes the
|
306
|
+
# given foreign key from the table called +table_name+.
|
307
|
+
# * <tt>remove_index(table_name, column: column_names)</tt>: Removes the index
|
308
|
+
# specified by +column_names+.
|
143
309
|
# * <tt>remove_index(table_name, name: index_name)</tt>: Removes the index
|
144
310
|
# specified by +index_name+.
|
311
|
+
# * <tt>remove_reference(table_name, ref_name, options)</tt>: Removes the
|
312
|
+
# reference(s) on +table_name+ specified by +ref_name+.
|
313
|
+
# * <tt>remove_timestamps(table_name, options)</tt>: Removes the timestamp
|
314
|
+
# columns (+created_at+ and +updated_at+) from the table definition.
|
145
315
|
#
|
146
316
|
# == Irreversible transformations
|
147
317
|
#
|
@@ -165,24 +335,24 @@ module ActiveRecord
|
|
165
335
|
#
|
166
336
|
# rails generate migration add_fieldname_to_tablename fieldname:string
|
167
337
|
#
|
168
|
-
# This will generate the file <tt>timestamp_add_fieldname_to_tablename</tt>, which will look like this:
|
169
|
-
# class AddFieldnameToTablename < ActiveRecord::Migration
|
338
|
+
# This will generate the file <tt>timestamp_add_fieldname_to_tablename.rb</tt>, which will look like this:
|
339
|
+
# class AddFieldnameToTablename < ActiveRecord::Migration[5.0]
|
170
340
|
# def change
|
171
|
-
# add_column :tablenames, :
|
341
|
+
# add_column :tablenames, :fieldname, :string
|
172
342
|
# end
|
173
343
|
# end
|
174
344
|
#
|
175
345
|
# To run migrations against the currently configured database, use
|
176
|
-
# <tt>
|
346
|
+
# <tt>rails db:migrate</tt>. This will update the database by running all of the
|
177
347
|
# pending migrations, creating the <tt>schema_migrations</tt> table
|
178
348
|
# (see "About the schema_migrations table" section below) if missing. It will also
|
179
349
|
# invoke the db:schema:dump task, which will update your db/schema.rb file
|
180
350
|
# to match the structure of your database.
|
181
351
|
#
|
182
352
|
# To roll the database back to a previous migration version, use
|
183
|
-
# <tt>
|
353
|
+
# <tt>rails db:migrate VERSION=X</tt> where <tt>X</tt> is the version to which
|
184
354
|
# you wish to downgrade. Alternatively, you can also use the STEP option if you
|
185
|
-
# wish to rollback last few migrations. <tt>
|
355
|
+
# wish to rollback last few migrations. <tt>rails db:migrate STEP=2</tt> will rollback
|
186
356
|
# the latest two migrations.
|
187
357
|
#
|
188
358
|
# If any of the migrations throw an <tt>ActiveRecord::IrreversibleMigration</tt> exception,
|
@@ -197,7 +367,7 @@ module ActiveRecord
|
|
197
367
|
#
|
198
368
|
# Not all migrations change the schema. Some just fix the data:
|
199
369
|
#
|
200
|
-
# class RemoveEmptyTags < ActiveRecord::Migration
|
370
|
+
# class RemoveEmptyTags < ActiveRecord::Migration[5.0]
|
201
371
|
# def up
|
202
372
|
# Tag.all.each { |tag| tag.destroy if tag.pages.empty? }
|
203
373
|
# end
|
@@ -210,7 +380,7 @@ module ActiveRecord
|
|
210
380
|
#
|
211
381
|
# Others remove columns when they migrate up instead of down:
|
212
382
|
#
|
213
|
-
# class RemoveUnnecessaryItemAttributes < ActiveRecord::Migration
|
383
|
+
# class RemoveUnnecessaryItemAttributes < ActiveRecord::Migration[5.0]
|
214
384
|
# def up
|
215
385
|
# remove_column :items, :incomplete_items_count
|
216
386
|
# remove_column :items, :completed_items_count
|
@@ -224,7 +394,7 @@ module ActiveRecord
|
|
224
394
|
#
|
225
395
|
# And sometimes you need to do something in SQL not abstracted directly by migrations:
|
226
396
|
#
|
227
|
-
# class MakeJoinUnique < ActiveRecord::Migration
|
397
|
+
# class MakeJoinUnique < ActiveRecord::Migration[5.0]
|
228
398
|
# def up
|
229
399
|
# execute "ALTER TABLE `pages_linked_pages` ADD UNIQUE `page_id_linked_page_id` (`page_id`,`linked_page_id`)"
|
230
400
|
# end
|
@@ -241,7 +411,7 @@ module ActiveRecord
|
|
241
411
|
# <tt>Base#reset_column_information</tt> in order to ensure that the model has the
|
242
412
|
# latest column data from after the new column was added. Example:
|
243
413
|
#
|
244
|
-
# class AddPeopleSalary < ActiveRecord::Migration
|
414
|
+
# class AddPeopleSalary < ActiveRecord::Migration[5.0]
|
245
415
|
# def up
|
246
416
|
# add_column :people, :salary, :integer
|
247
417
|
# Person.reset_column_information
|
@@ -275,21 +445,6 @@ module ActiveRecord
|
|
275
445
|
# The phrase "Updating salaries..." would then be printed, along with the
|
276
446
|
# benchmark for the block when the block completes.
|
277
447
|
#
|
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
448
|
# == Timestamped Migrations
|
294
449
|
#
|
295
450
|
# By default, Rails generates migrations that look like:
|
@@ -314,7 +469,7 @@ module ActiveRecord
|
|
314
469
|
# To define a reversible migration, define the +change+ method in your
|
315
470
|
# migration like this:
|
316
471
|
#
|
317
|
-
# class TenderloveMigration < ActiveRecord::Migration
|
472
|
+
# class TenderloveMigration < ActiveRecord::Migration[5.0]
|
318
473
|
# def change
|
319
474
|
# create_table(:horses) do |t|
|
320
475
|
# t.column :content, :text
|
@@ -344,7 +499,7 @@ module ActiveRecord
|
|
344
499
|
# can't execute inside a transaction though, and for these situations
|
345
500
|
# you can turn the automatic transactions off.
|
346
501
|
#
|
347
|
-
# class ChangeEnum < ActiveRecord::Migration
|
502
|
+
# class ChangeEnum < ActiveRecord::Migration[5.0]
|
348
503
|
# disable_ddl_transaction!
|
349
504
|
#
|
350
505
|
# def up
|
@@ -356,10 +511,31 @@ module ActiveRecord
|
|
356
511
|
# are in a Migration with <tt>self.disable_ddl_transaction!</tt>.
|
357
512
|
class Migration
|
358
513
|
autoload :CommandRecorder, 'active_record/migration/command_recorder'
|
514
|
+
autoload :Compatibility, 'active_record/migration/compatibility'
|
359
515
|
|
516
|
+
# This must be defined before the inherited hook, below
|
517
|
+
class Current < Migration # :nodoc:
|
518
|
+
end
|
519
|
+
|
520
|
+
def self.inherited(subclass) # :nodoc:
|
521
|
+
super
|
522
|
+
if subclass.superclass == Migration
|
523
|
+
subclass.include Compatibility::Legacy
|
524
|
+
end
|
525
|
+
end
|
526
|
+
|
527
|
+
def self.[](version)
|
528
|
+
Compatibility.find(version)
|
529
|
+
end
|
530
|
+
|
531
|
+
def self.current_version
|
532
|
+
ActiveRecord::VERSION::STRING.to_f
|
533
|
+
end
|
534
|
+
|
535
|
+
MigrationFilenameRegexp = /\A([0-9]+)_([_a-z0-9]*)\.?([_a-z0-9]*)?\.rb\z/ # :nodoc:
|
360
536
|
|
361
537
|
# 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
|
538
|
+
# loading a web page if <tt>config.active_record.migration_error</tt> is set to :page_load
|
363
539
|
class CheckPending
|
364
540
|
def initialize(app)
|
365
541
|
@app = app
|
@@ -388,17 +564,22 @@ module ActiveRecord
|
|
388
564
|
attr_accessor :delegate # :nodoc:
|
389
565
|
attr_accessor :disable_ddl_transaction # :nodoc:
|
390
566
|
|
567
|
+
def nearest_delegate # :nodoc:
|
568
|
+
delegate || superclass.nearest_delegate
|
569
|
+
end
|
570
|
+
|
571
|
+
# Raises <tt>ActiveRecord::PendingMigrationError</tt> error if any migrations are pending.
|
391
572
|
def check_pending!(connection = Base.connection)
|
392
573
|
raise ActiveRecord::PendingMigrationError if ActiveRecord::Migrator.needs_migration?(connection)
|
393
574
|
end
|
394
575
|
|
395
576
|
def load_schema_if_pending!
|
396
577
|
if ActiveRecord::Migrator.needs_migration? || !ActiveRecord::Migrator.any_migrations?
|
397
|
-
#
|
578
|
+
# Roundtrip to Rake to allow plugins to hook into database initialization.
|
398
579
|
FileUtils.cd Rails.root do
|
399
580
|
current_config = Base.connection_config
|
400
581
|
Base.clear_all_connections!
|
401
|
-
system("bin/
|
582
|
+
system("bin/rails db:test:prepare")
|
402
583
|
# Establish a new connection, the old database may be gone (db:test:prepare uses purge)
|
403
584
|
Base.establish_connection(current_config)
|
404
585
|
end
|
@@ -413,7 +594,7 @@ module ActiveRecord
|
|
413
594
|
end
|
414
595
|
|
415
596
|
def method_missing(name, *args, &block) # :nodoc:
|
416
|
-
|
597
|
+
nearest_delegate.send(name, *args, &block)
|
417
598
|
end
|
418
599
|
|
419
600
|
def migrate(direction)
|
@@ -453,7 +634,7 @@ module ActiveRecord
|
|
453
634
|
# and create the table 'apples' on the way up, and the reverse
|
454
635
|
# on the way down.
|
455
636
|
#
|
456
|
-
# class FixTLMigration < ActiveRecord::Migration
|
637
|
+
# class FixTLMigration < ActiveRecord::Migration[5.0]
|
457
638
|
# def change
|
458
639
|
# revert do
|
459
640
|
# create_table(:horses) do |t|
|
@@ -470,9 +651,9 @@ module ActiveRecord
|
|
470
651
|
# Or equivalently, if +TenderloveMigration+ is defined as in the
|
471
652
|
# documentation for Migration:
|
472
653
|
#
|
473
|
-
# require_relative '
|
654
|
+
# require_relative '20121212123456_tenderlove_migration'
|
474
655
|
#
|
475
|
-
# class FixupTLMigration < ActiveRecord::Migration
|
656
|
+
# class FixupTLMigration < ActiveRecord::Migration[5.0]
|
476
657
|
# def change
|
477
658
|
# revert TenderloveMigration
|
478
659
|
#
|
@@ -486,13 +667,13 @@ module ActiveRecord
|
|
486
667
|
def revert(*migration_classes)
|
487
668
|
run(*migration_classes.reverse, revert: true) unless migration_classes.empty?
|
488
669
|
if block_given?
|
489
|
-
if
|
490
|
-
|
670
|
+
if connection.respond_to? :revert
|
671
|
+
connection.revert { yield }
|
491
672
|
else
|
492
|
-
recorder = CommandRecorder.new(
|
673
|
+
recorder = CommandRecorder.new(connection)
|
493
674
|
@connection = recorder
|
494
675
|
suppress_messages do
|
495
|
-
|
676
|
+
connection.revert { yield }
|
496
677
|
end
|
497
678
|
@connection = recorder.delegate
|
498
679
|
recorder.commands.each do |cmd, args, block|
|
@@ -503,7 +684,7 @@ module ActiveRecord
|
|
503
684
|
end
|
504
685
|
|
505
686
|
def reverting?
|
506
|
-
|
687
|
+
connection.respond_to?(:reverting) && connection.reverting
|
507
688
|
end
|
508
689
|
|
509
690
|
class ReversibleBlockHelper < Struct.new(:reverting) # :nodoc:
|
@@ -525,7 +706,7 @@ module ActiveRecord
|
|
525
706
|
# when the three columns 'first_name', 'last_name' and 'full_name' exist,
|
526
707
|
# even when migrating down:
|
527
708
|
#
|
528
|
-
# class SplitNameMigration < ActiveRecord::Migration
|
709
|
+
# class SplitNameMigration < ActiveRecord::Migration[5.0]
|
529
710
|
# def change
|
530
711
|
# add_column :users, :first_name, :string
|
531
712
|
# add_column :users, :last_name, :string
|
@@ -560,7 +741,7 @@ module ActiveRecord
|
|
560
741
|
revert { run(*migration_classes, direction: dir, revert: true) }
|
561
742
|
else
|
562
743
|
migration_classes.each do |migration_class|
|
563
|
-
migration_class.new.exec_migration(
|
744
|
+
migration_class.new.exec_migration(connection, dir)
|
564
745
|
end
|
565
746
|
end
|
566
747
|
end
|
@@ -649,10 +830,10 @@ module ActiveRecord
|
|
649
830
|
end
|
650
831
|
|
651
832
|
def method_missing(method, *arguments, &block)
|
652
|
-
arg_list = arguments.map
|
833
|
+
arg_list = arguments.map(&:inspect) * ', '
|
653
834
|
|
654
835
|
say_with_time "#{method}(#{arg_list})" do
|
655
|
-
unless
|
836
|
+
unless connection.respond_to? :revert
|
656
837
|
unless arguments.empty? || [:execute, :enable_extension, :disable_extension].include?(method)
|
657
838
|
arguments[0] = proper_table_name(arguments.first, table_name_options)
|
658
839
|
if [:rename_table, :add_foreign_key].include?(method) ||
|
@@ -731,7 +912,9 @@ module ActiveRecord
|
|
731
912
|
end
|
732
913
|
end
|
733
914
|
|
734
|
-
|
915
|
+
# Builds a hash for use in ActiveRecord::Migration#proper_table_name using
|
916
|
+
# the Active Record object's table_name prefix and suffix
|
917
|
+
def table_name_options(config = ActiveRecord::Base) #:nodoc:
|
735
918
|
{
|
736
919
|
table_name_prefix: config.table_name_prefix,
|
737
920
|
table_name_suffix: config.table_name_suffix
|
@@ -823,7 +1006,7 @@ module ActiveRecord
|
|
823
1006
|
new(:up, migrations, target_version).migrate
|
824
1007
|
end
|
825
1008
|
|
826
|
-
def down(migrations_paths, target_version = nil
|
1009
|
+
def down(migrations_paths, target_version = nil)
|
827
1010
|
migrations = migrations(migrations_paths)
|
828
1011
|
migrations.select! { |m| yield m } if block_given?
|
829
1012
|
|
@@ -843,10 +1026,12 @@ module ActiveRecord
|
|
843
1026
|
end
|
844
1027
|
|
845
1028
|
def get_all_versions(connection = Base.connection)
|
846
|
-
|
847
|
-
|
848
|
-
|
849
|
-
|
1029
|
+
ActiveSupport::Deprecation.silence do
|
1030
|
+
if connection.table_exists?(schema_migrations_table_name)
|
1031
|
+
SchemaMigration.all.map { |x| x.version.to_i }.sort
|
1032
|
+
else
|
1033
|
+
[]
|
1034
|
+
end
|
850
1035
|
end
|
851
1036
|
end
|
852
1037
|
|
@@ -862,26 +1047,18 @@ module ActiveRecord
|
|
862
1047
|
migrations(migrations_paths).any?
|
863
1048
|
end
|
864
1049
|
|
865
|
-
def last_version
|
866
|
-
last_migration.version
|
867
|
-
end
|
868
|
-
|
869
1050
|
def last_migration #:nodoc:
|
870
1051
|
migrations(migrations_paths).last || NullMigration.new
|
871
1052
|
end
|
872
1053
|
|
873
1054
|
def migrations_paths
|
874
1055
|
@migrations_paths ||= ['db/migrate']
|
875
|
-
# just to not break things if someone uses:
|
1056
|
+
# just to not break things if someone uses: migrations_path = some_string
|
876
1057
|
Array(@migrations_paths)
|
877
1058
|
end
|
878
1059
|
|
879
|
-
def migrations_path
|
880
|
-
migrations_paths.first
|
881
|
-
end
|
882
|
-
|
883
1060
|
def parse_migration_filename(filename) # :nodoc:
|
884
|
-
File.basename(filename).scan(
|
1061
|
+
File.basename(filename).scan(Migration::MigrationFilenameRegexp).first
|
885
1062
|
end
|
886
1063
|
|
887
1064
|
def migrations(paths)
|
@@ -948,6 +1125,7 @@ module ActiveRecord
|
|
948
1125
|
validate(@migrations)
|
949
1126
|
|
950
1127
|
Base.connection.initialize_schema_migrations_table
|
1128
|
+
Base.connection.initialize_internal_metadata_table
|
951
1129
|
end
|
952
1130
|
|
953
1131
|
def current_version
|
@@ -960,32 +1138,18 @@ module ActiveRecord
|
|
960
1138
|
alias :current :current_migration
|
961
1139
|
|
962
1140
|
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
|
1141
|
+
if use_advisory_lock?
|
1142
|
+
with_advisory_lock { run_without_lock }
|
1143
|
+
else
|
1144
|
+
run_without_lock
|
972
1145
|
end
|
973
1146
|
end
|
974
1147
|
|
975
1148
|
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
|
1149
|
+
if use_advisory_lock?
|
1150
|
+
with_advisory_lock { migrate_without_lock }
|
1151
|
+
else
|
1152
|
+
migrate_without_lock
|
989
1153
|
end
|
990
1154
|
end
|
991
1155
|
|
@@ -1010,19 +1174,69 @@ module ActiveRecord
|
|
1010
1174
|
end
|
1011
1175
|
|
1012
1176
|
def migrated
|
1013
|
-
@migrated_versions
|
1177
|
+
@migrated_versions || load_migrated
|
1178
|
+
end
|
1179
|
+
|
1180
|
+
def load_migrated
|
1181
|
+
@migrated_versions = Set.new(self.class.get_all_versions)
|
1014
1182
|
end
|
1015
1183
|
|
1016
1184
|
private
|
1185
|
+
|
1186
|
+
# Used for running a specific migration.
|
1187
|
+
def run_without_lock
|
1188
|
+
migration = migrations.detect { |m| m.version == @target_version }
|
1189
|
+
raise UnknownMigrationVersionError.new(@target_version) if migration.nil?
|
1190
|
+
result = execute_migration_in_transaction(migration, @direction)
|
1191
|
+
|
1192
|
+
record_environment
|
1193
|
+
result
|
1194
|
+
end
|
1195
|
+
|
1196
|
+
# Used for running multiple migrations up to or down to a certain value.
|
1197
|
+
def migrate_without_lock
|
1198
|
+
if invalid_target?
|
1199
|
+
raise UnknownMigrationVersionError.new(@target_version)
|
1200
|
+
end
|
1201
|
+
|
1202
|
+
result = runnable.each do |migration|
|
1203
|
+
execute_migration_in_transaction(migration, @direction)
|
1204
|
+
end
|
1205
|
+
|
1206
|
+
record_environment
|
1207
|
+
result
|
1208
|
+
end
|
1209
|
+
|
1210
|
+
# Stores the current environment in the database.
|
1211
|
+
def record_environment
|
1212
|
+
return if down?
|
1213
|
+
ActiveRecord::InternalMetadata[:environment] = ActiveRecord::Migrator.current_environment
|
1214
|
+
end
|
1215
|
+
|
1017
1216
|
def ran?(migration)
|
1018
1217
|
migrated.include?(migration.version.to_i)
|
1019
1218
|
end
|
1020
1219
|
|
1220
|
+
# Return true if a valid version is not provided.
|
1221
|
+
def invalid_target?
|
1222
|
+
!target && @target_version && @target_version > 0
|
1223
|
+
end
|
1224
|
+
|
1021
1225
|
def execute_migration_in_transaction(migration, direction)
|
1226
|
+
return if down? && !migrated.include?(migration.version.to_i)
|
1227
|
+
return if up? && migrated.include?(migration.version.to_i)
|
1228
|
+
|
1229
|
+
Base.logger.info "Migrating to #{migration.name} (#{migration.version})" if Base.logger
|
1230
|
+
|
1022
1231
|
ddl_transaction(migration) do
|
1023
1232
|
migration.migrate(direction)
|
1024
1233
|
record_version_state_after_migrating(migration.version)
|
1025
1234
|
end
|
1235
|
+
rescue => e
|
1236
|
+
msg = "An error has occurred, "
|
1237
|
+
msg << "this and " if use_transaction?(migration)
|
1238
|
+
msg << "all later migrations canceled:\n\n#{e}"
|
1239
|
+
raise StandardError, msg, e.backtrace
|
1026
1240
|
end
|
1027
1241
|
|
1028
1242
|
def target
|
@@ -1051,10 +1265,27 @@ module ActiveRecord
|
|
1051
1265
|
ActiveRecord::SchemaMigration.where(:version => version.to_s).delete_all
|
1052
1266
|
else
|
1053
1267
|
migrated << version
|
1054
|
-
ActiveRecord::SchemaMigration.create!(:
|
1268
|
+
ActiveRecord::SchemaMigration.create!(version: version.to_s)
|
1055
1269
|
end
|
1056
1270
|
end
|
1057
1271
|
|
1272
|
+
def self.last_stored_environment
|
1273
|
+
return nil if current_version == 0
|
1274
|
+
raise NoEnvironmentInSchemaError unless ActiveRecord::InternalMetadata.table_exists?
|
1275
|
+
|
1276
|
+
environment = ActiveRecord::InternalMetadata[:environment]
|
1277
|
+
raise NoEnvironmentInSchemaError unless environment
|
1278
|
+
environment
|
1279
|
+
end
|
1280
|
+
|
1281
|
+
def self.current_environment
|
1282
|
+
ActiveRecord::ConnectionHandling::DEFAULT_ENV.call
|
1283
|
+
end
|
1284
|
+
|
1285
|
+
def self.protected_environment?
|
1286
|
+
ActiveRecord::Base.protected_environments.include?(last_stored_environment) if last_stored_environment
|
1287
|
+
end
|
1288
|
+
|
1058
1289
|
def up?
|
1059
1290
|
@direction == :up
|
1060
1291
|
end
|
@@ -1075,5 +1306,25 @@ module ActiveRecord
|
|
1075
1306
|
def use_transaction?(migration)
|
1076
1307
|
!migration.disable_ddl_transaction && Base.connection.supports_ddl_transactions?
|
1077
1308
|
end
|
1309
|
+
|
1310
|
+
def use_advisory_lock?
|
1311
|
+
Base.connection.supports_advisory_locks?
|
1312
|
+
end
|
1313
|
+
|
1314
|
+
def with_advisory_lock
|
1315
|
+
lock_id = generate_migrator_advisory_lock_id
|
1316
|
+
got_lock = Base.connection.get_advisory_lock(lock_id)
|
1317
|
+
raise ConcurrentMigrationError unless got_lock
|
1318
|
+
load_migrated # reload schema_migrations to be sure it wasn't changed by another process before we got the lock
|
1319
|
+
yield
|
1320
|
+
ensure
|
1321
|
+
Base.connection.release_advisory_lock(lock_id) if got_lock
|
1322
|
+
end
|
1323
|
+
|
1324
|
+
MIGRATOR_SALT = 2053462845
|
1325
|
+
def generate_migrator_advisory_lock_id
|
1326
|
+
db_name_hash = Zlib.crc32(Base.connection.current_database)
|
1327
|
+
MIGRATOR_SALT * db_name_hash
|
1328
|
+
end
|
1078
1329
|
end
|
1079
1330
|
end
|