Reputation: 709
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.
Upvotes: 0
Views: 89
Reputation: 3347
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
Upvotes: 1