aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--activerecord/CHANGELOG.md5
-rw-r--r--activerecord/lib/active_record/migration.rb18
-rw-r--r--activerecord/test/cases/invertible_migration_test.rb25
3 files changed, 48 insertions, 0 deletions
diff --git a/activerecord/CHANGELOG.md b/activerecord/CHANGELOG.md
index 57ec37c75b..2088b018d7 100644
--- a/activerecord/CHANGELOG.md
+++ b/activerecord/CHANGELOG.md
@@ -1,3 +1,8 @@
+* Add `#only_up` to database migrations for code that is only relevant when
+ migrating up, e.g. populating a new column.
+
+ *Rich Daley*
+
* Require raw SQL fragments to be explicitly marked when used in
relation query methods.
diff --git a/activerecord/lib/active_record/migration.rb b/activerecord/lib/active_record/migration.rb
index c13efa9d70..67c8c9fc08 100644
--- a/activerecord/lib/active_record/migration.rb
+++ b/activerecord/lib/active_record/migration.rb
@@ -734,6 +734,24 @@ module ActiveRecord
execute_block { yield helper }
end
+ # Used to specify an operation that is only run when migrating up
+ # (for example, populating a new column with its initial values).
+ #
+ # In the following example, the new column `published` will be given
+ # the value `true` for all existing records.
+ #
+ # class AddPublishedToPosts < ActiveRecord::Migration[5.3]
+ # def change
+ # add_column :posts, :published, :boolean, default: false
+ # up_only do
+ # execute "update posts set published = 'true'"
+ # end
+ # end
+ # end
+ def up_only
+ execute_block { yield } unless reverting?
+ end
+
# Runs the given migration classes.
# Last argument can specify options:
# - :direction (default is :up)
diff --git a/activerecord/test/cases/invertible_migration_test.rb b/activerecord/test/cases/invertible_migration_test.rb
index 60c628511f..e0f40710eb 100644
--- a/activerecord/test/cases/invertible_migration_test.rb
+++ b/activerecord/test/cases/invertible_migration_test.rb
@@ -161,6 +161,13 @@ module ActiveRecord
end
end
+ class UpOnlyMigration < SilentMigration
+ def change
+ add_column :horses, :oldie, :boolean, default: false
+ up_only { execute "update horses set oldie = 'true'" }
+ end
+ end
+
setup do
@verbose_was, ActiveRecord::Migration.verbose = ActiveRecord::Migration.verbose, false
end
@@ -378,5 +385,23 @@ module ActiveRecord
"horses_index_named index should not exist"
end
end
+
+ def test_up_only
+ InvertibleMigration.new.migrate(:up)
+ horse1 = Horse.create
+ # populates existing horses with oldie=true but new ones have default false
+ UpOnlyMigration.new.migrate(:up)
+ Horse.reset_column_information
+ horse1.reload
+ horse2 = Horse.create
+
+ assert horse1.oldie? # created before migration
+ assert !horse2.oldie? # created after migration
+
+ UpOnlyMigration.new.migrate(:down) # should be no error
+ connection = ActiveRecord::Base.connection
+ assert !connection.column_exists?(:horses, :oldie)
+ Horse.reset_column_information
+ end
end
end