I would like to run db:schema:load
in place of db:migrate
on the initial deploy of my rails app.
This used to be fairly trivial, as seen in this stack overflow question, but in Capistrano 3, they have deprecated the deploy:cold
task. The initial deploy isn't any different than all subsequent deploys.
Any suggestions? Thanks!
I, too, am new to Capistrano, and trying to use it for the first time to deploy a Rails app to production servers I configured with Puppet.
I finally had to dig into the Capistrano source (and capistrano/bundler, and capistrano/rails, and even sshkit and net-ssh to debug auth problems) to determine exactly how everything works before I felt confidant deciding for myself what changes I wanted to make. I just finished making those changes, and I'm pleased with the results:
# lib/capistrano/tasks/cold.rake
namespace :deploy do
desc "deploy app for the first time (expects pre-created but empty DB)"
task :cold do
before 'deploy:migrate', 'deploy:initdb'
invoke 'deploy'
end
desc "initialize a brand-new database (db:schema:load, db:seed)"
task :initdb do
on primary :web do |host|
within release_path do
if test(:psql, 'portal_production -c "SELECT table_name FROM information_schema.tables WHERE table_schema=\'public\' AND table_type=\'BASE TABLE\';"|grep schema_migrations')
puts '*** THE PRODUCTION DATABASE IS ALREADY INITIALIZED, YOU IDIOT! ***'
else
execute :rake, 'db:schema:load'
execute :rake, 'db:seed'
end
end
end
end
end
The deploy:cold task merely hooks my custom deploy:inidb task to run before deploy:migrate. That way the schema and seeds get loaded, and the deploy:migrate step that follows does nothing (safely) because there are no new migrations to run. As a safety, I test to see if the schema_migrations table already exists before loading the schema in case you run deploy:cold again.
Note: I choose to create the DB using Puppet so I can avoid having to grant the CREATEDB privilege to my production postgresql user, but if you want Capistrano to do it, just add "execute :rake, 'db:create'" before the db:schema:load, or replace all three lines with 'db:setup'.
You'll have to define deploy:cold
as basically a duplicate of the normal deploy task but with deploy:db_load_schema
instead of deploy:migrations
. For example:
desc 'Deploy app for first time'
task :cold do
invoke 'deploy:starting'
invoke 'deploy:started'
invoke 'deploy:updating'
invoke 'bundler:install'
invoke 'deploy:db_load_schema' # This replaces deploy:migrations
invoke 'deploy:compile_assets'
invoke 'deploy:normalize_assets'
invoke 'deploy:publishing'
invoke 'deploy:published'
invoke 'deploy:finishing'
invoke 'deploy:finished'
end
desc 'Setup database'
task :db_load_schema do
on roles(:db) do
within release_path do
with rails_env: (fetch(:rails_env) || fetch(:stage)) do
execute :rake, 'db:schema:load'
end
end
end
end
It might even be better to run the deploy:db_schema_load
task independently, as the tasks included in the default deploy
might change over time.
I actually using db:setup
for fresh deploys because it seeds the database after creating tables:
desc 'Setup database'
task :db_setup do
...
execute :rake, 'db:setup'
...
end
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With