db:schema:load и db:migrate с помощью capistrano

У меня есть приложение rails, которое я переношу на другой сервер, и я полагаю, что должен использовать db:schema:load для создания базы данных mysql, потому что это рекомендуется. Моя проблема в том, что я использую capistrano для развертывания, и, похоже, вместо этого по умолчанию используется rake db: migrate. Есть ли способ изменить это или Capistrano использует db: migrate по уважительной причине?


person Anon    schedule 25.08.2009    source источник
comment
Какую основную задачу вы используете для развертывания на новом сервере?   -  person Greg Campbell    schedule 25.08.2009


Ответы (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
person Andres Jaan Tack    schedule 29.10.2009
comment
Отлично. Я изменил свое холодное развертывание в соответствии с этим форматом. Однако я использую Multistage-Extension, поэтому я добавил RAILS_ENV=${rails_env} после rake. Также для моей промежуточной среды я хотел перезагрузить схему, поэтому я добавил туда rake db:drop и rake db:create. - person Howler; 09.06.2011
comment
@Хоулер, я тоже так делал. :) - person Andres Jaan Tack; 29.06.2011
comment
ВНИМАНИЕ: это старо. См. ответы на Cap 3.x или выше. - person labyrinth; 11.03.2019

Взобравшись на плечи Андреса Яана Така, Адама Спирса и Камиэля Ванруиджа, я построил следующую задачу для перезаписи 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, так что, если база данных еще не существует, она будет создана перед загрузкой схемы.
person Jon Garvin    schedule 12.07.2012
comment
ВНИМАНИЕ: это старо. См. ответы на Cap 3.x или выше. - person labyrinth; 11.03.2019

Это отличный ответ от Андреса Яана Така. Я просто хотел добавить несколько комментариев.

Во-первых, вот улучшенная версия задачи Андреса 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 технически является лучшим подходом, поэтому, если можно снизить риск случайной потери данных, стоит перейти на него.

person Adam Spiers    schedule 17.05.2012
comment
Добавление 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
comment
Отличная идея, Камиэль! Я только что добавил ваше предложение к проблеме github. - person Adam Spiers; 18.05.2012
comment
ВНИМАНИЕ: это старо. См. ответы на Cap 3.x или выше. - person labyrinth; 11.03.2019

В 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
person Xavier    schedule 02.08.2014
comment
Спасибо. Это работает очень хорошо. Однако я не могу просто запустить deploy:db_setup, так как на сервере еще нет копии моего приложения (насколько я понимаю, самое первое развертывание подготовило бы почву для этого). Мне очень странно, что у Capistrano нет задачи по умолчанию для этого требования... - person Joshua Muheim; 22.10.2019