activerecord 4.2.0 → 5.0.0
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 +1537 -789
- 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/aggregations.rb +37 -23
- data/lib/active_record/association_relation.rb +16 -3
- data/lib/active_record/associations/alias_tracker.rb +19 -16
- data/lib/active_record/associations/association.rb +23 -9
- data/lib/active_record/associations/association_scope.rb +74 -102
- data/lib/active_record/associations/belongs_to_association.rb +26 -29
- 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 +12 -20
- data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +22 -15
- 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 +3 -10
- data/lib/active_record/associations/collection_association.rb +61 -33
- data/lib/active_record/associations/collection_proxy.rb +81 -35
- data/lib/active_record/associations/foreign_association.rb +11 -0
- data/lib/active_record/associations/has_many_association.rb +21 -57
- data/lib/active_record/associations/has_many_through_association.rb +15 -45
- data/lib/active_record/associations/has_one_association.rb +13 -5
- data/lib/active_record/associations/join_dependency/join_association.rb +20 -8
- data/lib/active_record/associations/join_dependency.rb +37 -21
- data/lib/active_record/associations/preloader/association.rb +51 -53
- data/lib/active_record/associations/preloader/collection_association.rb +0 -6
- 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/through_association.rb +27 -14
- data/lib/active_record/associations/preloader.rb +18 -8
- data/lib/active_record/associations/singular_association.rb +8 -8
- data/lib/active_record/associations/through_association.rb +22 -9
- data/lib/active_record/associations.rb +321 -212
- data/lib/active_record/attribute/user_provided_default.rb +28 -0
- data/lib/active_record/attribute.rb +79 -15
- data/lib/active_record/attribute_assignment.rb +20 -141
- data/lib/active_record/attribute_decorators.rb +6 -5
- data/lib/active_record/attribute_methods/before_type_cast.rb +6 -1
- data/lib/active_record/attribute_methods/dirty.rb +51 -81
- data/lib/active_record/attribute_methods/primary_key.rb +2 -2
- 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 +65 -14
- data/lib/active_record/attribute_methods/write.rb +14 -38
- data/lib/active_record/attribute_methods.rb +70 -45
- data/lib/active_record/attribute_mutation_tracker.rb +70 -0
- data/lib/active_record/attribute_set/builder.rb +37 -15
- data/lib/active_record/attribute_set.rb +34 -3
- data/lib/active_record/attributes.rb +199 -73
- data/lib/active_record/autosave_association.rb +73 -25
- data/lib/active_record/base.rb +35 -27
- 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 +40 -0
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +457 -181
- data/lib/active_record/connection_adapters/abstract/database_limits.rb +3 -3
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +83 -59
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +3 -3
- data/lib/active_record/connection_adapters/abstract/quoting.rb +74 -9
- data/lib/active_record/connection_adapters/abstract/savepoints.rb +4 -4
- data/lib/active_record/connection_adapters/abstract/schema_creation.rb +61 -39
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +246 -185
- data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +72 -17
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +438 -136
- data/lib/active_record/connection_adapters/abstract/transaction.rb +53 -40
- data/lib/active_record/connection_adapters/abstract_adapter.rb +166 -66
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +429 -335
- 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 +125 -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 +26 -177
- data/lib/active_record/connection_adapters/postgresql/column.rb +5 -10
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +11 -73
- data/lib/active_record/connection_adapters/postgresql/explain_pretty_printer.rb +42 -0
- data/lib/active_record/connection_adapters/postgresql/oid/array.rb +27 -56
- data/lib/active_record/connection_adapters/postgresql/oid/bit.rb +2 -2
- data/lib/active_record/connection_adapters/postgresql/oid/bytea.rb +2 -1
- data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +3 -1
- data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +7 -13
- data/lib/active_record/connection_adapters/postgresql/oid/enum.rb +3 -1
- data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +3 -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/type_map_initializer.rb +17 -5
- 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/oid.rb +1 -6
- data/lib/active_record/connection_adapters/postgresql/quoting.rb +26 -18
- 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 +248 -154
- data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +35 -0
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +258 -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 +150 -209
- data/lib/active_record/connection_adapters/statement_pool.rb +31 -12
- data/lib/active_record/connection_handling.rb +38 -15
- data/lib/active_record/core.rb +109 -114
- data/lib/active_record/counter_cache.rb +14 -25
- data/lib/active_record/dynamic_matchers.rb +1 -20
- data/lib/active_record/enum.rb +115 -79
- data/lib/active_record/errors.rb +88 -48
- data/lib/active_record/explain_registry.rb +1 -1
- data/lib/active_record/explain_subscriber.rb +2 -2
- data/lib/active_record/fixture_set/file.rb +26 -5
- data/lib/active_record/fixtures.rb +84 -46
- data/lib/active_record/gem_version.rb +2 -2
- data/lib/active_record/inheritance.rb +32 -40
- data/lib/active_record/integration.rb +4 -4
- data/lib/active_record/internal_metadata.rb +56 -0
- data/lib/active_record/legacy_yaml_adapter.rb +46 -0
- data/lib/active_record/locale/en.yml +3 -2
- data/lib/active_record/locking/optimistic.rb +27 -25
- data/lib/active_record/locking/pessimistic.rb +1 -1
- data/lib/active_record/log_subscriber.rb +43 -21
- data/lib/active_record/migration/command_recorder.rb +59 -18
- data/lib/active_record/migration/compatibility.rb +126 -0
- data/lib/active_record/migration.rb +372 -114
- data/lib/active_record/model_schema.rb +128 -38
- data/lib/active_record/nested_attributes.rb +71 -32
- data/lib/active_record/no_touching.rb +1 -1
- data/lib/active_record/null_relation.rb +16 -8
- data/lib/active_record/persistence.rb +124 -80
- data/lib/active_record/query_cache.rb +15 -18
- data/lib/active_record/querying.rb +10 -9
- data/lib/active_record/railtie.rb +28 -19
- data/lib/active_record/railties/controller_runtime.rb +1 -1
- data/lib/active_record/railties/databases.rake +67 -51
- data/lib/active_record/readonly_attributes.rb +1 -1
- data/lib/active_record/reflection.rb +318 -139
- data/lib/active_record/relation/batches/batch_enumerator.rb +67 -0
- data/lib/active_record/relation/batches.rb +139 -34
- data/lib/active_record/relation/calculations.rb +80 -102
- data/lib/active_record/relation/delegation.rb +7 -20
- data/lib/active_record/relation/finder_methods.rb +167 -97
- data/lib/active_record/relation/from_clause.rb +32 -0
- data/lib/active_record/relation/merger.rb +38 -41
- data/lib/active_record/relation/predicate_builder/array_handler.rb +12 -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/predicate_builder.rb +124 -82
- data/lib/active_record/relation/query_attribute.rb +19 -0
- data/lib/active_record/relation/query_methods.rb +323 -257
- data/lib/active_record/relation/record_fetch_warning.rb +49 -0
- data/lib/active_record/relation/spawn_methods.rb +11 -10
- 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/relation.rb +176 -115
- data/lib/active_record/result.rb +4 -3
- data/lib/active_record/runtime_registry.rb +1 -1
- data/lib/active_record/sanitization.rb +95 -66
- data/lib/active_record/schema.rb +26 -22
- data/lib/active_record/schema_dumper.rb +62 -38
- data/lib/active_record/schema_migration.rb +11 -17
- data/lib/active_record/scoping/default.rb +24 -9
- data/lib/active_record/scoping/named.rb +49 -28
- data/lib/active_record/scoping.rb +32 -15
- data/lib/active_record/secure_token.rb +38 -0
- data/lib/active_record/serialization.rb +2 -4
- data/lib/active_record/statement_cache.rb +16 -14
- data/lib/active_record/store.rb +8 -3
- data/lib/active_record/suppressor.rb +58 -0
- data/lib/active_record/table_metadata.rb +68 -0
- data/lib/active_record/tasks/database_tasks.rb +59 -42
- data/lib/active_record/tasks/mysql_database_tasks.rb +32 -26
- data/lib/active_record/tasks/postgresql_database_tasks.rb +29 -9
- 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 +58 -0
- data/lib/active_record/transactions.rb +159 -67
- data/lib/active_record/type/adapter_specific_registry.rb +130 -0
- data/lib/active_record/type/date.rb +2 -41
- data/lib/active_record/type/date_time.rb +2 -38
- data/lib/active_record/type/hash_lookup_type_map.rb +8 -2
- data/lib/active_record/type/internal/abstract_json.rb +29 -0
- data/lib/active_record/type/internal/timezone.rb +15 -0
- data/lib/active_record/type/serialized.rb +21 -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.rb +66 -17
- data/lib/active_record/type_caster/connection.rb +29 -0
- data/lib/active_record/type_caster/map.rb +19 -0
- data/lib/active_record/type_caster.rb +7 -0
- 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 +29 -18
- data/lib/active_record/validations.rb +33 -32
- data/lib/active_record.rb +9 -2
- data/lib/rails/generators/active_record/migration/migration_generator.rb +7 -4
- data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb +8 -6
- data/lib/rails/generators/active_record/migration/templates/migration.rb +8 -7
- data/lib/rails/generators/active_record/migration.rb +7 -0
- data/lib/rails/generators/active_record/model/model_generator.rb +32 -15
- 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 +60 -34
- 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/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 -30
- data/lib/active_record/type/decimal.rb +0 -40
- 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 -55
- data/lib/active_record/type/mutable.rb +0 -16
- data/lib/active_record/type/numeric.rb +0 -36
- data/lib/active_record/type/string.rb +0 -36
- data/lib/active_record/type/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 -101
@@ -9,40 +9,170 @@ module ActiveRecord
|
|
9
9
|
end
|
10
10
|
end
|
11
11
|
|
12
|
-
# Exception that can be raised to stop migrations from
|
12
|
+
# Exception that can be raised to stop migrations from being rolled back.
|
13
|
+
# For example the following migration is not reversible.
|
14
|
+
# Rolling back this migration will raise an ActiveRecord::IrreversibleMigration error.
|
15
|
+
#
|
16
|
+
# class IrreversibleMigrationExample < ActiveRecord::Migration[5.0]
|
17
|
+
# def change
|
18
|
+
# create_table :distributors do |t|
|
19
|
+
# t.string :zipcode
|
20
|
+
# end
|
21
|
+
#
|
22
|
+
# execute <<-SQL
|
23
|
+
# ALTER TABLE distributors
|
24
|
+
# ADD CONSTRAINT zipchk
|
25
|
+
# CHECK (char_length(zipcode) = 5) NO INHERIT;
|
26
|
+
# SQL
|
27
|
+
# end
|
28
|
+
# end
|
29
|
+
#
|
30
|
+
# There are two ways to mitigate this problem.
|
31
|
+
#
|
32
|
+
# 1. Define <tt>#up</tt> and <tt>#down</tt> methods instead of <tt>#change</tt>:
|
33
|
+
#
|
34
|
+
# class ReversibleMigrationExample < ActiveRecord::Migration[5.0]
|
35
|
+
# def up
|
36
|
+
# create_table :distributors do |t|
|
37
|
+
# t.string :zipcode
|
38
|
+
# end
|
39
|
+
#
|
40
|
+
# execute <<-SQL
|
41
|
+
# ALTER TABLE distributors
|
42
|
+
# ADD CONSTRAINT zipchk
|
43
|
+
# CHECK (char_length(zipcode) = 5) NO INHERIT;
|
44
|
+
# SQL
|
45
|
+
# end
|
46
|
+
#
|
47
|
+
# def down
|
48
|
+
# execute <<-SQL
|
49
|
+
# ALTER TABLE distributors
|
50
|
+
# DROP CONSTRAINT zipchk
|
51
|
+
# SQL
|
52
|
+
#
|
53
|
+
# drop_table :distributors
|
54
|
+
# end
|
55
|
+
# end
|
56
|
+
#
|
57
|
+
# 2. Use the #reversible method in <tt>#change</tt> method:
|
58
|
+
#
|
59
|
+
# class ReversibleMigrationExample < ActiveRecord::Migration[5.0]
|
60
|
+
# def change
|
61
|
+
# create_table :distributors do |t|
|
62
|
+
# t.string :zipcode
|
63
|
+
# end
|
64
|
+
#
|
65
|
+
# reversible do |dir|
|
66
|
+
# dir.up do
|
67
|
+
# execute <<-SQL
|
68
|
+
# ALTER TABLE distributors
|
69
|
+
# ADD CONSTRAINT zipchk
|
70
|
+
# CHECK (char_length(zipcode) = 5) NO INHERIT;
|
71
|
+
# SQL
|
72
|
+
# end
|
73
|
+
#
|
74
|
+
# dir.down do
|
75
|
+
# execute <<-SQL
|
76
|
+
# ALTER TABLE distributors
|
77
|
+
# DROP CONSTRAINT zipchk
|
78
|
+
# SQL
|
79
|
+
# end
|
80
|
+
# end
|
81
|
+
# end
|
82
|
+
# end
|
13
83
|
class IrreversibleMigration < MigrationError
|
14
84
|
end
|
15
85
|
|
16
86
|
class DuplicateMigrationVersionError < MigrationError#:nodoc:
|
17
|
-
def initialize(version)
|
18
|
-
|
87
|
+
def initialize(version = nil)
|
88
|
+
if version
|
89
|
+
super("Multiple migrations have the version number #{version}.")
|
90
|
+
else
|
91
|
+
super("Duplicate migration version error.")
|
92
|
+
end
|
19
93
|
end
|
20
94
|
end
|
21
95
|
|
22
96
|
class DuplicateMigrationNameError < MigrationError#:nodoc:
|
23
|
-
def initialize(name)
|
24
|
-
|
97
|
+
def initialize(name = nil)
|
98
|
+
if name
|
99
|
+
super("Multiple migrations have the name #{name}.")
|
100
|
+
else
|
101
|
+
super("Duplicate migration name.")
|
102
|
+
end
|
25
103
|
end
|
26
104
|
end
|
27
105
|
|
28
106
|
class UnknownMigrationVersionError < MigrationError #:nodoc:
|
29
|
-
def initialize(version)
|
30
|
-
|
107
|
+
def initialize(version = nil)
|
108
|
+
if version
|
109
|
+
super("No migration with version number #{version}.")
|
110
|
+
else
|
111
|
+
super("Unknown migration version.")
|
112
|
+
end
|
31
113
|
end
|
32
114
|
end
|
33
115
|
|
34
116
|
class IllegalMigrationNameError < MigrationError#:nodoc:
|
35
|
-
def initialize(name)
|
36
|
-
|
117
|
+
def initialize(name = nil)
|
118
|
+
if name
|
119
|
+
super("Illegal name for migration file: #{name}\n\t(only lower case letters, numbers, and '_' allowed).")
|
120
|
+
else
|
121
|
+
super("Illegal name for migration.")
|
122
|
+
end
|
37
123
|
end
|
38
124
|
end
|
39
125
|
|
40
126
|
class PendingMigrationError < MigrationError#:nodoc:
|
127
|
+
def initialize(message = nil)
|
128
|
+
if !message && defined?(Rails.env)
|
129
|
+
super("Migrations are pending. To resolve this issue, run:\n\n\tbin/rails db:migrate RAILS_ENV=#{::Rails.env}")
|
130
|
+
elsif !message
|
131
|
+
super("Migrations are pending. To resolve this issue, run:\n\n\tbin/rails db:migrate")
|
132
|
+
else
|
133
|
+
super
|
134
|
+
end
|
135
|
+
end
|
136
|
+
end
|
137
|
+
|
138
|
+
class ConcurrentMigrationError < MigrationError #:nodoc:
|
139
|
+
DEFAULT_MESSAGE = "Cannot run migrations because another migration process is currently running.".freeze
|
140
|
+
|
141
|
+
def initialize(message = DEFAULT_MESSAGE)
|
142
|
+
super
|
143
|
+
end
|
144
|
+
end
|
145
|
+
|
146
|
+
class NoEnvironmentInSchemaError < MigrationError #:nodoc:
|
41
147
|
def initialize
|
42
|
-
|
43
|
-
|
148
|
+
msg = "Environment data not found in the schema. To resolve this issue, run: \n\n\tbin/rails db:environment:set"
|
149
|
+
if defined?(Rails.env)
|
150
|
+
super("#{msg} RAILS_ENV=#{::Rails.env}")
|
151
|
+
else
|
152
|
+
super(msg)
|
153
|
+
end
|
154
|
+
end
|
155
|
+
end
|
156
|
+
|
157
|
+
class ProtectedEnvironmentError < ActiveRecordError #:nodoc:
|
158
|
+
def initialize(env = "production")
|
159
|
+
msg = "You are attempting to run a destructive action against your '#{env}' database.\n"
|
160
|
+
msg << "If you are sure you want to continue, run the same command with the environment variable:\n"
|
161
|
+
msg << "DISABLE_DATABASE_ENVIRONMENT_CHECK=1"
|
162
|
+
super(msg)
|
163
|
+
end
|
164
|
+
end
|
165
|
+
|
166
|
+
class EnvironmentMismatchError < ActiveRecordError
|
167
|
+
def initialize(current: nil, stored: nil)
|
168
|
+
msg = "You are attempting to modify a database that was last run in `#{ stored }` environment.\n"
|
169
|
+
msg << "You are running in `#{ current }` environment. "
|
170
|
+
msg << "If you are sure you want to continue, first set the environment using:\n\n"
|
171
|
+
msg << "\tbin/rails db:environment:set"
|
172
|
+
if defined?(Rails.env)
|
173
|
+
super("#{msg} RAILS_ENV=#{::Rails.env}\n\n")
|
44
174
|
else
|
45
|
-
super("
|
175
|
+
super("#{msg}\n\n")
|
46
176
|
end
|
47
177
|
end
|
48
178
|
end
|
@@ -59,7 +189,7 @@ module ActiveRecord
|
|
59
189
|
#
|
60
190
|
# Example of a simple migration:
|
61
191
|
#
|
62
|
-
# class AddSsl < ActiveRecord::Migration
|
192
|
+
# class AddSsl < ActiveRecord::Migration[5.0]
|
63
193
|
# def up
|
64
194
|
# add_column :accounts, :ssl_enabled, :boolean, default: true
|
65
195
|
# end
|
@@ -79,7 +209,7 @@ module ActiveRecord
|
|
79
209
|
#
|
80
210
|
# Example of a more complex migration that also needs to initialize data:
|
81
211
|
#
|
82
|
-
# class AddSystemSettings < ActiveRecord::Migration
|
212
|
+
# class AddSystemSettings < ActiveRecord::Migration[5.0]
|
83
213
|
# def up
|
84
214
|
# create_table :system_settings do |t|
|
85
215
|
# t.string :name
|
@@ -106,17 +236,18 @@ module ActiveRecord
|
|
106
236
|
#
|
107
237
|
# == Available transformations
|
108
238
|
#
|
239
|
+
# === Creation
|
240
|
+
#
|
241
|
+
# * <tt>create_join_table(table_1, table_2, options)</tt>: Creates a join
|
242
|
+
# table having its name as the lexical order of the first two
|
243
|
+
# arguments. See
|
244
|
+
# ActiveRecord::ConnectionAdapters::SchemaStatements#create_join_table for
|
245
|
+
# details.
|
109
246
|
# * <tt>create_table(name, options)</tt>: Creates a table called +name+ and
|
110
247
|
# makes the table object available to a block that can then add columns to it,
|
111
248
|
# following the same format as +add_column+. See example above. The options hash
|
112
249
|
# is for fragments like "DEFAULT CHARSET=UTF-8" that are appended to the create
|
113
250
|
# 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
251
|
# * <tt>add_column(table_name, column_name, type, options)</tt>: Adds a new column
|
121
252
|
# to the table called +table_name+
|
122
253
|
# named +column_name+ specified to be one of the following types:
|
@@ -127,21 +258,59 @@ module ActiveRecord
|
|
127
258
|
# Other options include <tt>:limit</tt> and <tt>:null</tt> (e.g.
|
128
259
|
# <tt>{ limit: 50, null: false }</tt>) -- see
|
129
260
|
# 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+.
|
261
|
+
# * <tt>add_foreign_key(from_table, to_table, options)</tt>: Adds a new
|
262
|
+
# foreign key. +from_table+ is the table with the key column, +to_table+ contains
|
263
|
+
# the referenced primary key.
|
136
264
|
# * <tt>add_index(table_name, column_names, options)</tt>: Adds a new index
|
137
265
|
# with the name of the column. Other options include
|
138
266
|
# <tt>:name</tt>, <tt>:unique</tt> (e.g.
|
139
267
|
# <tt>{ name: 'users_name_index', unique: true }</tt>) and <tt>:order</tt>
|
140
268
|
# (e.g. <tt>{ order: { name: :desc } }</tt>).
|
141
|
-
# * <tt>
|
142
|
-
#
|
269
|
+
# * <tt>add_reference(:table_name, :reference_name)</tt>: Adds a new column
|
270
|
+
# +reference_name_id+ by default an integer. See
|
271
|
+
# ActiveRecord::ConnectionAdapters::SchemaStatements#add_reference for details.
|
272
|
+
# * <tt>add_timestamps(table_name, options)</tt>: Adds timestamps (+created_at+
|
273
|
+
# and +updated_at+) columns to +table_name+.
|
274
|
+
#
|
275
|
+
# === Modification
|
276
|
+
#
|
277
|
+
# * <tt>change_column(table_name, column_name, type, options)</tt>: Changes
|
278
|
+
# the column to a different type using the same parameters as add_column.
|
279
|
+
# * <tt>change_column_default(table_name, column_name, default)</tt>: Sets a
|
280
|
+
# default value for +column_name+ defined by +default+ on +table_name+.
|
281
|
+
# * <tt>change_column_null(table_name, column_name, null, default = nil)</tt>:
|
282
|
+
# Sets or removes a +NOT NULL+ constraint on +column_name+. The +null+ flag
|
283
|
+
# indicates whether the value can be +NULL+. See
|
284
|
+
# ActiveRecord::ConnectionAdapters::SchemaStatements#change_column_null for
|
285
|
+
# details.
|
286
|
+
# * <tt>change_table(name, options)</tt>: Allows to make column alterations to
|
287
|
+
# the table called +name+. It makes the table object available to a block that
|
288
|
+
# can then add/remove columns, indexes or foreign keys to it.
|
289
|
+
# * <tt>rename_column(table_name, column_name, new_column_name)</tt>: Renames
|
290
|
+
# a column but keeps the type and content.
|
291
|
+
# * <tt>rename_index(table_name, old_name, new_name)</tt>: Renames an index.
|
292
|
+
# * <tt>rename_table(old_name, new_name)</tt>: Renames the table called +old_name+
|
293
|
+
# to +new_name+.
|
294
|
+
#
|
295
|
+
# === Deletion
|
296
|
+
#
|
297
|
+
# * <tt>drop_table(name)</tt>: Drops the table called +name+.
|
298
|
+
# * <tt>drop_join_table(table_1, table_2, options)</tt>: Drops the join table
|
299
|
+
# specified by the given arguments.
|
300
|
+
# * <tt>remove_column(table_name, column_name, type, options)</tt>: Removes the column
|
301
|
+
# named +column_name+ from the table called +table_name+.
|
302
|
+
# * <tt>remove_columns(table_name, *column_names)</tt>: Removes the given
|
303
|
+
# columns from the table definition.
|
304
|
+
# * <tt>remove_foreign_key(from_table, options_or_to_table)</tt>: Removes the
|
305
|
+
# given foreign key from the table called +table_name+.
|
306
|
+
# * <tt>remove_index(table_name, column: column_names)</tt>: Removes the index
|
307
|
+
# specified by +column_names+.
|
143
308
|
# * <tt>remove_index(table_name, name: index_name)</tt>: Removes the index
|
144
309
|
# specified by +index_name+.
|
310
|
+
# * <tt>remove_reference(table_name, ref_name, options)</tt>: Removes the
|
311
|
+
# reference(s) on +table_name+ specified by +ref_name+.
|
312
|
+
# * <tt>remove_timestamps(table_name, options)</tt>: Removes the timestamp
|
313
|
+
# columns (+created_at+ and +updated_at+) from the table definition.
|
145
314
|
#
|
146
315
|
# == Irreversible transformations
|
147
316
|
#
|
@@ -165,24 +334,24 @@ module ActiveRecord
|
|
165
334
|
#
|
166
335
|
# rails generate migration add_fieldname_to_tablename fieldname:string
|
167
336
|
#
|
168
|
-
# This will generate the file <tt>timestamp_add_fieldname_to_tablename</tt>, which will look like this:
|
169
|
-
# class AddFieldnameToTablename < ActiveRecord::Migration
|
337
|
+
# This will generate the file <tt>timestamp_add_fieldname_to_tablename.rb</tt>, which will look like this:
|
338
|
+
# class AddFieldnameToTablename < ActiveRecord::Migration[5.0]
|
170
339
|
# def change
|
171
|
-
# add_column :tablenames, :
|
340
|
+
# add_column :tablenames, :fieldname, :string
|
172
341
|
# end
|
173
342
|
# end
|
174
343
|
#
|
175
344
|
# To run migrations against the currently configured database, use
|
176
|
-
# <tt>
|
345
|
+
# <tt>rails db:migrate</tt>. This will update the database by running all of the
|
177
346
|
# pending migrations, creating the <tt>schema_migrations</tt> table
|
178
347
|
# (see "About the schema_migrations table" section below) if missing. It will also
|
179
348
|
# invoke the db:schema:dump task, which will update your db/schema.rb file
|
180
349
|
# to match the structure of your database.
|
181
350
|
#
|
182
351
|
# To roll the database back to a previous migration version, use
|
183
|
-
# <tt>
|
352
|
+
# <tt>rails db:migrate VERSION=X</tt> where <tt>X</tt> is the version to which
|
184
353
|
# you wish to downgrade. Alternatively, you can also use the STEP option if you
|
185
|
-
# wish to rollback last few migrations. <tt>
|
354
|
+
# wish to rollback last few migrations. <tt>rails db:migrate STEP=2</tt> will rollback
|
186
355
|
# the latest two migrations.
|
187
356
|
#
|
188
357
|
# If any of the migrations throw an <tt>ActiveRecord::IrreversibleMigration</tt> exception,
|
@@ -197,7 +366,7 @@ module ActiveRecord
|
|
197
366
|
#
|
198
367
|
# Not all migrations change the schema. Some just fix the data:
|
199
368
|
#
|
200
|
-
# class RemoveEmptyTags < ActiveRecord::Migration
|
369
|
+
# class RemoveEmptyTags < ActiveRecord::Migration[5.0]
|
201
370
|
# def up
|
202
371
|
# Tag.all.each { |tag| tag.destroy if tag.pages.empty? }
|
203
372
|
# end
|
@@ -210,7 +379,7 @@ module ActiveRecord
|
|
210
379
|
#
|
211
380
|
# Others remove columns when they migrate up instead of down:
|
212
381
|
#
|
213
|
-
# class RemoveUnnecessaryItemAttributes < ActiveRecord::Migration
|
382
|
+
# class RemoveUnnecessaryItemAttributes < ActiveRecord::Migration[5.0]
|
214
383
|
# def up
|
215
384
|
# remove_column :items, :incomplete_items_count
|
216
385
|
# remove_column :items, :completed_items_count
|
@@ -224,7 +393,7 @@ module ActiveRecord
|
|
224
393
|
#
|
225
394
|
# And sometimes you need to do something in SQL not abstracted directly by migrations:
|
226
395
|
#
|
227
|
-
# class MakeJoinUnique < ActiveRecord::Migration
|
396
|
+
# class MakeJoinUnique < ActiveRecord::Migration[5.0]
|
228
397
|
# def up
|
229
398
|
# execute "ALTER TABLE `pages_linked_pages` ADD UNIQUE `page_id_linked_page_id` (`page_id`,`linked_page_id`)"
|
230
399
|
# end
|
@@ -241,7 +410,7 @@ module ActiveRecord
|
|
241
410
|
# <tt>Base#reset_column_information</tt> in order to ensure that the model has the
|
242
411
|
# latest column data from after the new column was added. Example:
|
243
412
|
#
|
244
|
-
# class AddPeopleSalary < ActiveRecord::Migration
|
413
|
+
# class AddPeopleSalary < ActiveRecord::Migration[5.0]
|
245
414
|
# def up
|
246
415
|
# add_column :people, :salary, :integer
|
247
416
|
# Person.reset_column_information
|
@@ -275,21 +444,6 @@ module ActiveRecord
|
|
275
444
|
# The phrase "Updating salaries..." would then be printed, along with the
|
276
445
|
# benchmark for the block when the block completes.
|
277
446
|
#
|
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
447
|
# == Timestamped Migrations
|
294
448
|
#
|
295
449
|
# By default, Rails generates migrations that look like:
|
@@ -307,15 +461,14 @@ module ActiveRecord
|
|
307
461
|
#
|
308
462
|
# == Reversible Migrations
|
309
463
|
#
|
310
|
-
# Starting with Rails 3.1, you will be able to define reversible migrations.
|
311
464
|
# Reversible migrations are migrations that know how to go +down+ for you.
|
312
|
-
# You simply supply the +up+ logic, and the Migration system
|
465
|
+
# You simply supply the +up+ logic, and the Migration system figures out
|
313
466
|
# how to execute the down commands for you.
|
314
467
|
#
|
315
468
|
# To define a reversible migration, define the +change+ method in your
|
316
469
|
# migration like this:
|
317
470
|
#
|
318
|
-
# class TenderloveMigration < ActiveRecord::Migration
|
471
|
+
# class TenderloveMigration < ActiveRecord::Migration[5.0]
|
319
472
|
# def change
|
320
473
|
# create_table(:horses) do |t|
|
321
474
|
# t.column :content, :text
|
@@ -345,7 +498,7 @@ module ActiveRecord
|
|
345
498
|
# can't execute inside a transaction though, and for these situations
|
346
499
|
# you can turn the automatic transactions off.
|
347
500
|
#
|
348
|
-
# class ChangeEnum < ActiveRecord::Migration
|
501
|
+
# class ChangeEnum < ActiveRecord::Migration[5.0]
|
349
502
|
# disable_ddl_transaction!
|
350
503
|
#
|
351
504
|
# def up
|
@@ -357,10 +510,31 @@ module ActiveRecord
|
|
357
510
|
# are in a Migration with <tt>self.disable_ddl_transaction!</tt>.
|
358
511
|
class Migration
|
359
512
|
autoload :CommandRecorder, 'active_record/migration/command_recorder'
|
513
|
+
autoload :Compatibility, 'active_record/migration/compatibility'
|
360
514
|
|
515
|
+
# This must be defined before the inherited hook, below
|
516
|
+
class Current < Migration # :nodoc:
|
517
|
+
end
|
518
|
+
|
519
|
+
def self.inherited(subclass) # :nodoc:
|
520
|
+
super
|
521
|
+
if subclass.superclass == Migration
|
522
|
+
subclass.include Compatibility::Legacy
|
523
|
+
end
|
524
|
+
end
|
525
|
+
|
526
|
+
def self.[](version)
|
527
|
+
Compatibility.find(version)
|
528
|
+
end
|
529
|
+
|
530
|
+
def self.current_version
|
531
|
+
ActiveRecord::VERSION::STRING.to_f
|
532
|
+
end
|
533
|
+
|
534
|
+
MigrationFilenameRegexp = /\A([0-9]+)_([_a-z0-9]*)\.?([_a-z0-9]*)?\.rb\z/ # :nodoc:
|
361
535
|
|
362
536
|
# This class is used to verify that all migrations have been run before
|
363
|
-
# loading a web page if config.active_record.migration_error is set to :page_load
|
537
|
+
# loading a web page if <tt>config.active_record.migration_error</tt> is set to :page_load
|
364
538
|
class CheckPending
|
365
539
|
def initialize(app)
|
366
540
|
@app = app
|
@@ -389,17 +563,22 @@ module ActiveRecord
|
|
389
563
|
attr_accessor :delegate # :nodoc:
|
390
564
|
attr_accessor :disable_ddl_transaction # :nodoc:
|
391
565
|
|
566
|
+
def nearest_delegate # :nodoc:
|
567
|
+
delegate || superclass.nearest_delegate
|
568
|
+
end
|
569
|
+
|
570
|
+
# Raises <tt>ActiveRecord::PendingMigrationError</tt> error if any migrations are pending.
|
392
571
|
def check_pending!(connection = Base.connection)
|
393
572
|
raise ActiveRecord::PendingMigrationError if ActiveRecord::Migrator.needs_migration?(connection)
|
394
573
|
end
|
395
574
|
|
396
575
|
def load_schema_if_pending!
|
397
576
|
if ActiveRecord::Migrator.needs_migration? || !ActiveRecord::Migrator.any_migrations?
|
398
|
-
#
|
577
|
+
# Roundtrip to Rake to allow plugins to hook into database initialization.
|
399
578
|
FileUtils.cd Rails.root do
|
400
579
|
current_config = Base.connection_config
|
401
580
|
Base.clear_all_connections!
|
402
|
-
system("bin/
|
581
|
+
system("bin/rails db:test:prepare")
|
403
582
|
# Establish a new connection, the old database may be gone (db:test:prepare uses purge)
|
404
583
|
Base.establish_connection(current_config)
|
405
584
|
end
|
@@ -414,14 +593,17 @@ module ActiveRecord
|
|
414
593
|
end
|
415
594
|
|
416
595
|
def method_missing(name, *args, &block) # :nodoc:
|
417
|
-
|
596
|
+
nearest_delegate.send(name, *args, &block)
|
418
597
|
end
|
419
598
|
|
420
599
|
def migrate(direction)
|
421
600
|
new.migrate direction
|
422
601
|
end
|
423
602
|
|
424
|
-
# Disable
|
603
|
+
# Disable the transaction wrapping this migration.
|
604
|
+
# You can still create your own transactions even after calling #disable_ddl_transaction!
|
605
|
+
#
|
606
|
+
# For more details read the {"Transactional Migrations" section above}[rdoc-ref:Migration].
|
425
607
|
def disable_ddl_transaction!
|
426
608
|
@disable_ddl_transaction = true
|
427
609
|
end
|
@@ -451,7 +633,7 @@ module ActiveRecord
|
|
451
633
|
# and create the table 'apples' on the way up, and the reverse
|
452
634
|
# on the way down.
|
453
635
|
#
|
454
|
-
# class FixTLMigration < ActiveRecord::Migration
|
636
|
+
# class FixTLMigration < ActiveRecord::Migration[5.0]
|
455
637
|
# def change
|
456
638
|
# revert do
|
457
639
|
# create_table(:horses) do |t|
|
@@ -468,9 +650,9 @@ module ActiveRecord
|
|
468
650
|
# Or equivalently, if +TenderloveMigration+ is defined as in the
|
469
651
|
# documentation for Migration:
|
470
652
|
#
|
471
|
-
# require_relative '
|
653
|
+
# require_relative '20121212123456_tenderlove_migration'
|
472
654
|
#
|
473
|
-
# class FixupTLMigration < ActiveRecord::Migration
|
655
|
+
# class FixupTLMigration < ActiveRecord::Migration[5.0]
|
474
656
|
# def change
|
475
657
|
# revert TenderloveMigration
|
476
658
|
#
|
@@ -484,13 +666,13 @@ module ActiveRecord
|
|
484
666
|
def revert(*migration_classes)
|
485
667
|
run(*migration_classes.reverse, revert: true) unless migration_classes.empty?
|
486
668
|
if block_given?
|
487
|
-
if
|
488
|
-
|
669
|
+
if connection.respond_to? :revert
|
670
|
+
connection.revert { yield }
|
489
671
|
else
|
490
|
-
recorder = CommandRecorder.new(
|
672
|
+
recorder = CommandRecorder.new(connection)
|
491
673
|
@connection = recorder
|
492
674
|
suppress_messages do
|
493
|
-
|
675
|
+
connection.revert { yield }
|
494
676
|
end
|
495
677
|
@connection = recorder.delegate
|
496
678
|
recorder.commands.each do |cmd, args, block|
|
@@ -501,7 +683,7 @@ module ActiveRecord
|
|
501
683
|
end
|
502
684
|
|
503
685
|
def reverting?
|
504
|
-
|
686
|
+
connection.respond_to?(:reverting) && connection.reverting
|
505
687
|
end
|
506
688
|
|
507
689
|
class ReversibleBlockHelper < Struct.new(:reverting) # :nodoc:
|
@@ -523,7 +705,7 @@ module ActiveRecord
|
|
523
705
|
# when the three columns 'first_name', 'last_name' and 'full_name' exist,
|
524
706
|
# even when migrating down:
|
525
707
|
#
|
526
|
-
# class SplitNameMigration < ActiveRecord::Migration
|
708
|
+
# class SplitNameMigration < ActiveRecord::Migration[5.0]
|
527
709
|
# def change
|
528
710
|
# add_column :users, :first_name, :string
|
529
711
|
# add_column :users, :last_name, :string
|
@@ -558,7 +740,7 @@ module ActiveRecord
|
|
558
740
|
revert { run(*migration_classes, direction: dir, revert: true) }
|
559
741
|
else
|
560
742
|
migration_classes.each do |migration_class|
|
561
|
-
migration_class.new.exec_migration(
|
743
|
+
migration_class.new.exec_migration(connection, dir)
|
562
744
|
end
|
563
745
|
end
|
564
746
|
end
|
@@ -647,13 +829,14 @@ module ActiveRecord
|
|
647
829
|
end
|
648
830
|
|
649
831
|
def method_missing(method, *arguments, &block)
|
650
|
-
arg_list = arguments.map
|
832
|
+
arg_list = arguments.map(&:inspect) * ', '
|
651
833
|
|
652
834
|
say_with_time "#{method}(#{arg_list})" do
|
653
|
-
unless
|
835
|
+
unless connection.respond_to? :revert
|
654
836
|
unless arguments.empty? || [:execute, :enable_extension, :disable_extension].include?(method)
|
655
837
|
arguments[0] = proper_table_name(arguments.first, table_name_options)
|
656
|
-
if [:rename_table, :add_foreign_key].include?(method)
|
838
|
+
if [:rename_table, :add_foreign_key].include?(method) ||
|
839
|
+
(method == :remove_foreign_key && !arguments.second.is_a?(Hash))
|
657
840
|
arguments[1] = proper_table_name(arguments.second, table_name_options)
|
658
841
|
end
|
659
842
|
end
|
@@ -728,7 +911,9 @@ module ActiveRecord
|
|
728
911
|
end
|
729
912
|
end
|
730
913
|
|
731
|
-
|
914
|
+
# Builds a hash for use in ActiveRecord::Migration#proper_table_name using
|
915
|
+
# the Active Record object's table_name prefix and suffix
|
916
|
+
def table_name_options(config = ActiveRecord::Base) #:nodoc:
|
732
917
|
{
|
733
918
|
table_name_prefix: config.table_name_prefix,
|
734
919
|
table_name_suffix: config.table_name_suffix
|
@@ -820,7 +1005,7 @@ module ActiveRecord
|
|
820
1005
|
new(:up, migrations, target_version).migrate
|
821
1006
|
end
|
822
1007
|
|
823
|
-
def down(migrations_paths, target_version = nil
|
1008
|
+
def down(migrations_paths, target_version = nil)
|
824
1009
|
migrations = migrations(migrations_paths)
|
825
1010
|
migrations.select! { |m| yield m } if block_given?
|
826
1011
|
|
@@ -840,10 +1025,12 @@ module ActiveRecord
|
|
840
1025
|
end
|
841
1026
|
|
842
1027
|
def get_all_versions(connection = Base.connection)
|
843
|
-
|
844
|
-
|
845
|
-
|
846
|
-
|
1028
|
+
ActiveSupport::Deprecation.silence do
|
1029
|
+
if connection.table_exists?(schema_migrations_table_name)
|
1030
|
+
SchemaMigration.all.map { |x| x.version.to_i }.sort
|
1031
|
+
else
|
1032
|
+
[]
|
1033
|
+
end
|
847
1034
|
end
|
848
1035
|
end
|
849
1036
|
|
@@ -859,22 +1046,22 @@ module ActiveRecord
|
|
859
1046
|
migrations(migrations_paths).any?
|
860
1047
|
end
|
861
1048
|
|
862
|
-
def last_version
|
863
|
-
last_migration.version
|
864
|
-
end
|
865
|
-
|
866
1049
|
def last_migration #:nodoc:
|
867
1050
|
migrations(migrations_paths).last || NullMigration.new
|
868
1051
|
end
|
869
1052
|
|
870
1053
|
def migrations_paths
|
871
1054
|
@migrations_paths ||= ['db/migrate']
|
872
|
-
# just to not break things if someone uses:
|
1055
|
+
# just to not break things if someone uses: migrations_path = some_string
|
873
1056
|
Array(@migrations_paths)
|
874
1057
|
end
|
875
1058
|
|
876
|
-
def
|
877
|
-
|
1059
|
+
def match_to_migration_filename?(filename) # :nodoc:
|
1060
|
+
File.basename(filename) =~ Migration::MigrationFilenameRegexp
|
1061
|
+
end
|
1062
|
+
|
1063
|
+
def parse_migration_filename(filename) # :nodoc:
|
1064
|
+
File.basename(filename).scan(Migration::MigrationFilenameRegexp).first
|
878
1065
|
end
|
879
1066
|
|
880
1067
|
def migrations(paths)
|
@@ -883,8 +1070,7 @@ module ActiveRecord
|
|
883
1070
|
files = Dir[*paths.map { |p| "#{p}/**/[0-9]*_*.rb" }]
|
884
1071
|
|
885
1072
|
migrations = files.map do |file|
|
886
|
-
version, name, scope = file
|
887
|
-
|
1073
|
+
version, name, scope = parse_migration_filename(file)
|
888
1074
|
raise IllegalMigrationNameError.new(file) unless version
|
889
1075
|
version = version.to_i
|
890
1076
|
name = name.camelize
|
@@ -920,6 +1106,7 @@ module ActiveRecord
|
|
920
1106
|
validate(@migrations)
|
921
1107
|
|
922
1108
|
Base.connection.initialize_schema_migrations_table
|
1109
|
+
Base.connection.initialize_internal_metadata_table
|
923
1110
|
end
|
924
1111
|
|
925
1112
|
def current_version
|
@@ -932,32 +1119,18 @@ module ActiveRecord
|
|
932
1119
|
alias :current :current_migration
|
933
1120
|
|
934
1121
|
def run
|
935
|
-
|
936
|
-
|
937
|
-
|
938
|
-
|
939
|
-
execute_migration_in_transaction(migration, @direction)
|
940
|
-
rescue => e
|
941
|
-
canceled_msg = use_transaction?(migration) ? ", this migration was canceled" : ""
|
942
|
-
raise StandardError, "An error has occurred#{canceled_msg}:\n\n#{e}", e.backtrace
|
943
|
-
end
|
1122
|
+
if use_advisory_lock?
|
1123
|
+
with_advisory_lock { run_without_lock }
|
1124
|
+
else
|
1125
|
+
run_without_lock
|
944
1126
|
end
|
945
1127
|
end
|
946
1128
|
|
947
1129
|
def migrate
|
948
|
-
if
|
949
|
-
|
950
|
-
|
951
|
-
|
952
|
-
runnable.each do |migration|
|
953
|
-
Base.logger.info "Migrating to #{migration.name} (#{migration.version})" if Base.logger
|
954
|
-
|
955
|
-
begin
|
956
|
-
execute_migration_in_transaction(migration, @direction)
|
957
|
-
rescue => e
|
958
|
-
canceled_msg = use_transaction?(migration) ? "this and " : ""
|
959
|
-
raise StandardError, "An error has occurred, #{canceled_msg}all later migrations canceled:\n\n#{e}", e.backtrace
|
960
|
-
end
|
1130
|
+
if use_advisory_lock?
|
1131
|
+
with_advisory_lock { migrate_without_lock }
|
1132
|
+
else
|
1133
|
+
migrate_without_lock
|
961
1134
|
end
|
962
1135
|
end
|
963
1136
|
|
@@ -982,19 +1155,67 @@ module ActiveRecord
|
|
982
1155
|
end
|
983
1156
|
|
984
1157
|
def migrated
|
985
|
-
@migrated_versions
|
1158
|
+
@migrated_versions || load_migrated
|
1159
|
+
end
|
1160
|
+
|
1161
|
+
def load_migrated
|
1162
|
+
@migrated_versions = Set.new(self.class.get_all_versions)
|
986
1163
|
end
|
987
1164
|
|
988
1165
|
private
|
1166
|
+
|
1167
|
+
# Used for running a specific migration.
|
1168
|
+
def run_without_lock
|
1169
|
+
migration = migrations.detect { |m| m.version == @target_version }
|
1170
|
+
raise UnknownMigrationVersionError.new(@target_version) if migration.nil?
|
1171
|
+
execute_migration_in_transaction(migration, @direction)
|
1172
|
+
|
1173
|
+
record_environment
|
1174
|
+
end
|
1175
|
+
|
1176
|
+
# Used for running multiple migrations up to or down to a certain value.
|
1177
|
+
def migrate_without_lock
|
1178
|
+
if invalid_target?
|
1179
|
+
raise UnknownMigrationVersionError.new(@target_version)
|
1180
|
+
end
|
1181
|
+
|
1182
|
+
runnable.each do |migration|
|
1183
|
+
execute_migration_in_transaction(migration, @direction)
|
1184
|
+
end
|
1185
|
+
|
1186
|
+
record_environment
|
1187
|
+
end
|
1188
|
+
|
1189
|
+
# Stores the current environment in the database.
|
1190
|
+
def record_environment
|
1191
|
+
return if down?
|
1192
|
+
ActiveRecord::InternalMetadata[:environment] = ActiveRecord::Migrator.current_environment
|
1193
|
+
end
|
1194
|
+
|
989
1195
|
def ran?(migration)
|
990
1196
|
migrated.include?(migration.version.to_i)
|
991
1197
|
end
|
992
1198
|
|
1199
|
+
# Return true if a valid version is not provided.
|
1200
|
+
def invalid_target?
|
1201
|
+
!target && @target_version && @target_version > 0
|
1202
|
+
end
|
1203
|
+
|
993
1204
|
def execute_migration_in_transaction(migration, direction)
|
1205
|
+
return if down? && !migrated.include?(migration.version.to_i)
|
1206
|
+
return if up? && migrated.include?(migration.version.to_i)
|
1207
|
+
|
1208
|
+
Base.logger.info "Migrating to #{migration.name} (#{migration.version})" if Base.logger
|
1209
|
+
|
994
1210
|
ddl_transaction(migration) do
|
995
1211
|
migration.migrate(direction)
|
996
1212
|
record_version_state_after_migrating(migration.version)
|
997
1213
|
end
|
1214
|
+
rescue => e
|
1215
|
+
msg = "An error has occurred, "
|
1216
|
+
msg << "this and " if use_transaction?(migration)
|
1217
|
+
msg << "all later migrations canceled:\n\n#{e}"
|
1218
|
+
raise StandardError, msg, e.backtrace
|
998
1219
|
end
|
999
1220
|
|
1000
1221
|
def target
|
@@ -1023,10 +1244,27 @@ module ActiveRecord
|
|
1023
1244
|
ActiveRecord::SchemaMigration.where(:version => version.to_s).delete_all
|
1024
1245
|
else
|
1025
1246
|
migrated << version
|
1026
|
-
ActiveRecord::SchemaMigration.create!(:
|
1247
|
+
ActiveRecord::SchemaMigration.create!(version: version.to_s)
|
1027
1248
|
end
|
1028
1249
|
end
|
1029
1250
|
|
1251
|
+
def self.last_stored_environment
|
1252
|
+
return nil if current_version == 0
|
1253
|
+
raise NoEnvironmentInSchemaError unless ActiveRecord::InternalMetadata.table_exists?
|
1254
|
+
|
1255
|
+
environment = ActiveRecord::InternalMetadata[:environment]
|
1256
|
+
raise NoEnvironmentInSchemaError unless environment
|
1257
|
+
environment
|
1258
|
+
end
|
1259
|
+
|
1260
|
+
def self.current_environment
|
1261
|
+
ActiveRecord::ConnectionHandling::DEFAULT_ENV.call
|
1262
|
+
end
|
1263
|
+
|
1264
|
+
def self.protected_environment?
|
1265
|
+
ActiveRecord::Base.protected_environments.include?(last_stored_environment) if last_stored_environment
|
1266
|
+
end
|
1267
|
+
|
1030
1268
|
def up?
|
1031
1269
|
@direction == :up
|
1032
1270
|
end
|
@@ -1047,5 +1285,25 @@ module ActiveRecord
|
|
1047
1285
|
def use_transaction?(migration)
|
1048
1286
|
!migration.disable_ddl_transaction && Base.connection.supports_ddl_transactions?
|
1049
1287
|
end
|
1288
|
+
|
1289
|
+
def use_advisory_lock?
|
1290
|
+
Base.connection.supports_advisory_locks?
|
1291
|
+
end
|
1292
|
+
|
1293
|
+
def with_advisory_lock
|
1294
|
+
lock_id = generate_migrator_advisory_lock_id
|
1295
|
+
got_lock = Base.connection.get_advisory_lock(lock_id)
|
1296
|
+
raise ConcurrentMigrationError unless got_lock
|
1297
|
+
load_migrated # reload schema_migrations to be sure it wasn't changed by another process before we got the lock
|
1298
|
+
yield
|
1299
|
+
ensure
|
1300
|
+
Base.connection.release_advisory_lock(lock_id) if got_lock
|
1301
|
+
end
|
1302
|
+
|
1303
|
+
MIGRATOR_SALT = 2053462845
|
1304
|
+
def generate_migrator_advisory_lock_id
|
1305
|
+
db_name_hash = Zlib.crc32(Base.connection.current_database)
|
1306
|
+
MIGRATOR_SALT * db_name_hash
|
1307
|
+
end
|
1050
1308
|
end
|
1051
1309
|
end
|