Search code examples
ruby-on-railsrubyrubygemscapistranogit-submodules

Run `rails db:migrate` with capistrano in a gem/submodule


I have a rails 5.2 app. I am trying to deploy it using Capistrano.

The app has a gem dependency submodule, which contains all of the models and migrations needed for this project. This submodule depends on other gems in it's .gemspec.

Therefore, I need to run rails db:migrate in the submodule root, instead of the parent project root.

I have added the following to deploy.rb:

  desc 'Runs rake db:migrate if migrations are set'
  task :migrate => [:set_rails_env] do
    on primary fetch(:migration_role) do
      within "#{release_path}/PATH/TO/SUBMODULE" do
        with rails_env: fetch(:rails_env) do
          execute :rake, "db:migrate"
        end
      end
    end
  end

  before :starting,    :migrate

Gemfile:

gem 'dependency', path: 'PATH/TO/SUBMODULE'
gem 'capistrano-git-with-submodules', '~> 2.0'
group :development do
  gem 'capistrano',         require: false
  gem 'capistrano-rvm',     require: false
  gem 'capistrano-rails',   require: false
  gem 'capistrano-bundler', require: false
  gem 'capistrano3-puma',   require: false
end

When I try to run this task, I get an error message saying:

 DEBUG [b4c1cf18]   [31mCould not find aasm-5.0.2 in any of the sources[0m
 DEBUG [b4c1cf18]   
 DEBUG [b4c1cf18]   [33mRun `bundle install` to install missing gems.[0m
 DEBUG [b4c1cf18]

It seems like the gem set (containing all parent and submodule gems) used in deploying the parent project isn't in the path or is unavailable when it comes time to run this task.

I can get the parent project running without the migrations, so I know that the parent project is loading all the correct gem set at runtime. Just not during this task.

I'm not quite sure how Capistrano works under the hood, how could I make sure that these gems are available to this task when it runs?


Solution

  • I figured it out, I needed 3 things:

    1.execute :bundle before execute :rake, :"db:migrate"

    1. Provide a second argument to within "#{release_path}/PATH/TO/SUBMODULE" to make it within "#{release_path}/PATH/TO/SUBMODULE", release_path - couldn't find docs on this, only this PR: https://github.com/capistrano/bundler/pull/84

    2. symlink secrets to the engine so it doesn't prevent any tasks from running:

        task :symlink_secrets do
            on roles(:app) do
              execute "rm -rf #{release_path}/PATH/TO/SUBMODULE/spec/dummy/config/secrets.yml"
              execute "ln -nfs ~/secrets.yml #{release_path}/PATH/TO/SUBMODULE/spec/dummy/config/secrets.yml"
            end 
        end