mercredi 22 décembre 2021

Run Rake task programmatically with specified environment

I'm setting up a second database with my Ruby on Rails (3) application, so I want to create a rake task to create the second development database. I'm trying to overwrite the rake db:create task such that it does all the database creation that I need. However, it seems I can't find a suitable way to perform this task. I've tried a few approaches - establishing a connection to the database from the URL:

# remove db:create from the list of rake tasks in order to override it
db_create = Rake.application.instance_variable_get('@tasks').delete('db:create')

namespace :db do
  task :create do
    if Rails.env == "development"
      # database.yml contains an entry for secondary_development, this works, as confirmed from rails console
      ActiveRecord::Base.establish_connection "postgresql://localhost/secondary_development"       
      Rake::Task["db:create"].invoke # this does nothing
    end

    # invoke original db_create task - this works
    db_create.invoke
  end
end

Another approach was to do:

# remove db:create from the list of rake tasks in order to override it
db_create = Rake.application.instance_variable_get('@tasks').delete('db:create')

namespace :db do
  task :create do
    if Rails.env == "development"
      Rails.env = "secondary_development"
      Rake::Task["db:create"].invoke
    end

    # invoke original db_create task - this doesn't work like this
    db_create.invoke
  end
end

This time only the secondary_development db:create works and the database is created as desired, but the development database is no longer created using this approach.

From one answer I found elsewhere, I thought that reenabling the task would be necessary, but that didn't change anything here and appears not to be the issue.

Finally, an approach that has worked is:

# remove db:create from the list of rake tasks in order to override it
db_create = Rake.application.instance_variable_get('@tasks').delete('db:create')

namespace :db do
  task :create do
    if Rails.env == "development"
      system("rake db:create RAILS_ENV=secondary_development")
    end

    db_create.invoke
  end
end

The only issue here is that because the rake task is being run via system, the Rails application has to load before being executed, so I'm essentially loading the application twice fully just to run the task - this will be 3 times when I add a test database into the mix.

So, the actual question(s):

Is it possible to run Rake::Task["..."] programmatically with a specified environment?

Why doesn't ActiveRecord::Base.establish_connection work in this way when creating the database? I had success when running this from Rails console.

Aucun commentaire:

Enregistrer un commentaire