在建立Rails开发环境时保留现有数据 | 日常Rails

200 阅读3分钟

你的Rails应用是否利用了bin/setup脚本来简化新开发者的入职培训?如果没有,那么尽可能地将这个过程自动化往往是值得的。rails new 所提供的默认版本是一个很好的起点。这样做可以为未来的开发者节省宝贵的升级时间,并在同时发现设置过程中的潜在漏洞。而且正如我一直在学习的那样,它对Visual Studio Code中基于容器的开发环境来说是超级方便的。

但是,有一个问题潜伏着!

Rails提供的bin/setup样本包括一个设置新的开发和测试数据库的步骤,使用db:setup rake任务。这个任务实际上执行了几个不同的任务:

  • 创建数据库(开发和测试)。
  • 在这些数据库上建立模式,如db/schema.rb(或*.sql*)中定义的那样
  • db/seeds.rb中的数据作为开发数据库的种子,如果有的话。

不过,这些步骤中的一个并不是无用的,在随后的运行中会抹去任何开发中的数据。

从定义文件中构建模式比迁移更快,而且避免了迁移文件被删除的潜在问题。但是,根据设计,它放弃了现有的表,并根据模式文件中提供的最新定义重新创建它们。db:reset 任务的文档明确指出数据库会被清除,而db:setup的文档却没有提到这一点,这就更令人惊讶和困惑了!这就是为什么我们要把数据库清除掉。

总之,在第一次建立传统开发环境时,运行bin/setup(或rails db:setup )作为一个一次性的过程,这可能不是一个问题,但在基于Docker容器的开发环境中,从头开始的重建可能会更频繁,怎么办?

保留你的开发数据!

我找到了一个解决方案。添加一个rake任务,通过检查Active Record是否能与之建立连接来检查开发数据库是否存在。然后,根据结果来决定是否运行db:setup

这就是任务,由Stack Overflow上的penguincoder提供。我把它放在lib/tasks/db.rake中:

namespace :db do
  desc "Checks to see if the database exists"
  task :exists do
    begin
      Rake::Task["environment"].invoke
      ActiveRecord::Base.connection
    rescue
      exit 1
    else
      exit 0
    end
  end
end

然后,更新bin/setup,在system! 调用中加入一点额外的bash,进行实际的数据库设置。检查数据库是否已经存在,如果存在,只需运行迁移,使其与当前模式保持一致。如果没有,就进行全面的设置,包括根据应用程序当前的模式定义重建数据库:

puts "\n== Preparing database =="
system! 'bin/rails db:exists && bin/rails db:migrate || bin/rails db:setup'

我喜欢这种方法,有几个原因。首先,把它变成一个rake任务意味着我可以在其他工作流程中重复使用它,甚至可以提取到一个gem中。其次,它使bin/setup接近其原始精神--只是一个轻量级的Ruby脚本,执行较低层次的要求,以准备一个开发环境。只要安装了Ruby,它就应该能够完成它的工作。

我还测试了一种交互式方法--提示开发者是否重置数据库--但这在VS Codedevcontainer.json文件中把bin/setup设postCreateCommand ,并不奏效。也许可以通过加入第三方CLI应用程序gem来实现这两种方式,但我还是想让bin/setup保持简单。

总结

在我继续以程序员的幸福为名建立和完善基于容器的开发环境时,我非常倾向于让Ruby和Rails做它们擅长的事情,其余的则使用Docker。我很高兴这个解决方案允许我继续采用这种方法。

无论你是为你的应用程序建立一个基于Docker容器的开发环境,还是以其他方式加强入职体验,我都希望这个方法是有用的。谢谢你的阅读!