如何向现有的Rails数据库添加新的种子数据

22

我正在开发一个应用程序,已经部署到一些测试和分段系统以及各种开发人员的工作站。我需要添加一些附加的参考数据,但我不确定如何添加。

大多数建议使用seed.rb文件,然而我的理解是这只在应用程序最初部署时运行一次。由于我们不想重新构建测试和分段数据库,只为了添加一行参考数据,是否有其他方法可以添加这些数据呢?

我考虑使用db migration,这个方法正确吗?

谢谢


2
你可以随意运行 seed.rb,它只是一个普通的 Ruby 脚本文件... 但请记住,如果你之前已经运行过它并再次运行,你会得到重复的数据。在你的情况下,如果你只想添加一行数据,那么可以使用 rake task 或者使用脚本运行器 http://guides.rubyonrails.org/command_line.html#rails-runner。我认为迁移不适合这种情况。 - j03w
6个回答

31

将您的seed.rb文件结构化,以允许持续创建和更新数据。您不仅限于仅运行一次种子文件,如果您认为它仅用于初始部署,您将错过它在设置参考数据方面所能提供的灵活性。

种子文件只是ruby代码,因此您可以执行以下操作:

user = User.find_or_initialize_by(email: 'bob@example.com')
user.name = 'Bob'
user.password = 'secret'
user.role = 'manager'
user.save!

如果数据不存在,它将创建新的数据;如果找到数据,则会更新数据。

如果您正确构建种子文件,则还可以创建和更新依赖对象。

我建议使用Bang Save,以确保在无法保存对象时引发异常。这是调试种子的最简单方法。

我使用seedbank gem来提供更多结构化的种子数据,包括根据环境设置数据、依赖种子等。

我不推荐使用迁移用于种子数据。它缺乏灵活性(例如如何仅针对一个环境定位种子数据),并且没有真正的方法来构建可在任何时候运行以刷新特定环境的可重用数据集。您还将拥有一组与架构无关的迁移,并且每次想要生成新的或变化现有数据时,都必须创建新的迁移。


@nmott- 在添加了上述内容后,我需要执行rake db:seed吗?如果这样做,现有的内容也会再次填充吗? - Sam
2
@Jsd 是的,rake db:seed 命令会加载种子文件,并且如果某个模型已存在,则会查找该记录并使用种子文件中的数据进行覆盖。这意味着您可以更改应用程序中的数据,并使用种子文件定期刷新回标准数据集。 - nmott
这似乎会随着时间的推移变得相当臃肿。 - Chris Nicola
很高兴知道它至少不会删除非种子数据。 - Donato
不应该使用 db:migrate 重新创建数据库,而应该使用 db:schema:load。 - weexpectedTHIS

2
最好在seed.rb或由seed.rb调用的另一个任务中使用像这样的幂等方法:
Contact.find_by_email("test@example.com") || Contact.create(email: "test@example.com", phone: "202-291-1970", created_by: "System")
# This saves you an update to the DB if the record already exists.

或者类似于@nmott的方式:
Contact.find_or_initialize_by_email("test@example.com").update_attributes(phone: "202-291-1970", created_by: "System")
# this performs an update regardless, but it may be useful if you want to reset your data.

如果您想在保存之前分配多个属性,请使用assign_attributes而不是update_attributes

2
您可以使用迁移,但这并不是您最安全的选项。例如,您通过迁移向表中添加记录,然后在将来更改该表的模式。当您在某个地方安装应用程序时,您将无法运行rake db:migrate
种子数据始终是明智的选择,因为可以在完全迁移的模式下运行rake db:seed
如果只是针对一条记录,请使用Rails控制台。

1

我经常使用种子文件向新表或现有表添加实例。我的解决方案很简单。我只需将db/seeds.rb文件中的所有其他种子数据注释掉,以便仅保留新的种子数据。然后运行bin/rake db:seed


0

我在 seed.rb 中做了类似的事情。

users_list = [
   {id: 1, name: "Diego", age: "25"},
   {id: 2, name: "Elano", age: "27"}
]

while !users_list.empty? do
  begin
    User.create(users_list)
  rescue
    users_list = users_list.drop(1) #removing the first if the id already exist.
  end
end

如果列表中已经存在具有给定ID的项目,则会返回异常,然后我们将删除该项并重试,直到users_list数组为空为止。
这样,您就不需要在包含对象之前搜索每个对象,但是您将无法像@nmott代码中那样更新已插入的值。

0

不要修改 seeds.db,因为您可能希望将其用于播种新数据库,而是可以创建自定义 Rake 任务(RailsCast #66 Custom Rake Tasks)。

您可以创建任意数量的 Rake 任务。例如,假设您有两个服务器,一个运行您的应用程序版本 1.0,另一个运行 1.1,并且您想将两者升级到 1.2。然后,您可以创建 lib/tasks/1-0-to-1-2.rakelib/tasks`1-1-to-1-2.rake,因为根据您的应用程序版本可能需要不同的代码。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接