У меня есть приложение rails, которое я перехожу на другой сервер, и я полагаю, что я должен использовать db: schema: load для создания базы данных mysql, потому что он рекомендуется. Моя проблема заключается в том, что я использую capistrano для развертывания, и, похоже, он не выполняет команду rake db: вместо этого migrate. Есть ли способ изменить это или является capistrano с помощью db: migrate по уважительной причине?
Db: schema: load vs db: migrate with capistrano
Ответ 1
Зачем использовать 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
Ответ 2
Поднявшись на плечи Андреса Яана Тэка, Адама Спирса и Камиэля Ваньюоя, я создал следующую задачу, чтобы перезаписать развертывание: холодно.
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
, поэтому, если база данных еще не существует, она будет создана до загрузки схемы.
Ответ 3
Это отличный ответ Андреса Яана Тэка. Я просто хотел добавить несколько комментариев.
Во-первых, здесь улучшена версия задачи Andres 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
vs. db:migrate
уже обсуждалось в группе обсуждения Capistrano, и было некоторое нежелание переключаться Задача deploy:cold
использовать db:schema:load
над db:migrate
, так как если вы запускаете ее непреднамеренно, то первая уничтожает всю базу данных, тогда как последняя, вероятно, будет жаловаться и без залога. Тем не менее db:schema:load
технически лучше подходит, поэтому, если риск случайной потери данных может быть уменьшен, стоило бы переключиться.
Ответ 4
В 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
, вы можете просто изменить задачу грабли, например:
desc 'Load DB Schema'
task :db_schema_load do
...
execute :rake, 'db:schema:load'
...
end