Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fixed a bug #2

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
75 changes: 67 additions & 8 deletions lib/after_commit.rb
Original file line number Diff line number Diff line change
@@ -1,33 +1,92 @@
require 'rubygems'
require 'ruby-debug'
Debugger.start
module AfterCommit
@@records = {}
@@records_queue = []

@@record_methods = {
:all => :committed_records,
:create => :committed_records_on_create,
:update => :committed_records_on_update,
:destroy => :committed_records_on_destroy
}

@@callback_methods = {
:all => :after_commit_callback,
:create => :after_commit_on_create_callback,
:update => :after_commit_on_update_callback,
:destroy => :after_commit_on_destroy_callback
}

def self.records
@@records
end

# Push a new variable holder onto our stack.
def self.push
@@records_queue.push @@records
@@records = {}
end

def self.pop
@@records = @@records_queue.pop
end

# Send callbacks of this type after a commit.
# We push a new variable holder on each record, then pop it off, which avoids
# an infinite loop whereby an on_commit callback makes a new transaction
# (like in creating a BackgrounDRb record)
def self.callback(crud_method, &block)
record_method = @@record_methods[crud_method]
callback_method = @@callback_methods[crud_method]
committed_records = send(record_method)

unless committed_records.empty?
committed_records.each do |record|
push
record.send(callback_method)
pop
end
end

records[crud_method] = []
end

def self.clear!
@@records = {}
@@records_queue = []
end

def self.committed_records
@@committed_records ||= []
records[:all] ||= []
end

def self.committed_records=(committed_records)
@@committed_records = committed_records
records[:all] = committed_records
end

def self.committed_records_on_create
@@committed_records_on_create ||= []
records[:create] ||= []
end

def self.committed_records_on_create=(committed_records)
@@committed_records_on_create = committed_records
records[:create] = committed_records
end

def self.committed_records_on_update
@@committed_records_on_update ||= []
records[:update] ||= []
end

def self.committed_records_on_update=(committed_records)
@@committed_records_on_update = committed_records
records[:update] = committed_records
end

def self.committed_records_on_destroy
@@committed_records_on_destroy ||= []
records[:destroy] ||= []
end

def self.committed_records_on_destroy=(committed_records)
@@committed_records_on_destroy = committed_records
records[:destroy] = committed_records
end
end
68 changes: 7 additions & 61 deletions lib/after_commit/connection_adapters.rb
Original file line number Diff line number Diff line change
Expand Up @@ -21,80 +21,26 @@ def commit_db_transaction_with_callback
def rollback_db_transaction_with_callback
rollback_db_transaction_without_callback

AfterCommit.committed_records = []
AfterCommit.committed_records_on_create = []
AfterCommit.committed_records_on_update = []
AfterCommit.committed_records_on_destroy = []
AfterCommit.clear!
end
alias_method_chain :rollback_db_transaction, :callback

protected
protected

def trigger_after_commit_callbacks
# Trigger the after_commit callback for each of the committed
# records.
if AfterCommit.committed_records.any?
AfterCommit.committed_records.each do |record|
begin
record.after_commit_callback
rescue
end
end
end

# Make sure we clear out our list of committed records now that we've
# triggered the callbacks for each one.
AfterCommit.committed_records = []
AfterCommit.callback(:all)
end

def trigger_after_commit_on_create_callbacks
# Trigger the after_commit_on_create callback for each of the committed
# records.
if AfterCommit.committed_records_on_create.any?
AfterCommit.committed_records_on_create.each do |record|
begin
record.after_commit_on_create_callback
rescue
end
end
end

# Make sure we clear out our list of committed records now that we've
# triggered the callbacks for each one.
AfterCommit.committed_records_on_create = []
AfterCommit.callback(:create)
end

def trigger_after_commit_on_update_callbacks
# Trigger the after_commit_on_update callback for each of the committed
# records.
if AfterCommit.committed_records_on_update.any?
AfterCommit.committed_records_on_update.each do |record|
begin
record.after_commit_on_update_callback
rescue
end
end
end

# Make sure we clear out our list of committed records now that we've
# triggered the callbacks for each one.
AfterCommit.committed_records_on_update = []
AfterCommit.callback(:update)
end

def trigger_after_commit_on_destroy_callbacks
# Trigger the after_commit_on_destroy callback for each of the committed
# records.
if AfterCommit.committed_records_on_destroy.any?
AfterCommit.committed_records_on_destroy.each do |record|
begin
record.after_commit_on_destroy_callback
rescue
end
end
end

# Make sure we clear out our list of committed records now that we've
# triggered the callbacks for each one.
AfterCommit.committed_records_on_destroy = []
AfterCommit.callback(:destroy)
end
#end protected
end
Expand Down
33 changes: 29 additions & 4 deletions test/after_commit_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -8,31 +8,53 @@

ActiveRecord::Base.establish_connection({"adapter" => "sqlite3", "database" => 'test.sqlite3'})
begin
ActiveRecord::Base.connection.execute("drop table mock_records");
ActiveRecord::Base.connection.execute("drop table mock_records")
ActiveRecord::Base.connection.execute("drop table mock_non_callbacks")
rescue
end
ActiveRecord::Base.connection.execute("create table mock_records(id int)");
ActiveRecord::Base.connection.execute("create table mock_records(id int)")
ActiveRecord::Base.connection.execute("create table mock_non_callbacks(id int)")

require File.dirname(__FILE__) + '/../init.rb'

class MockNonCallback < ActiveRecord::Base; end

class MockRecord < ActiveRecord::Base
attr_accessor :after_commit_called
attr_accessor :after_commit_on_create_called
attr_accessor :after_commit_on_update_called
attr_accessor :after_commit_on_destroy_called

def clear_flags
@after_commit_called = @after_commit_on_create_called = @after_commit_on_update_called = @after_commit_on_destroy_called = nil
end

after_commit :do_commit
def do_commit
raise "Re-called on commit!" if self.after_commit_called
self.after_commit_called = true
MockNonCallback.transaction{ MockNonCallback.create! }
end

after_commit_on_create :do_create
def do_create
raise "Re-called on create!" if self.after_commit_on_create_called
self.after_commit_on_create_called = true
MockNonCallback.transaction{ MockNonCallback.create! }
end

after_commit_on_update :do_update
def do_update
raise "Re-called on update!" if self.after_commit_on_update_called
self.after_commit_on_update_called = true
MockNonCallback.transaction{ MockNonCallback.create! }
end

after_commit_on_create :do_destroy
after_commit_on_destroy :do_destroy
def do_destroy
raise "Re-called on destroy!" if self.after_commit_on_destroy_called
self.after_commit_on_destroy_called = true
MockNonCallback.transaction{ MockNonCallback.create! }
end
end

Expand All @@ -43,11 +65,14 @@ def test_after_commit_on_create_is_called

def test_after_commit_on_update_is_called
record = MockRecord.create!
record.clear_flags
record.save
assert_equal true, record.after_commit_on_update_called
end

def test_after_commit_on_destroy_is_called
assert_equal true, MockRecord.create!.destroy.after_commit_on_destroy_called
record = MockRecord.create!
record.clear_flags
assert_equal true, record.destroy.after_commit_on_destroy_called
end
end