3

I have appended a my_checks method call to the rails db:migrate invocation. The code below works great as long as db:migrate does not throw an exception. However, if db:migrate does throw an exception, the my_checks method won't be executed.

Is there a way I can rewrite the code below to ensure that my_checks gets executed no matter what happens in db:migrate?

namespace :db do
  def my_checks
    ...
  end

  task :migrate do
    my_checks
  end
end
Reck
  • 7,966
  • 2
  • 20
  • 24

1 Answers1

4

Just wrap it in a begin/rescue/ensure/end statement:

namespace :db do
  def my_checks
    ...
  end

  task :migrate do
    begin
      # something that may raise error
    rescue
      # what to do if error, you can omit this if you don't care about error
    ensure
      my_checks
    end
  end
end

EDIT

I would do it like this:

namespace :db do
  def my_checks
    ...
  end

  task :my_migrate do
    begin
      Rake::Task['db:migrate'].invoke
    rescue
      # what to do if error, you can omit this if you don't care about error
    ensure
      my_checks
    end
  end
end

EDIT 2

Okay, try:

def alias_task(name, old_name)
  # from https://gist.github.com/raggi/232966
  t = Rake::Task[old_name]
  desc t.full_comment if t.full_comment
  task name, *t.arg_names do |_, args|
    # values_at is broken on Rake::TaskArguments
    args = t.arg_names.map { |a| args[a] }
    t.invoke(args)
  end
end

alias_task 'db:old_migrate', 'db:migrate'

namespace :db do

  def my_checks
    puts 'ok'
  end

  task :migrate do
    begin
      Rake::Task["db:old_migrate"].execute
    ensure
      my_checks
    end
  end
end

EDIT 3

Okay, this should work, and is much more simple:

namespace :db do

  def my_checks
    puts 'ok'
  end

  task :other do
    at_exit { my_checks }
  end
end

Rake::Task['db:migrate'].enhance(['db:other'])

Use of at_exit from a suggestion by the late Jim Weirich at https://www.ruby-forum.com/topic/61010.

See http://ruby-doc.org/stdlib-1.9.3/libdoc/rake/rdoc/Rake/Task.html for more about enhance.

Jacob Brown
  • 7,221
  • 4
  • 30
  • 50
  • I was really hoping for a solution that would not involve wrapping the rails `db:migrate` task. It's a good approach, but it would require my colleagues to change their workflow and call `db:my_migrate` instead of `db:migrate`. I was hoping to avoid this :) – Reck Jun 23 '14 at 15:37
  • Just gave it a try. Unfortunately it doesn't seem to work. What's happening is that the rails `db:migrate` gets run followed by the code defined in the `:migrate` task of the code in edit 2. However, since I made the rails `db:migrate` throw an exception, the code defined in the :migrate task does not get reached. This is turning out to be more difficult than expected :/ – Reck Jun 23 '14 at 16:55
  • @Reck, See my edit 3. I just tried this out with an exception in `db:migrate`. – Jacob Brown Jun 23 '14 at 17:19
  • That's perfect. Thank you so much for this!! – Reck Jun 23 '14 at 17:39