db:schema:load vs db:migrate with capistrano

前端 未结 4 1878
说谎
说谎 2021-01-31 18:54

I have a rails app that I\'m moving to another server and I figure I should use db:schema:load to create the mysql database because it\'s recommended. My problem is that I\'m u

相关标签:
4条回答
  • 2021-01-31 19:25

    In Capistrano 3 / Rails 4, the default deploy syntax has changed. You can do this instead:

    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
    

    If you're cautious of invoking the standard deploy tasks manually in the :cold task (as they may change in upcoming version or if you have a custom deploy task), you can also simply call deploy:db_setup before running deploy.

    To perform db:schema:load instead of db:setup, you can simply change the rake task, like so:

    desc 'Load DB Schema'
    task :db_schema_load do
      ...
            execute :rake, 'db:schema:load'
      ...
    end
    
    0 讨论(0)
  • 2021-01-31 19:30

    Why to use db:schema:load

    I find that my own migrations eventually do some shuffling of data (suppose I combine first_name and last_name columns into a full_name column, for instance). As soon as I do any of this, I start using ActiveRecord to sift through database records, and your models eventually make assumptions about certain columns. My "Person" table, for instance, was later given a "position" column by which people are sorted. Earlier migrations now fail to select data, because the "position" column doesn't exist yet.

    How to change the default behavior in Capistrano

    In conclusion, I believe deploy:cold should use db:schema:load instead of db:migrate. I solved this problem by changing the middle step which Capistrano performs on a cold deploy. For Capistrano v2.5.9, the default task in the library code looks like this.

    namespace :deploy do
      ...
      task :cold do
        update
        migrate  # This step performs `rake db:migrate`.
        start
      end
      ...
    end
    

    I overrode the task in my deploy.rb as follows.

    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
    
    0 讨论(0)
  • 2021-01-31 19:31

    That's a great answer from Andres Jaan Tack. I just wanted to add a few comments.

    Firstly, here's an improved version of Andres' deploy:load_schema task which includes a warning, and more importantly uses bundle exec and RAILS_ENV to ensure that the environment is set up correctly:

    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
    

    I have submitted a feature request to have deploy:load_schema implemented in Capistrano. In that request, I noted that the 'db:schema:load vs. db:migrate' debate has already been covered in the Capistrano discussion group, and there was some reluctance to switch the deploy:cold task to using db:schema:load over db:migrate, since if run unintentionally, the former nukes the entire database whereas the latter would probably complain and bail harmlessly. Nevertheless db:schema:load is technically the better approach, so if the risk of accidental data loss could be mitigated, it would be worth switching.

    0 讨论(0)
  • 2021-01-31 19:47

    Climbing up on the shoulders of Andres Jaan Tack, Adam Spiers, and Kamiel Wanrooij, I've built the following task to overwrite 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
    

    My enhancements here are...

    • wrap it in transaction do, so that Capistrano will do a proper rollback after aborting.
    • doing db:setup instead of db:schema:load, so that if the database doesn't already exist, it will be created before loading the schema.
    0 讨论(0)
提交回复
热议问题