У меня есть приложение rails, которое я переношу на другой сервер, и я полагаю, что должен использовать db:schema:load для создания базы данных mysql, потому что это рекомендуется. Моя проблема в том, что я использую capistrano для развертывания, и, похоже, вместо этого по умолчанию используется rake db: migrate. Есть ли способ изменить это или Capistrano использует db: migrate по уважительной причине?
db:schema:load и db:migrate с помощью capistrano
Ответы (4)
Зачем использовать db:schema:load
Я обнаружил, что мои собственные миграции в конечном итоге приводят к некоторой перетасовке данных (например, я объединяю столбцы first_name и last_name в столбец full_name). Как только я делаю что-либо из этого, я начинаю использовать ActiveRecord для просеивания записей базы данных, и ваши модели в конечном итоге делают предположения об определенных столбцах. Моя таблица «Люди», например, позже получила столбец «Позиция», по которому сортируются люди. В более ранних миграциях теперь не удается выбрать данные, поскольку столбец «позиция» еще не существует.
Как изменить поведение по умолчанию в Capistrano
В заключение я считаю, что deploy:cold
следует использовать db:schema:load
вместо db:migrate
. Я решил эту проблему, изменив средний шаг, который Capistrano выполняет при холодном развертывании. Для Capistrano v2.5.9 задача по умолчанию в коде библиотеки выглядит так.
namespace :deploy do
...
task :cold do
update
migrate # This step performs `rake db:migrate`.
start
end
...
end
Я переопределил задачу в моем deploy.rb
следующим образом.
namespace :deploy do
task :cold do # Overriding the default deploy:cold
update
load_schema # My own step, replacing migrations.
start
end
task :load_schema, :roles => :app do
run "cd #{current_path}; rake db:schema:load"
end
end
Взобравшись на плечи Андреса Яана Така, Адама Спирса и Камиэля Ванруиджа, я построил следующую задачу для перезаписи deploy:cold.
task :cold do
transaction do
update
setup_db #replacing migrate in original
start
end
end
task :setup_db, :roles => :app do
raise RuntimeError.new('db:setup aborted!') unless Capistrano::CLI.ui.ask("About to `rake db:setup`. Are you sure to wipe the entire database (anything other than 'yes' aborts):") == 'yes'
run "cd #{current_path}; bundle exec rake db:setup RAILS_ENV=#{rails_env}"
end
Мои улучшения здесь...
- оберните его в
transaction do
, чтобы Capistrano выполнил правильный откат после прерывания. - выполнение
db:setup
вместоdb:schema:load
, так что, если база данных еще не существует, она будет создана перед загрузкой схемы.
Это отличный ответ от Андреса Яана Така. Я просто хотел добавить несколько комментариев.
Во-первых, вот улучшенная версия задачи Андреса deploy:load_schema
, которая включает предупреждение и, что более важно, использует bundle exec
и RAILS_ENV
для обеспечения правильной настройки среды:
namespace :deploy do
desc 'Load DB schema - CAUTION: rewrites database!'
task :load_schema, :roles => :app do
run "cd #{current_path}; bundle exec rake db:schema:load RAILS_ENV=#{rails_env}"
end
end
Я отправил запрос на добавление deploy:load_schema
в Capistrano. В этом запросе я отметил, что дебаты "db:schema:load
против db:migrate
" уже освещались в дискуссионной группе Capistrano. , и было некоторое нежелание переключать задачу deploy:cold
на использование db:schema:load
вместо db:migrate
, поскольку при непреднамеренном запуске первая уничтожает всю базу данных, тогда как вторая, вероятно, пожалуется и безвредно выйдет из строя. Тем не менее, db:schema:load
технически является лучшим подходом, поэтому, если можно снизить риск случайной потери данных, стоит перейти на него.
raise RuntimeError.new('load_schema aborted!') unless Capistrano::CLI.ui.ask("Are you sure to wipe the entire database (anything other than 'yes' aborts):") == 'yes'
в начале задачи работает как шарм! Это кажется достаточно безопасным, чтобы пропатчить deploy:cold.
- person Kamiel Wanrooij; 18.05.2012
В Capistrano 3/Rails 4 синтаксис развертывания по умолчанию изменился. Вместо этого вы можете сделать это:
desc 'Deploy app for first time'
task :cold do
invoke 'deploy:starting'
invoke 'deploy:started'
invoke 'deploy:updating'
invoke 'bundler:install'
invoke 'deploy:db_setup' # 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_setup do
on roles(:db) do
within release_path do
with rails_env: (fetch(:rails_env) || fetch(:stage)) do
execute :rake, 'db:setup' # This creates the database tables AND seeds
end
end
end
end
Если вы опасаетесь запускать стандартные задачи развертывания вручную в задаче :cold
(поскольку они могут измениться в следующей версии или если у вас есть пользовательская задача развертывания), вы также можете просто вызвать deploy:db_setup
перед запуском deploy
.
Чтобы выполнить db:schema:load
вместо db:setup
, вы можете просто изменить задачу rake, например:
desc 'Load DB Schema'
task :db_schema_load do
...
execute :rake, 'db:schema:load'
...
end
deploy:db_setup
, так как на сервере еще нет копии моего приложения (насколько я понимаю, самое первое развертывание подготовило бы почву для этого). Мне очень странно, что у Capistrano нет задачи по умолчанию для этого требования...
- person Joshua Muheim; 22.10.2019