在Rails中播种数据库的最佳方法是什么?


82

我有一个rake任务,可在Rails应用程序中填充一些初始数据。例如,国家,州,移动运营商等。

我现在设置的方式是,我在/ db / fixtures中的文件中有一堆create语句和一个处理它们的rake任务。例如,主题是我拥有的一个模型。我在/ db / fixtures中有一个theme.rb文件,看起来像这样:

Theme.delete_all
Theme.create(:id => 1, :name=>'Lite', :background_color=>'0xC7FFD5', :title_text_color=>'0x222222',
                      :component_theme_color=>'0x001277', :carrier_select_color=>'0x7683FF', :label_text_color=>'0x000000',
                      :join_upper_gradient=>'0x6FAEFF', :join_lower_gradient=>'0x000000', :join_text_color=>'0xFFFFFF',
                      :cancel_link_color=>'0x001277', :border_color=>'0x888888', :carrier_text_color=>'0x000000', :public => true)

Theme.create(:id => 2, :name=>'Metallic', :background_color=>'0x000000', :title_text_color=>'0x7299FF',
                      :component_theme_color=>'0xDBF2FF', :carrier_select_color=>'0x000000', :label_text_color=>'0xDBF2FF',
                      :join_upper_gradient=>'0x2B25FF', :join_lower_gradient=>'0xBEFFAC', :join_text_color=>'0x000000',
                      :cancel_link_color=>'0xFF7C12', :border_color=>'0x000000', :carrier_text_color=>'0x000000', :public => true)

Theme.create(:id => 3, :name=>'Blues', :background_color=>'0x0060EC', :title_text_color=>'0x000374',
                      :component_theme_color=>'0x000374', :carrier_select_color=>'0x4357FF', :label_text_color=>'0x000000',
                      :join_upper_gradient=>'0x4357FF', :join_lower_gradient=>'0xffffff', :join_text_color=>'0x000000',
                      :cancel_link_color=>'0xffffff', :border_color=>'0x666666', :carrier_text_color=>'0x000000', :public => true)
puts "Success: Theme data loaded"

这里的想法是,我想为用户安装一些股票主题。我对此方法有疑问。

设置ID无效。这意味着如果我决定添加一个主题,我们将其称为“红色”,那么我只想将主题语句添加到此Fixture文件中,并调用rake任务重新设置数据库的种子。如果这样做,因为主题属于其他对象,并且在重新初始化时更改了它们的ID,则所有链接都将断开。

我的问题是首先,这是处理种子数据库的好方法吗?在以前的帖子中,这是向我推荐的。

如果是这样,我该如何对ID进行硬编码,这有什么缺点?

如果不是,播种数据库的最佳方法是什么?

我将不胜感激,并经过深思熟虑,并结合了最佳实践。

Answers:


113

由于这些答案有些过时(尽管有些仍然适用),因此正在更新。

在Rails 2.3.4,db / seeds.rb中添加了简单功能

提供新的耙任务

rake db:seed

非常适合填充常见的静态记录,例如州,国家/地区等。

http://railscasts.com/episodes/179-seed-data

*请注意,如果已经创建了灯具,也可以使用db:seed任务来填充灯具,方法是将以下内容放入seed.rb文件(来自railscast情节):

require 'active_record/fixtures'
Fixtures.create_fixtures("#{Rails.root}/test/fixtures", "operating_systems")

对于Rails 3.x,使用“ ActiveRecord :: Fixtures”而不是“ Fixtures”常量

require 'active_record/fixtures'
ActiveRecord::Fixtures.create_fixtures("#{Rails.root}/test/fixtures", "fixtures_file_name")

28

通常,需要两种类型的种子数据。

  • 应用程序核心可能依赖的基本数据。我称其为普通种子。
  • 例如,环境数据对于开发应用程序来说,拥有一堆处于已知状态的数据非常有用,我们可以将其用于本地处理应用程序(上面的Factory Girl答案涵盖了此类数据)。

以我的经验,我总是遇到对这两种类型数据的需求。所以我放了一块小宝石,延伸了Rails的种子并允许您在db / seeds /下添加多个常见的种子文件,并在db / seeds / ENV下添加任何环境种子数据,例如db / seeds / development。

我发现这种方法足以使我的种子数据具有某种结构,并且使我能够通过运行以下命令将开发或登台环境设置为已知状态:

rake db:setup

固定装置易碎且易维护,常规sql转储也是如此。


我喜欢术语“系统数据”和“运行时数据”来描述代码依赖于现有数据与用户数据的关系。有时它们之间的界限很模糊。
Tim Abell

27

