Сохранить активный массив записей

У меня есть массив вроде этого

a = []

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

Как я могу сохранить его сразу?

Ответы

Ответ 1

a.each(&:save)

Это вызовет B#save для каждого элемента массива.

Ответ 2

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

Это создаст транзакцию, которая будет проходить через каждый элемент массива и вызовет элемент .save на нем.

Вы можете прочитать о транзакции ActiveRecord и каждый метод в Rails и Ruby API.

Ответ 3

Итак, мне кажется, что нам нужен средний уровень для Алексея, который делает исключение и прерывает транзакцию и одностороннее решение 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

Это даст вам немного двух миров: транзакция с откатом, знание о том, какие записи не удалось, и даже дает вам доступ к ошибкам проверки.

Ответ 4

Я знаю, что это старый вопрос, но я удивлен, что никто не думал об этом:

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

if broken.present?
  # error message
end

Ответ 5

Обертка 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

Ответ 6

Если вы ищете более эффективное решение, чем сохранение каждой строки в цикле, посмотрите мой ответ здесь Ruby on Rails - Импорт данных из CSV файла

Я предлагаю использовать gem activerecord-import там.