1
0
Fork 0
mirror of https://github.com/aasm/aasm synced 2023-03-27 23:22:41 -04:00

Fix :after_commit within nested transaction

This commit is contained in:
Sergey Tokarenko 2020-02-18 08:03:50 +03:00 committed by Anil Kumar Maurya
parent f7231d1c31
commit d66fccca72
4 changed files with 63 additions and 18 deletions

View file

@ -17,6 +17,7 @@ Gem::Specification.new do |s|
s.required_ruby_version = '>= 1.9.3'
s.add_dependency 'concurrent-ruby', '~> 1.0'
s.add_dependency 'after_commit_action', '~> 1.0'
s.add_development_dependency 'rake'
s.add_development_dependency 'sdoc'

View file

@ -1,3 +1,4 @@
require 'after_commit_action'
require 'aasm/persistence/orm'
module AASM
module Persistence
@ -28,6 +29,7 @@ module AASM
# end
#
def self.included(base)
base.send(:include, ::AfterCommitAction) unless base.include?(::AfterCommitAction)
base.send(:include, AASM::Persistence::Base)
base.send(:include, AASM::Persistence::ORM)
base.send(:include, AASM::Persistence::ActiveRecordPersistence::InstanceMethods)
@ -88,6 +90,12 @@ module AASM
end
end
def aasm_execute_after_commit
execute_after_commit do
yield
end
end
def aasm_enum(name=:default)
case AASM::StateMachineStore.fetch(self.class, true).machine(name).config.enum
when false then nil

View file

@ -81,6 +81,10 @@ module AASM
true
end
def aasm_execute_after_commit
yield
end
def aasm_write_state_attribute(state, name=:default)
aasm_write_attribute(self.class.aasm(name).attribute_name, aasm_raw_attribute_value(state, name))
end
@ -116,32 +120,32 @@ module AASM
# Returns true if event was fired successfully and transaction completed.
def aasm_fire_event(state_machine_name, name, options, *args, &block)
if aasm_supports_transactions? && options[:persist]
event = self.class.aasm(state_machine_name).state_machine.events[name]
event.fire_callbacks(:before_transaction, self, *args)
event.fire_global_callbacks(:before_all_transactions, self, *args)
return super unless aasm_supports_transactions? && options[:persist]
begin
success = if options[:persist] && use_transactions?(state_machine_name)
aasm_transaction(requires_new?(state_machine_name), requires_lock?(state_machine_name)) do
super
end
else
event = self.class.aasm(state_machine_name).state_machine.events[name]
event.fire_callbacks(:before_transaction, self, *args)
event.fire_global_callbacks(:before_all_transactions, self, *args)
begin
success = if options[:persist] && use_transactions?(state_machine_name)
aasm_transaction(requires_new?(state_machine_name), requires_lock?(state_machine_name)) do
super
end
else
super
end
if success
if success
aasm_execute_after_commit do
event.fire_callbacks(:after_commit, self, *args)
event.fire_global_callbacks(:after_all_commits, self, *args)
end
success
ensure
event.fire_callbacks(:after_transaction, self, *args)
event.fire_global_callbacks(:after_all_transactions, self, *args)
end
else
super
success
ensure
event.fire_callbacks(:after_transaction, self, *args)
event.fire_global_callbacks(:after_all_transactions, self, *args)
end
end

View file

@ -613,6 +613,38 @@ if defined?(ActiveRecord)
expect(validator).to be_running
expect(validator.name).to eq("name")
end
context "nested transaction" do
it "should fire :after_commit if root transaction was successful" do
validator = Validator.create(:name => 'name')
expect(validator).to be_sleeping
validator.transaction do
validator.run!
expect(validator.name).to eq("name")
expect(validator).to be_running
end
expect(validator.name).to eq("name changed")
expect(validator.reload).to be_running
end
end
it "should not fire :after_commit if root transaction failed" do
validator = Validator.create(:name => 'name')
expect(validator).to be_sleeping
validator.transaction do
validator.run!
expect(validator.name).to eq("name")
expect(validator).to be_running
raise ActiveRecord::Rollback, "failed on purpose"
end
expect(validator.name).to eq("name")
expect(validator.reload).to be_sleeping
end
end
describe 'before and after transaction callbacks' do