There is a confession in this. The confession that we, while in development crunch mode, do not use migrations. We use them when our apps go to production, but the last project would have had over 200 migrations by the time it went live. A development DB is a volatile thing, especially when features are constantly being changed and added. “Yet,” you say, “this is the very problem migrations were created to solve.”
Let me propose another solution: rake remigrate. We keep our initial migration under version control. When a change is made, we svn up and run rake remigrate. This task deletes and recreates our development database, runs the initial migration, then loads our fixtures. When we take our app live we begin creating new migrations, as the schema has been solidified.
This method is advantageous if two people are working on a new migration at the same time. Version control is designed for this situation and new files don’t have to be added with the potential for conflict. It also ensures the entire development team always has the proper fixtures loaded. Plus, who wants to constantly write alter table when you can just change the schema definition?
Without further adieu, enjoy rake remigrate:
desc "Drop then recreate the dev database, migrate up, and load fixtures" task :remigrate => :environment do return unless %w[development test staging].include? RAILS_ENV ActiveRecord::Base.connection.tables.each { |t| ActiveRecord::Base.connection.drop_table t } Rake::Task[:migrate].invoke Rake::Task["db:fixtures:load"].invoke end
Just stick it in rails_root/lib/tasks (named something like remigrate.rake) and you’re ready to remigrate.
Update: As topfunky points out, this is currently MySQL-only. The Postgres adapter doesn’t have the needed recreated_database (or any database create / drop) methods.
Update 2: Thanks to erik’s critical thinking prowess we now have a database agnostic rake remigrate. Three cheers!
I don’t get it. Does this come with a javascript rollover?
Very useful! I was doing this another way, but this will work much better.
Hmm…appears to be MySQL-only. The Postgres adapter doesn’t have the recreate_database method.
Doh, thanks for checking it out topfunky. A warning has been issued.
replacing:
ActiveRecord::Base.connection.recreate_database ActiveRecord::Base.connection.current_database
with:
ActiveRecord::Base.connection.tables.each do |t| ActiveRecord::Base.connection.drop_table t; end
seems to work with sqlite, maybe even in the general case?
I love the utility of this task but I am having some problem preventing me from using it. I have some records that are created as part of my migration (i.e. not fixtures). About 20 of them. When I run this task two records get created both completely empty. I tried separating the task into two tasks (one to clear the other to migrate and load fixtures) but that didn’t seem to help either. Not sure the reason but I would love to know why.
Thanks for the task anyway. Maybe when my rails skills get better I can figure out why.
Nevermind my last comment. Forgot that fixtures will wipe out data in the tables including data that was in the migration.
Since we’re using FK constraints we can’t just go dropping tables in any old order. Instead this is the uglified solution we’re using, with some production protection baked in.
You might want to look at:
http://svn.integrumtech.com/public/plugins/rake_tasks/
It has a nice rake db:reset rake command which drops, creates and then migrates the database for your current RAILS_ENV
Whats with the second case ?
Chime in.