Reputation: 5120
Is there a plugin available to have Rails run through a db:migrate on startup? I'm looking for a solution that doesn't involve calling out to the Rake task via the shell; so, no "system('rake db:migrate')
".
I can readily write my own plugin to do this, but figured it would be better to use/improve an existing migrate-on-init plugin if one exists.
Upvotes: 4
Views: 4340
Reputation: 8252
Using config.after_initialize
works, but there are two problems:
it runs after all other initializers, so if those initializers do some databasey stuff they'd be using the old schema
it runs in all environments, including Rake tasks and Resque workers. We don't want to automatically migrate every time we run rake routes
, do we? And we don't want multiple migrations to happen simultaneously.
My solution is to use a config/initializers
file, so I can decide what order it runs in, and to check for whether we're inside a rake task.
Also, until I'm comfortable with auto-migrate on deploy, I'm only doing this in the development
and test
environments.
Finally, I want to print some extra information (migrating to and from version), so instead of a one-liner, I reach into the Migrator, perhaps more intimately than I should.
Oh yeah! Also it should write schema.rb
. So I'm blatantly stealing code from db:schema:dump
from inside active_record/railties/databases.rake
. (Wouldn't it be nice if rake tasks were methods on an object, so we could just call them?)
config/initializers/automatically_migrate.rb
:
# don't do this in production
if (Rails.env.development? or Rails.env.test?) and
# don't do this in a worker or task
!defined?(Rake) # SEE BELOW FOR POSSIBLE FIX
migrations_paths = ActiveRecord::Migrator.migrations_paths
migrator = ActiveRecord::Migrator.new(:up, migrations_paths, nil)
pending_migrations = migrator.pending_migrations
unless pending_migrations.empty?
puts "Migrating from #{migrator.current_version} to #{pending_migrations.last.version}"
migrator.migrate
require 'active_record/schema_dumper'
filename = ENV['SCHEMA'] || "#{Rails.root}/db/schema.rb"
File.open(filename, "w:utf-8") do |file|
ActiveRecord::Base.establish_connection(Rails.env)
ActiveRecord::SchemaDumper.dump(ActiveRecord::Base.connection, file)
end
end
end
Update: Apparently the new version of Rake is more liberal about when it loads, so the expression !defined?(Rake)
is always false, even when being run from the command line (i.e. not inside a Rake Task or a Resque Worker). I'm trying the following instead
caller.grep(/rake/).empty?
Upvotes: 4
Reputation: 8820
Here is my working version for Rails 3.2 on jRuby:
config.after_initialize do
ActiveRecord::Migrator.migrate(Rails.root.join("db/migrate"), nil)
end
Upvotes: 3
Reputation: 846
Sam's Answer did not quite work for me. I'm using Rails 3.0, I think you might need to add this inside of application.rb, anywhere inside the class.
config.after_initialize do
ActiveRecord::Migrator.migrate (RAILS_ROOT + "/db/migrate" )
end
On a similar note, I'm using JRuby and Deploying as a War, I wonder why this is not creating the tables for me, instead it complains that table such&such does not exist.
Upvotes: 1
Reputation:
Put the following inside Rails::Initializer block in environment.rb ...
config.after_initialize do ActiveRecord::Migrator.migrate (RAILS_ROOT + "/db/migrate" ) end
Upvotes: 2
Reputation: 1541
In my experience, db:migrate-like routine should only be called when new migrations are present, because it takes quite a bit of time. You shouldn't really have so many migrations that you can't track when they are present.
That said, the task of running new migration in production environment is best handled by deployment tools like Capistrano. when deploying to production box, capistrano runs migrations if you tell it too.
Running db:migrate-like routine upon every-init is resource and time wastful.
Upvotes: -3