16


5

アクティブなレコード配列を保存する

私はこのような配列を持っています

a = []

a << B.new(:name => "c")
a << B.new(:name => "s")
a << B.new(:name => "e")
a << B.new(:name => "t")

一度に保存するにはどうすればよいですか?

6 Answer


43


B.transaction do
  a.each(&:save!)
end

これにより、配列の各要素をループしてelement.saveを呼び出すトランザクションが作成されます。

ActiveRecord Transactionsおよびhttp://ruby-doc.org/core/classes/Array.html#M002173 [それぞれメソッド] RailsおよびRuby API。


24


a.each(&:save)

これにより、配列内の各項目で「B#save」が呼び出されます。


9


だから、Alexeyが例外を提起し、トランザクションとJordanのワンライナーソリューションを中止するための妥協点が必要だと思います。 提案してもいいですか:

B.transaction do
  success = a.map(&:save)
  unless success.all?
    errored = a.select{|b| !b.errors.blank?}
    # do something with the errored values
    raise ActiveRecord::Rollback
  end
end

これにより、両方の世界が少し得られます。ロールバックを伴うトランザクション、どのレコードが失敗したかを知ることができ、検証エラーにアクセスすることさえできます。


2


私はこれが古い質問であることを知っていますが、これについて誰も考えなかったことに驚いています:

B.transaction do
  broken = a.reject { |o| o.save }
  raise ActiveRecord::Rollback if broken.present?
end

if broken.present?
  # error message
end


0


トランザクションで「保存」をラップするだけでは十分ではありません。検証に合格しなければ、例外は発生せず、ロールバックはトリガーされません。

私はこれを提案することができます:

B.transaction do
  a.each do |o|
    raise ActiveRecord::Rollback unless o.save
  end
end
「B.transaction do a.each(&:save!)end」を実行するだけでもオプションではありません。トランザクションブロックは「ActiveRecord

Rollback」以外の例外をレスキューせず、検証に失敗するとアプリケーションがクラッシュするためです。 。

記録が保存されているかどうかを後で確認する方法がわかりません。

'' '' '

更新。 誰かが私の答えをダウンレートしたので、私はその人がカットアンドペーストのソリューションを探していたと思います:)、ここに失敗/成功値を処理するいくつかの(ugい:))方法があります:

save_failed = nil
B.transaction do
  a.each do |o|
    unless o.save
      save_failed = true
      raise ActiveRecord::Rollback
    end
  end
end
if save_failed
  # ...
else
  # ...
end


0


ループ内の各行を保存するよりも効率的なソリューションを探している場合は、https://stackoverflow.com/questions/4410794/ruby-on-rails-import-data-from-a-csv-で私の答えを見てくださいfile / 48039184#48039184 [Ruby on Rails-CSVファイルからデータをインポート]

そこでgem 'activerecord-import`を使用することをお勧めします。