【问题标题】:How to add new seed data to existing rails database如何将新的种子数据添加到现有的 Rails 数据库
【发布时间】:2026-01-02 01:35:01
【问题描述】:

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

大多数建议都说使用seed.rb,但我的理解是这只会在最初部署应用程序时运行一次。由于我们不想重建测试和暂存数据库只是为了添加 1 行参考数据,还有其他方法可以添加数据吗?

我正在考虑使用数据库迁移,这是正确的方法吗?

谢谢

【问题讨论】:

  • 你可以随意运行seed.rb,它只是一个普通的 ruby​​ 脚本文件……但请记住,如果你之前运行过它然后再次运行它,你会得到重复.在您的情况下,如果您只想添加一行数据,那么 rake task 或使用脚本运行器 guides.rubyonrails.org/command_line.html#rails-runner 我认为迁移不适合这个。

标签: ruby-on-rails ruby-on-rails-3 rails-migrations


【解决方案1】:

构建您的 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 吗?如果我喜欢现有的也再次填充??
  • @Jsd 是的,rake db:seed 将加载种子文件,如果特定模型已经存在,那么它将找到记录并用种子文件中的数据覆盖它。这意味着您可以更改应用中的数据并使用种子文件定期将其刷新回标准数据集。
  • 不过,随着时间的推移,它似乎最终会变得相当臃肿。
  • 很高兴知道它至少不会删除非种子数据
  • 您不应该使用 db:migrate 重新创建数据库,只需使用 db:schema:load
【解决方案2】:

您可以使用迁移,但这不是您拥有的最安全的选择。 例如,您通过迁移将记录添加到表中,然后在将来更改该表的架构。当您在某处安装应用程序时,您将无法运行rake db:migrate

种子总是可取的,因为rake db:seed 可以在完全迁移的架构上运行。

如果只是为了记录,请使用 rails 控制台。

【讨论】:

    【解决方案3】:

    最好在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

    【讨论】:

      【解决方案4】:

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

      【讨论】:

        【解决方案5】:

        我在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 代码中那样更新已插入的值。

        【讨论】:

          【解决方案6】:

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

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

          【讨论】: