web-dev-qa-db-ja.com

新しいシードデータを既存のRailsデータベースに追加する方法

一部のテストおよびステージングシステムとさまざまな開発者ワークステーションに既にデプロイされているアプリケーションに取り組んでいます。追加の参照データを追加する必要がありますが、追加する方法がわかりません。

ほとんどのアドバイスは、seed.rbを使用すると述べていますが、私の理解では、これはアプリケーションが最初にデプロイされたときに一度だけ実行されるということです。 1行の参照データを追加できるようにテストデータベースとステージングデータベースを再構築したくないので、データを追加する別の方法はありますか?

私はdbマイグレーションの使用を考えています、これは正しいアプローチですか?

ありがとう

20
toby

継続的にデータを作成および更新できるように、seed.rbファイルを構造化します。シードファイルを実行するのは1回だけに限られているわけではなく、シードファイルが初期展開にのみ使用されていると思われる場合、参照データを設定する際に提供できる柔軟性を逃してしまいます。

シードファイルは単なるRubyなので、次のようなことができます。

user = User.find_or_initialize_by(email: '[email protected]')
user.name = 'Bob'
user.password = 'secret'
user.role = 'manager'
user.save!

これにより、存在しない場合は新しいデータが作成され、データが見つかった場合は更新されます。

シードファイルを正しく構造化すると、依存オブジェクトを作成および更新することもできます。

オブジェクトを保存できない場合に例外が発生するように、bang saveを使用することをお勧めします。これは、シードをデバッグする最も簡単な方法です。

seedbank gem を使用して、環境ごとの設定データ、依存するシードなど、シードデータにより多くの構造を提供します。

シードデータの移行を使用することはお勧めしません。柔軟性が欠如しており(たとえば、シードデータを1つの環境だけにターゲティングする方法)、特定の環境を更新するためにいつでも実行できる再利用可能なデータのセットを構築する実際の方法はありません。また、スキーマを参照しない一連の移行があり、新しいデータを生成したり現在のデータを変更したりするたびに、新しい移行を作成する必要があります。

29
nmott

Seed.rbまたはseed.rbによって呼び出される別のタスクで、次のようなべき等メソッドを使用するのが最善です。

Contact.find_by_email("[email protected]") || Contact.create(email: "[email protected]", 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("[email protected]").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
konyak

移行を使用することもできますが、これは最も安全な方法ではありません。たとえば、移行によってテーブルにレコードを追加し、将来そのテーブルのスキーマを変更するとします。アプリをどこかにインストールすると、rake db:migrateを実行できなくなります。

完全に移行されたスキーマでrake db:seedを実行できるため、シードは常に推奨されます。

単なる記録の場合は、Rails consoleを使用してください。

2
Miotsu

シードファイルを使用して、常に新しいテーブルまたは既存のテーブルにインスタンスを追加します。私の解決策は簡単です。新しいシードデータだけがライブコードになるように、db/seeds.rbファイル内の他のすべてのシードデータをコメント化します。次に、bin/rake db:seedを実行します。

1
Steve Carey

私は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
Jaga Jugue

新しいデータベースのシードに使用するseeds.dbを変更する代わりに、カスタムRakeタスク( RailsCast#66カスタムRakeタスク )を作成できます。

必要な数のRakeタスクを作成できます。たとえば、2つのサーバーがあり、1つはアプリのバージョン1.0を実行し、もう1つは1.1を実行していて、両方を1.2にアップグレードするとします。その後、lib/tasks/1-0-to-1-2.rakelib/tasks`1-1-to-1-2.rakeを作成できます。これは、アプリのバージョンによって異なるコードが必要になる場合があるためです。

0
ehannes