Harry's Data Migrations are a way to manage changes to seed data in a rails app in a similar way to how schema migrations are handled.
A data migration library, similar to rails built-in schema migration. It also auto generates a db/seeds.rb
file, similar to how schema migrations generate the db/schema.rb
file.
Using this auto generated seed file makes it quick and easy to setup new environments, usually development or test.
Add gem 'seed_migration'
to your Gemfile
:
gem 'seed_migration'
rake seed_migration:install:migrations
rake db:migrate
That will create the table to keep track of data migrations.
You can use the generator :
rails g seed_migration AddFoo
A new file will be created under db/data/
using rails migration convention:
db/data/20140407162007_add_foo.rb
You'll need to implement the #up
method and if you need to be able to rollback, the #down
method.
To run all pending migrations, simply use
rake seed:migrate
If needed, you can run a specific migration:
rake seed:migrate MIGRATION=20140407162007_add_foo.rb
Rolling back the last migration is as simple as:
rake seed:rollback
You can rollback more than one migration at the same time:
rake seed:rollback STEP=3 # rollback last 3 migrations
Or rollback a specific migration:
rake seed:rollback MIGRATION=20140407162007_add_foo.rb
See the status of your migrations:
rake seed:migrate:status
Example output:
database: seed-migrationdevelopment
Status Migration ID Migration Name
--------------------------------------------------
up 20160114153832 Add users
down 20160114153843 Add more users
down 20160114153851 Add even more users
By default no models are registered, so running seed migrations won't update the seeds file. You have to manually register the models in the configuration file.
Simply register a model:
SeedMigration.register Product
You can customize the 'seeded' attribute list:
SeedMigration.register User do
exclude :id, :password
end
This will create a seeds.rb
containing all User and Product in the database:
# encoding: UTF-8
# This file is auto-generated from the current content of the database. Instead
# of editing this file, please use the migrations feature of Seed Migration to
# incrementally modify your database, and then regenerate this seed file.
#
# If you need to create the database on another system, you should be using
# db:seed, not running all the migrations from scratch. The latter is a flawed
# and unsustainable approach (the more migrations you'll amass, the slower
# it'll run and the greater likelihood for issues).
#
# It's strongly recommended to check this file into your version control system.
ActiveRecord::Base.transaction do
Product.create("created_at"=>"2014-04-04T15:42:24Z", "id"=>1, "name"=>"foo", "updated_at"=>"2014-04-04T15:42:24Z")
Product.create("created_at"=>"2014-04-04T15:42:24Z", "id"=>2, "name"=>"bar", "updated_at"=>"2014-04-04T15:42:24Z")
# ...
User.create("created_at"=>"2014-04-04T15:42:24Z", "id"=>1, "name"=>"admin", "updated_at"=>"2014-04-04T15:42:24Z")
# ...
end
SeedMigration::Migrator.bootstrap(20140404193326)
Note that seeds.rb
is only generated in development mode. Production data will not be dumped in this process.
Check for pending data migrations:
SeedMigration::Migrator.check_pending!
If there are pending migrations, this will raise
SeedMigration::Migrator::PendingMigrationError
.
If your app already contains seeds, using this gem could cause some issues. Here is the basic process to follow to ensure a smooth transition:
- Clean your local database, and seed it, that can be done with
rake db:reset
- register all the models that were created in the original seeds file
- run
rake seed:migrate
- At this point, your seeds file will be rewritten with all the
create
statements - Commit/Push the updated seeds file
It is recommended to add the rake seed:migrate
to your deploy script, so each new data migrations is ran upon new deploys.
You can enable the extend_native_migration_task
option to automatically run rake seed:migrate
after rake db:migrate
.
For Capistrano 3.x support, add this to your Capfile
require 'capistrano/seed_migration_tasks'
which provides the two cap tasks, which you can add to your deploy script or run on the command line:
cap {stage} seed:migrate
cap {stage} seed:rollback
rails g seed_migration AddADummyProduct
class AddADummyProduct < SeedMigration::Migration
def up
Product.create!({
:asset_path => "valentines-day.jpg",
:title => "Valentine's Day II: the revenge!",
:active => false,
:default => false,
}, :without_protection => true)
end
def down
Product.destroy_all(:title => "Valentine's Day II: the revenge!")
end
end
Use an initializer file for configuration.
extend_native_migration_task (default=false)
ignore_ids (default=false)
migration_table_name (default='seed_migration_data_migrations')
: Override the table name for the internal model that holds the migrationsuse_strict_create (default=false)
: Usecreate!
instead ofcreate
indb/seeds.rb
when set to true
# config/initializers/seed_migration.rb
SeedMigration.config do |c|
c.migration_table_name = 'data_migrations'
c.extend_native_migration_task = true
end
SeedMigration.register User do
exclude :id, :password
end
SeedMigration.register Product
At the moment, we rely by default on
ActiveRecord::Base.connection.reset_pk_sequence!
which is pg
only.
If you need to use this gem with another database, use the ignore_ids
configuration.
RAILS_ENV=test bundle exec rake app:db:reset
bundle exec rspec spec
- Fork it
- Create your feature branch (
git checkout -b my-new-feature
) - Commit your changes (
git commit -am 'Add some feature'
) - Push to the branch (
git push origin my-new-feature
) - Create new Pull Request