我有一個數組這樣保存活動記錄陣列
a = []
a << B.new(:name => "c")
a << B.new(:name => "s")
a << B.new(:name => "e")
a << B.new(:name => "t")
如何我可以將它保存在一次?
我有一個數組這樣保存活動記錄陣列
a = []
a << B.new(:name => "c")
a << B.new(:name => "s")
a << B.new(:name => "e")
a << B.new(:name => "t")
如何我可以將它保存在一次?
a.each(&:save)
這將調用B#save
陣列中的每個項目。
B.transaction do
a.each(&:save!)
end
這將創建一個事務,該事務遍歷數組的每個元素並調用element.save。
您可以在Rails和Ruby API中閱讀有關ActiveRecord Transactions和the each method的文章。
在事務中包裝save
將不夠用:如果未通過驗證,將不會引發異常,也不會引發回滾。
我可以建議是:
B.transaction do
a.each do |o|
raise ActiveRecord::Rollback unless o.save
end
end
只是做B.transaction do a.each(&:save!) end
是不是一種選擇,要麼,因爲事務塊不會拯救其他任何異常比ActiveRecord::Rollback
,應用程序會崩潰的驗證失敗。
我不知道如何檢查後,如果記錄已保存。
更新。正如有人downrated我的回答,我認爲這個人一直在尋找一個剪切和粘貼的解決方案:),所以這裏是一些(醜陋的:))的方式來處理失敗/成功值:
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
所以我認爲我們需要阿列克謝提出異議並中止交易和喬丹的單線解決方案。我提議:
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
這會給你一個位的兩個世界:通過滾動,它的知識記錄失敗的交易,甚至允許您訪問驗證錯誤在其中。
我知道這是一個老問題,但我驚訝的這個誰也沒有想到:
B.transaction do
broken = a.reject { |o| o.save }
raise ActiveRecord::Rollback if broken.present?
end
if broken.present?
# error message
end
你應該使用保存!而不是加薪。交易將處理剩下的事情。 – 2016-03-30 13:38:04
@ D.Wonnink是的,但它會短路進一步節省,所以你只會知道失敗的第一個,而不是所有的失敗。當你有30個對象保存在行中時,這可能會造成一個世界的不同,其中一半保存在行中,其中一半失敗,你必須以一種不會讓他重新發送表單15次來糾正15個錯誤的方式向用戶顯示驗證後來只是爲了學習另一件事情被打破;) – d4rky 2016-05-11 07:19:17
如果你正在尋找比節約每一行的循環請看看我的答案更有效的解決方案這裏Ruby on Rails - Import Data from a CSV file
我建議在那裏使用寶石activerecord-import
。
然後將其包裝在B.transaction中以將其全部保存在一個原子操作中。 – Farrel 2010-02-18 22:53:57
不要只是調用'save',要麼檢查返回值(true或false),要麼使用'.save!'讓rails在異常情況下引發異常! – reto 2013-05-16 14:15:18