factory_bot听起来像它将完成您要实现的目标。您可以在默认定义中定义所有通用属性,然后在创建时覆盖它们。您还可以将ID传递给工厂:

Factory.define :theme do |t|
  t.background_color '0x000000'
  t.title_text_color '0x000000',
  t.component_theme_color '0x000000'
  t.carrier_select_color '0x000000'
  t.label_text_color '0x000000',
  t.join_upper_gradient '0x000000'
  t.join_lower_gradient '0x000000'
  t.join_text_color '0x000000',
  t.cancel_link_color '0x000000'
  t.border_color '0x000000'
  t.carrier_text_color '0x000000'
  t.public true
end

Factory(:theme, :id => 1, :name => "Lite", :background_color => '0xC7FFD5')
Factory(:theme, :id => 2, :name => "Metallic", :background_color => '0xC7FFD5')
Factory(:theme, :id => 3, :name => "Blues", :background_color => '0x0060EC')

当与fakerr一起使用时,它可以真正快速地用关联填充数据库,而不必担心Fixtures(糟糕)。

我在rake任务中有这样的代码。

100.times do
    Factory(:company, :address => Factory(:address), :employees => [Factory(:employee)])
end

11
FactoryGirl实际上是用于代替固定装置进行测试的,但是它也可以用于将物料加载到生产中。使用以db:migrate为先决条件的rake任务来加载所有默认数据。您可能需要使rake任务足够智能,以至于它不会创建现有数据的副本。
Bob Aman

2
不建议使用FactoryGirl作为种子,请查看此文章
blackbiron

26

使用seeds.rb文件或FactoryBot很棒,但是对于固定数据结构和测试而言,它们分别很棒。

seedbank宝石可能会给你更多的控制和模块化你的种子。它插入了rake任务,您还可以定义种子之间的依赖关系。您的rake任务列表将具有以下附加功能(例如):

rake db:seed                    # Load the seed data from db/seeds.rb, db/seeds/*.seeds.rb and db/seeds/ENVIRONMENT/*.seeds.rb. ENVIRONMENT is the current environment in Rails.env.
rake db:seed:bar                # Load the seed data from db/seeds/bar.seeds.rb
rake db:seed:common             # Load the seed data from db/seeds.rb and db/seeds/*.seeds.rb.
rake db:seed:development        # Load the seed data from db/seeds.rb, db/seeds/*.seeds.rb and db/seeds/development/*.seeds.rb.
rake db:seed:development:users  # Load the seed data from db/seeds/development/users.seeds.rb
rake db:seed:foo                # Load the seed data from db/seeds/foo.seeds.rb
rake db:seed:original           # Load the seed data from db/seeds.rb

1

Rails有内置的方法种子数据的解释这里

另一种方法是将宝石用于更高级或更容易的播种,例如:seedbank

该gem的主要优点以及我使用它的原因是它具有高级功能,例如数据加载依赖性和每个环境的种子数据。

添加最新答案,因为此答案首先出现在Google上。


-3

最好的方法是使用灯具。

注意:请记住,夹具会直接插入并且不会使用模型,因此,如果您有填充数据的回调,则需要找到解决方法。


-4

在数据库迁移中添加它,这样每个人都可以在更新时获取它。在ruby / rails代码中处理所有逻辑,因此您不必麻烦使用显式ID设置。


如果我需要更改初始数据,则在使用迁移时可能会变得混乱。您的第二条评论没有任何意义。通过外键的链接将被破坏
Tony

c = Category.create(stuff)p = Post.create(stuff)p.category = c无需明确设置ID。如果更改初始数据,则只需创建一个新的迁移。相当容易。
Matt Rogish 09年

假设可以在创建对象时进行关联。这是一个我相信您的逻辑失败的示例...如果我错了,请纠正我。我用模板主题播种数据库。用户ID = 1创建模板ID = 2,主题ID = 4。此时,数据库中的记录如下:模板:id = 2,user_id = 1,theme_id = 4。现在,如果我重新初始化数据库,则主题ID = 4现在是主题ID = 10 ...然后用户模板的主题设置错误
Tony

好吧,这取决于“重新初始化”的含义-如果从零开始,Rails会自动处理所有关联。如果您要对ID值进行硬编码(错误!!!),那么它会崩溃。
马特·罗吉什

好的,我开始明白您的意思了,但是我必须由您来运行此方案。我用一个国家查询表为数据库添加了种子。美国=>国家/地区ID = 1。然后用户创建在美国存在的餐厅。餐厅数据库行的country_id =1。这很常见,对吧?稍后我决定要添加更多国家/地区...如果我将db清除干净并重新填充国家/地区查找表,那么除非id相同,否则餐厅国家/地区不再准确。我该如何处理?
托尼
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.