Reputation: 2088
I have a transaction like this
def accept_transaction
Purchase.transaction do
save! #Validate and Save purchase
product.update_bought
user.charge!(product.price)
Investment.add_spent(user_id: user.id,
spent: product.price)
end
What I would like to accomplish is add corresponding error messages to the Errors
object if the transaction is not completed. So the desired method would look something like
def accept_transaction
Purchase.transaction do
save! #Validate and Save purchase(adds validation errors by default)
add_out_of_stock_error unless product.update_bought
add_no_money_error unless user.charge!(product.price)
other_error unless Investment.add_spent(user_id: user.id,
spent: product.price)
end
def add_out_of_stock_error
errors[:base].add("Product not available")
end
def no_money_error
...
end
def other_error
...
end
Right now I can't get the desired result, those actions, in case of a failure, raise ActiveRecord::Rollback
error and don't trigger error methods.
Upvotes: 1
Views: 1205
Reputation: 2088
The solution I came up with (also thanks to @lcguida). Is a somewhat simple one
def accept_transaction
Purchase.transaction do
save! #Validate and Save purchase(adds validation errors by default)
catch_out_of_stock_error { product.update_bought }
catch_no_money_error { user.charge!(product.price) }
catch_other_error { Investment.add_spent(user_id: user.id,
spent: product.price) }
end
def catch_out_of_stock_error &block
begin
yield
rescue ActiveRecord::Rollback => e
errors.add(:base,"Product not available")
raise e
end
end
def catch_no_money_error &block
...
end
def catch_other_error &block
...
end
The idea being that for each error I have a separate method, where I pass in the method that can cause the error. Then I rescue from ActiveRecord::Rollback
in an isolated environment, append error and re-raise the same error.
Please post another answer if there is something easier/better.
Upvotes: 1
Reputation: 135
It sounds like you want to use save
and not save!
save!
raises an exception if the validations fail
http://apidock.com/rails/ActiveRecord/Base/save!
save
returns false
http://apidock.com/rails/ActiveRecord/Base/save
so you can do:
unless save
# add errors
end
but note both rollback the transaction.
Upvotes: 1