Execute a Rake task from within migration?

Ruby on-RailsRubyMigration

Ruby on-Rails Problem Overview


I have a Rake task that loads configuration data into the DB from a file, is there a correct ruby/rails way to call it on a migration up?

My objective is to sync my team DB configs, without have to broadcast then to run the task lalala

  def self.up
    change_table :fis_situacao_fiscal do |t|
      t.remove :mostrar_endereco
      t.rename :serie, :modelo 
    end
    
    Faturamento::Cfop.destroy_all()
    #perform rake here !
  end

UPDATE How I do now, and works:

system('rake sistema:load_data file=faturamento/cfop')

And this is the suggestion from @Ryan Bigg, and it's exception:

Rake::Task['rake sistema:load_data file=faturamento/cfop'].invoke()

.

==  AlterSituacaoFiscalModeloEndereco: migrating ====================
-- change_table(:fis_situacao_fiscal)
   -> 0.0014s

rake aborted!
An error has occurred, this and all later migrations canceled:

Don't know how to build task 'rake sistema:load_data file=faturamento/cfop'

Where it went wrong?

Ruby on-Rails Solutions


Solution 1 - Ruby on-Rails

Yes there's a way to do that:

Rake::Task['your_task'].invoke

Update

Do not put rake inside the brackets, just the name of the task. You should set an ENV variable when running this:

In the console

FILE=somefile.text rake db:sistema:load_data

Calling it separately

FILE=somefile.text rake some:other:task:that:calls:it

This will be available in your tasks as ENV['file']

Solution 2 - Ruby on-Rails

Note that if you call the Rake task with 'system', you need to check the process status afterwards and raise an exception if the Rake task failed. Otherwise the migration will succeed even if the Rake task fails.

You can check the process status like this:

if !($?.success?)
  raise "Rake task failed"
end

Invoking the rake task is a nicer option - it will cause the migration to fail if the Rake task fails.

Solution 3 - Ruby on-Rails

You can execute a rake task from within a loaded Rails environment with either Rake::Task['namespace:task'].invoke or Rake::Task['namespace:task'].execute.

You can pass data to the task inside of the invoke or execute method. Example:

Rake::Task['namespace:task'].invoke(paramValue)

This param can be handled in the rake task as follows:

namespace :namespace do
  desc "Example description."
  task :task, [:param] => :environment do |t, args|
    puts args[:param]
    ...
  end
end

This can be executed on the console as:

bundle exec rake namespace:task[paramValue]

More info: https://medium.com/@sampatbadhe/rake-task-invoke-or-execute-419cd689c3bd

Solution 4 - Ruby on-Rails

This decision fits better, IMHO.

In your case it would be smth like this:

backup_env = ENV.slice('file') if ENV.key?('file')
ENV['file'] = 'faturamento/cfop'
Rake::Task['sistema:load_data'].invoke
ENV.delete 'file'
ENV.merge!(backup_env) if backup_env

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionFabiano SorianiView Question on Stackoverflow
Solution 1 - Ruby on-RailsRyan BiggView Answer on Stackoverflow
Solution 2 - Ruby on-RailsLeslie ViljoenView Answer on Stackoverflow
Solution 3 - Ruby on-RailsJacob DaltonView Answer on Stackoverflow
Solution 4 - Ruby on-RailsВіталій АдамковView Answer on Stackoverflow