Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 25 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,31 @@ rake data:migrate

This will run all pending data migrations and store migration history in `data_migrations` table. You're all set.

If you need to generate migrations that can be run separately from data_migrations you can create Pre Migrations

To create a pre data migration you need to run:
```
rails generate pre_data_migration migration_name
```

and this will create a `pre_migration_name.rb` file in `db/data_migrations` folder with a following content:
```ruby
class PreMigrationName < DataMigration
def up
# put your code here
end
end
```

so all we need to do is to put some ruby code inside the `up` method.

Finally, at the release time, you need to run
```
rake data:migrate:pre
```

This will run all pending pre data migrations and store migration history in `data_migrations` table. You're all set.

## Rails Support

Rails 4.0 and higher
Expand Down
14 changes: 14 additions & 0 deletions lib/generators/pre_data_migration_generator.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
require 'rails/generators'
require 'rails-data-migrations'

class PreDataMigrationGenerator < Rails::Generators::NamedBase
source_root File.expand_path('../templates', __FILE__)

def create_migration_file
migration_file_name =
"#{RailsDataMigrations::Migrator.migrations_path}/#{Time.now.utc.strftime('%Y%m%d%H%M%S')}_pre_#{file_name}.rb"
copy_file 'data_migration_generator.rb', migration_file_name do |content|
content.sub(/ClassName/, "Pre#{file_name.camelize}")
end
end
end
17 changes: 15 additions & 2 deletions lib/rails_data_migrations/migrator.rb
Original file line number Diff line number Diff line change
Expand Up @@ -53,9 +53,22 @@ def list_migrations
def list_pending_migrations
if rails_5_2?
already_migrated = get_all_versions
list_migrations.reject { |m| already_migrated.include?(m.version) }
list_migrations
.reject { |m| already_migrated.include?(m.version) }
.reject { |m| m.filename.match(/\d{14}_pre_/) }
else
open(migrations_path).pending_migrations
open(migrations_path).pending_migrations.reject { |m| m.filename.match(/\d{14}_pre_/) }
end
end

def list_pending_pre_migrations
if rails_5_2?
already_migrated = get_all_versions
list_migrations
.reject { |m| already_migrated.include?(m.version) }
.select { |m| m.filename.match(/\d{14}_pre_/) }
else
open(migrations_path).pending_migrations.select { |m| m.filename.match(/\d{14}_pre_/) }
end
end

Expand Down
7 changes: 7 additions & 0 deletions lib/tasks/data_migrations.rake
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,13 @@ namespace :data do
apply_single_migration(:up, ENV['VERSION'])
end

desc 'Apply pre data migrations'
task pre: :init_migration do
RailsDataMigrations::Migrator.list_pending_pre_migrations.sort_by(&:version).each do |m|
apply_single_migration(:up, m.version)
end
end

desc 'Revert single data migration using VERSION'
task down: :init_migration do
apply_single_migration(:down, ENV['VERSION'])
Expand Down
74 changes: 57 additions & 17 deletions spec/data_migrations_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -14,33 +14,62 @@
context 'generator' do
let(:migration_name) { 'test_migration' }

let(:file_name) { 'spec/db/data-migrations/20161031000000_test_migration.rb' }
context 'regular migration' do
let(:file_name) { 'spec/db/data-migrations/20161031000000_test_migration.rb' }

before(:each) do
allow(Time).to receive(:now).and_return(Time.utc(2016, 10, 31))
Rails::Generators.invoke('data_migration', [migration_name])
end
before(:each) do
allow(Time).to receive(:now).and_return(Time.utc(2016, 10, 31))
Rails::Generators.invoke('data_migration', [migration_name])
end

it 'creates non-empty migration file' do
expect(File.exist?(file_name)).to be_truthy
expect(File.size(file_name)).to be > 0
end

it 'creates non-empty migration file' do
expect(File.exist?(file_name)).to be_truthy
expect(File.size(file_name)).to be > 0
it 'creates valid migration class' do
# rubocop:disable Security/Eval
eval(File.open(file_name).read)
# rubocop:enable Security/Eval
klass = migration_name.classify.constantize
expect(klass.superclass).to eq(ActiveRecord::DataMigration)
expect(klass.instance_methods(false)).to eq([:up])
end
end

it 'creates valid migration class' do
# rubocop:disable Security/Eval
eval(File.open(file_name).read)
# rubocop:enable Security/Eval
klass = migration_name.classify.constantize
expect(klass.superclass).to eq(ActiveRecord::DataMigration)
expect(klass.instance_methods(false)).to eq([:up])
context 'pre migration' do
let(:file_name) { 'spec/db/data-migrations/20190131000000_pre_test_migration.rb' }

before(:each) do
allow(Time).to receive(:now).and_return(Time.utc(2019, 1, 31))
Rails::Generators.invoke('pre_data_migration', [migration_name])
end

it 'creates non-empty pre migration file' do
expect(File.exist?(file_name)).to be_truthy
expect(File.size(file_name)).to be > 0
end

it 'creates valid pre migration class' do
# rubocop:disable Security/Eval
eval(File.open(file_name).read)
# rubocop:enable Security/Eval
klass = "pre_#{migration_name}".classify.constantize
expect(klass.superclass).to eq(ActiveRecord::DataMigration)
expect(klass.instance_methods(false)).to eq([:up])
end
end
end

context 'migrator' do
before(:each) do
allow(Time).to receive(:now).and_return(Time.utc(2016, 11, 1, 2, 3, 4))
allow(Time).to receive(:now).and_return(
Time.utc(2016, 11, 1, 2, 3, 4),
Time.utc(2019, 1, 1, 2, 3, 14)
)

Rails::Generators.invoke('data_migration', ['test'])
Rails::Generators.invoke('pre_data_migration', ['test'])
end

def load_rake_rasks
Expand All @@ -54,7 +83,7 @@ def load_rake_rasks
end

it 'list migration file' do
expect(RailsDataMigrations::Migrator.list_migrations.size).to eq(1)
expect(RailsDataMigrations::Migrator.list_migrations.size).to eq(2)
end

it 'applies pending migrations only once' do
Expand All @@ -69,6 +98,17 @@ def load_rake_rasks
end
end

it 'applies pending pre migrations' do
expect(RailsDataMigrations::LogEntry.count).to eq(0)

load_rake_rasks

Rake::Task['data:migrate:pre'].execute

expect(RailsDataMigrations::Migrator.current_version).to eq(20190101020314)
expect(RailsDataMigrations::LogEntry.count).to eq(1)
end

it 'requires VERSION to run a single migration' do
ENV['VERSION'] = nil

Expand Down