Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Rails plugin to run migrations on startup?

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.

like image 417
Don Werve Avatar asked Sep 19 '25 00:09

Don Werve


1 Answers

Using config.after_initialize works, but there are two problems:

  1. it runs after all other initializers, so if those initializers do some databasey stuff they'd be using the old schema

  2. 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?
like image 105
AlexChaffee Avatar answered Sep 20 '25 12:09

AlexChaffee