Railsでデータベースをシードする最良の方法は何ですか?


82

Railsアプリに初期データを入力するrakeタスクがあります。たとえば、国、州、携帯電話会社など。

私が今それを設定している方法は、/ db / fixtures内のファイルにたくさんのcreateステートメントとそれらを処理するrakeタスクがあることです。たとえば、私が持っているモデルの1つはテーマです。/ 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の設定は機能しません。つまり、テーマを追加することにした場合は、それを「赤」と呼びましょう。次に、このフィクスチャファイルにテーマステートメントを追加し、rakeタスクを呼び出してデータベースを再シードします。そうすると、テーマは他のオブジェクトに属し、この再初期化時にIDが変更されるため、すべてのリンクが壊れます。

私の質問はまず第一に、これはデータベースのシードを処理するための良い方法ですか?以前の投稿で、これは私に推奨されました。

もしそうなら、どうすればIDをハードコーディングできますか?それには欠点がありますか?

そうでない場合、データベースをシードするための最良の方法は何ですか?

ベストプラクティスを取り入れた、長く考え抜かれた回答に心から感謝します。

回答:


113

これらの回答は少し古くなっているため、更新しています(ただし、一部はまだ適用されます)。

Rails 2.3.4、db /seeds.rbに追加されたシンプルな機能

新しいレーキタスクを提供します

rake db:seed

州、国などの一般的な静的レコードを入力するのに適しています...

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

*フィクスチャをすでに作成している場合は、フィクスチャを使用して、(railscastエピソードからの)seeds.rbファイルに以下を追加することでdb:seedタスクを設定できることに注意してください。

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

Rails 3.xの場合、「Fixtures」定数の代わりに「ActiveRecord :: Fixtures」を使用します

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

28

通常、2種類のシードデータが必要です。

  • アプリケーションのコアが依存する可能性のある基本データ。私はこれを一般的な種と呼んでいます。
  • 環境データ、たとえばアプリを開発する場合、ローカルでアプリを操作するために使用できる既知の状態のデータを大量に用意しておくと便利です(上記のファクトリーガールの回答はこの種のデータを対象としています)。

私の経験では、これら2つのタイプのデータの必要性に常に遭遇していました。そこで、Railsのシードを拡張し、db / seeds /の下に複数の一般的なシードファイルを追加し、db / seeds / ENVの下に環境シードデータ(db / seeds / developmentなど)を追加できる小さなgemをまとめまし

このアプローチは、シードデータに何らかの構造を与えるのに十分であり、次のコマンドを実行するだけで、開発環境またはステージング環境を既知の状態にセットアップする力を与えてくれます。

rake db:setup

通常のSQLダンプと同様に、フィクスチャは壊れやすく、維持するのが簡単です。


「システムデータ」と「ランタイムデータ」という用語は、コードが既存のデータとユーザーからのデータに依存していることを表すのが好きです。それらの間の線がぼやけていることがあります。
ティムアベル

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')

偽造者と一緒に使用すると、Fixtures(yuck)をいじる必要なしに、データベースに関連付けを非常に迅速に取り込むことができます。

rakeタスクにこのようなコードがあります。

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

11
FactoryGirlは、実際にはフィクスチャの代わりにテストすることを目的としていますが、本番環境にデータをロードするためにも使用できます。すべてのデフォルトデータをロードするための前提条件としてdb:migrateを持つrakeタスクを使用します。rakeタスクを、既存のデータのコピーを作成しないように十分にインテリジェントにする必要がある場合があります。
ボブ・アマン

2
FactoryGirlをシードに使用することはお勧めしません。この投稿を確認してください
blackbiron 2017年

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には、ここで説明するようにデータをシードする方法が組み込まれています

もう1つの方法は、seedbankなどのより高度で簡単なシードにgemを使用することです

このgemの主な利点と私が使用する理由は、データの読み込みの依存関係や環境ごとのシードデータなどの高度な機能を備えていることです。

この答えはグーグルで最初だったので、最新の答えを追加します。


-3

最良の方法は、器具を使用することです。

注:フィクスチャは直接挿入を行い、モデルを使用しないため、データを入力するコールバックがある場合は、回避策を見つける必要があることに注意してください。


-4

データベースの移行に追加します。そうすれば、更新時に全員が取得できます。すべてのロジックをruby / railsコードで処理するため、明示的なID設定をいじる必要はありません。


初期データを変更する必要がある場合、移行を使用すると問題が発生する可能性があります。あなたの2番目のコメントは本当に意味がありません。外部キーを介したリンクは破棄されます
Tony

c = Category.create(stuff)p = Post.create(stuff)p.category = cIDを明示的に設定する必要はありません。初期データを変更する場合は、新しい移行を作成するだけです。とても簡単。
Matt Rogish 2009

つまり、オブジェクトの作成時に関連付けを行うことができると想定しています。これはあなたの論理が失敗すると私が信じる例です...私が間違っているなら私を訂正してください。テンプレートテーマをDBにシードします。ユーザーid = 1は、テーマid = 4のテンプレートid = 2を作成します。この時点で、レコードは次のようにデータベースにあります:テンプレート:id = 2、user_id = 1、theme_id = 4。データベースを再初期化すると、テーマID = 4がテーマID = 10になります...その後、ユーザーのテンプレートのテーマが正しくなくなります
Tony

「re-init」の意味によって異なります。ゼロから開始すると、Railsはすべての関連付けを自動的に処理します。ID値をハードコーディングしている場合(悪い!!!)、はい、それは爆発します。
Matt Rogish 2009

わかりました、私はあなたのポイントを見始めています、しかし私はあなたによってこのシナリオを実行しなければなりません。データベースに国のルックアップテーブルをシードします。米国=>国ID = 1。次に、ユーザーは米国に存在するレストランを作成します。レストランのデータベース行のcountry_id = 1です。これは非常に一般的ですよね?後で国を追加することにしました...データベースをクリーンにワイプして国のルックアップテーブルに再入力すると、IDが同じでない限り、レストランの国は正確ではなくなります。これをどのように処理しますか?
トニー
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.