问题描述
我有一个正在移至另一台服务器的Rails应用程序,我认为我应该使用DB:架构:加载来创建MySQL数据库,因为建议使用它.我的问题是我正在使用Capistrano进行部署,并且似乎默认为Rake DB:迁移.有没有办法更改此问题,或者是使用DB的Capistrano是有充分理由迁移的?
推荐答案
为什么要使用db:架构: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
i在我的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)的肩膀上爬上来,我已经建立了以下任务以覆盖部署:冷.
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)的好答案.我只是想添加一些评论.
首先,这是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
我已经提交了在Capistrano中实现的功能请求.在该要求中,我注意到'db:schema:load vs. vs.
问题描述
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 using capistrano to deploy and it seems to be defaulting to rake db:migrate instead. Is there a way to change this or is capistrano using db:migrate for a good reason?
推荐答案
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
其他推荐答案
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.
其他推荐答案
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.