简体   繁体   中英

Capture all errors in form and ensure atomicity -rails

I want to capture all the errors in a form and also ensure that the operation is atomic that is the form goes through if there are no errors else it just captures the error and no other correct fields are saved.

ActiveRecord::Base.transaction do
    @var_types.each_with_index do |var,index|
          begin
            var.save!
            puts "saving"
          rescue
            puts "rescued"
          end
    end

I am using the above block, although this captures all the errors in but atomicity is not guarenteed. Any way to correct this?

EDIT:

Example An example would be say something like a form where a user has to enter multiple fields and multiple fields may not conform to the db rules, so i expect all the errors to be shown at once so the save as to keep happening to get all the errors but at the same time ensure that no correct changes get saved if there is even one error.

You have to catch the exception outside the transaction.

The transactions are rollbacked when an exception goes out the transaction block

begin
  ActiveRecord::Base.transaction do
    @var_types.each_with_index do |var,index|
      var.save!
      puts "saving"
    end
  end
rescue
  puts "rescued"
end

UPDATE after reading your comment:

ActiveRecord::Base.transaction do
  raise ActiveRecord::Rollback unless @var_types.map(&:save).all? #passing here a block like { |res| res == true } is redundant.
  redirect_to some_index_path, notice: "Everything saved"
end

render action: 'edit' # something didn't pass the validation, re-render the view

Things to note here: If you raise ActiveRecord::Rollback inside a transaction block, you don't need a rescue for it (read the docs at http://api.rubyonrails.org/classes/ActiveRecord/Rollback.html )

Someone might say that you should not drive the flow based in exception-throwing, if you don't feel comfortable with it, you can do something like this:

all_saved = false # need to define this var outside, or it will a block-level variable, visible only in the block
ActiveRecord::Base.transaction do
  all_saved = @var_types.map(&:save).all?
  raise ActiveRecord::Rollback unless all_saved
end

if all_saved
  redirect_to some_index_path, notice: "Everything saved"
else
  render action: 'edit' # something didn't pass the validation, re-render the view
end

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM