save an active records array

前端 未结 6 812
梦如初夏
梦如初夏 2021-02-05 07:28

I have an array like this

a = []

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


        
相关标签:
6条回答
  • 2021-02-05 08:04
    B.transaction do
      a.each(&:save!)
    end
    

    This will create a transaction that loops through each element of the array and calls element.save on it.

    You can read about ActiveRecord Transactions and the each method in the Rails and Ruby APIs.

    0 讨论(0)
  • 2021-02-05 08:14
    a.each(&:save)
    

    This will call B#save on each item in the array.

    0 讨论(0)
  • 2021-02-05 08:14

    I know this is an old question but I'm suprised no one thought of this:

    B.transaction do
      broken = a.reject { |o| o.save }
      raise ActiveRecord::Rollback if broken.present?
    end
    
    if broken.present?
      # error message
    end
    
    0 讨论(0)
  • 2021-02-05 08:16

    So I think we need a middle ground to Alexey's raising exceptions and aborting the transaction and Jordan's one-liner solution. May I propose:

    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
    

    This will give you a bit of both worlds: a transaction with rollback, knowledge of which records failed and even gives you access to the validation errors therein.

    0 讨论(0)
  • 2021-02-05 08:23

    Wrapping save in transaction will not be enough: if a validation is not passed, there will be no exception raised and no rollback triggered.

    I can suggest this:

    B.transaction do
      a.each do |o|
        raise ActiveRecord::Rollback unless o.save
      end
    end
    

    Just doing B.transaction do a.each(&:save!) end is not an option either, because the transaction block will not rescue any exception other than ActiveRecord::Rollback, and the application would crash on failed validation.

    I do not know how to check afterwards if the records have been saved.


    Update. As someone has downrated my answer, i assume that the person was looking for a cut-and-paste solution :), so here is some (ugly :)) way to process fail/success value:

    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 讨论(0)
  • 2021-02-05 08:29

    In case you're looking for more efficient solution than save each row in the loop please look my answer here Ruby on Rails - Import Data from a CSV file

    I'm suggesting to use gem activerecord-import there.

    0 讨论(0)
提交回复
热议问题