Ответ 1
a.each(&:save)
Это вызовет B#save
для каждого элемента массива.
У меня есть массив вроде этого
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
Это создаст транзакцию, которая будет проходить через каждый элемент массива и вызовет элемент .save на нем.
Вы можете прочитать о транзакции ActiveRecord и каждый метод в Rails и Ruby API.
Итак, мне кажется, что нам нужен средний уровень для Алексея, который делает исключение и прерывает транзакцию и одностороннее решение 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
Это даст вам немного двух миров: транзакция с откатом, знание о том, какие записи не удалось, и даже дает вам доступ к ошибкам проверки.
Я знаю, что это старый вопрос, но я удивлен, что никто не думал об этом:
B.transaction do
broken = a.reject { |o| o.save }
raise ActiveRecord::Rollback if broken.present?
end
if broken.present?
# error message
end
Обертка 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
, и приложение потерпит крах при неудачной проверке.
Я не знаю, как проверить, если записи сохранены.
Update. Поскольку кто-то отказался от моего ответа, я предполагаю, что человек искал решение для вырезания и вставки:), поэтому вот какой-то (уродливый:)) способ обработки отказа/успеха:
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
Если вы ищете более эффективное решение, чем сохранение каждой строки в цикле, посмотрите мой ответ здесь Ruby on Rails - Импорт данных из CSV файла
Я предлагаю использовать gem activerecord-import
там.