我有一个要移动到另一台服务器的 rails 应用程序,我认为我应该使用 db:schema:load 来创建 mysql 数据库,因为它是推荐的。我的问题是我正在使用 capistrano 进行部署,并且它似乎默认为 rake db:migrate 。有没有办法改变这一点,或者 capistrano 是否有充分的理由使用 db:migrate?
4 回答
为什么要使用 db:schema:load
我发现我自己的迁移最终会对数据进行一些改组(例如,假设我将 first_name 和 last_name 列组合成一个 full_name 列)。一旦我这样做了,我就开始使用 ActiveRecord 来筛选数据库记录,并且您的模型最终会对某些列做出假设。例如,我的“Person”表后来被赋予了一个“position”列,用于对人员进行排序。早期的迁移现在无法选择数据,因为“位置”列还不存在。
如何更改 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
爬上 Andres Jaan Tack、Adam Spiers 和 Kamiel Wanrooij 的肩膀,我构建了以下任务来覆盖 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
,这样如果数据库不存在,它将在加载模式之前创建。
这是 Andres Jaan Tack 的一个很好的回答。我只是想添加一些评论。
首先,这是 Andresdeploy: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
我已经提交了在 Capistrano中实施的功能请求deploy:load_schema
。在那个请求中,我注意到Capistrano 讨论组已经讨论了“ db:schema:load
vsdb:migrate
”的争论,并且有些人不愿意将deploy:cold
任务切换到 using db:schema:load
over db:migrate
,因为如果无意中运行,前者会破坏整个数据库,而后者可能会抱怨并无害地保释。尽管如此db:schema:load
,从技术上讲,这是更好的方法,因此如果可以减轻意外数据丢失的风险,那么值得转换。
在 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