chrismuc-after_commit 0.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/README ADDED
@@ -0,0 +1,40 @@
1
+ after_commit
2
+ ============
3
+
4
+ After_commit enables you to add after_commit methods to ActiveRecord models, which are called once the transaction has been committed to the database.
5
+ Typically one needs this in asynchronous processing where you pass on IDs of new records to another thread or post them to a message queue. Using the stock after_XXX
6
+ callbacks you cannot be sure that the other thread/process is already seeing the new record (at least if the database is ACID compliant).
7
+
8
+
9
+ Usage:
10
+ ======
11
+
12
+ class Blog < ActiveRecord::Base
13
+ include AfterCommit::ActiveRecord
14
+
15
+ def after_commit_on_create
16
+ # do something
17
+ end
18
+
19
+ def after_commit_on_update
20
+ # do something
21
+ end
22
+
23
+ def after_commit_on_destroy
24
+ # do something
25
+ end
26
+ end
27
+
28
+
29
+ You have to include AfterCommit::ActiveRecord to add the new callbacks. They aren't automatically added to ActiveRecord::Base as tracking the committed
30
+ records takes a little overhead and I thought it's better to be able to manually select which models should get that feature.
31
+
32
+ You have to explicitely define the methods like in the example above, something like after_commit_on_create :do_what_ever doesn't work.
33
+
34
+ Credits:
35
+ ========
36
+ I've take existing code and basically made it threadsafe (hopefully, so it should be safe when running config.threadsafe!). Sources are:
37
+
38
+ http://github.com/GUI/after_commit/tree/master
39
+ http://github.com/freelancing-god/thinking-sphinx
40
+
@@ -0,0 +1,85 @@
1
+ module AfterCommit
2
+ def self.touched_records(type)
3
+ h = (Thread.current[:after_commit] ||= {})
4
+ h[type] ||= []
5
+ end
6
+
7
+ def self.clear
8
+ Thread.current[:after_commit] = nil
9
+ end
10
+
11
+ def self.trigger
12
+ begin
13
+ [:create, :update, :destroy].each do |type|
14
+ callback_name = "after_commit_on_#{type}"
15
+ touched_records(type).each do |record|
16
+ begin
17
+ record.send(callback_name) if record.respond_to?(callback_name)
18
+ rescue => e
19
+ puts e
20
+ end
21
+ end
22
+ end
23
+ ensure
24
+ self.clear
25
+ end
26
+ end
27
+
28
+ module ActiveRecord
29
+ def self.included(base)
30
+ base.class_eval do
31
+ after_create :add_touched_record_on_create
32
+ after_update :add_touched_record_on_update
33
+ after_destroy :add_touched_record_on_destroy
34
+
35
+ def add_touched_record_on_create
36
+ AfterCommit.touched_records(:create) << self
37
+ end
38
+
39
+ def add_touched_record_on_update
40
+ AfterCommit.touched_records(:update) << self
41
+ end
42
+
43
+ def add_touched_record_on_destroy
44
+ AfterCommit.touched_records(:destroy) << self
45
+ end
46
+ end
47
+ end
48
+ end
49
+
50
+ module ConnectionAdapters
51
+ def self.included(base)
52
+ base.class_eval do
53
+ # The commit_db_transaction method gets called when the outermost
54
+ # transaction finishes and everything inside commits. We want to
55
+ # override it so that after this happens, any records that were saved
56
+ # or destroyed within this transaction now get their after_commit
57
+ # callback fired.
58
+ def commit_db_transaction_with_callback
59
+ commit_db_transaction_without_callback
60
+ AfterCommit.trigger
61
+ end
62
+ alias_method_chain :commit_db_transaction, :callback
63
+
64
+ def rollback_db_transaction_with_callback
65
+ rollback_db_transaction_without_callback
66
+ AfterCommit.clear
67
+ end
68
+ alias_method_chain :rollback_db_transaction, :callback
69
+ end
70
+ end
71
+ end
72
+ end
73
+
74
+ unless defined? AFTER_COMMIT_PATCH_APPLIED
75
+ AFTER_COMMIT_PATCH_APPLIED=true # in my test setup this was executed twice resulting in an infinite recursion
76
+
77
+ Object.subclasses_of(ActiveRecord::ConnectionAdapters::AbstractAdapter).each do |klass|
78
+ puts "Applying after_commit patch to: #{klass}"
79
+ klass.send(:include, AfterCommit::ConnectionAdapters)
80
+ end
81
+
82
+ if defined?(JRUBY_VERSION) and defined?(JdbcSpec::MySQL)
83
+ JdbcSpec::MySQL.send :include, AfterCommit::ConnectionAdapters
84
+ end
85
+ end
@@ -0,0 +1,46 @@
1
+ $LOAD_PATH.unshift(File.dirname(__FILE__) + '/../lib')
2
+ require 'test/unit'
3
+ require 'rubygems'
4
+ require 'activerecord'
5
+
6
+ ActiveRecord::Base.establish_connection({"adapter" => defined?(JRUBY_VERSION) ? "jdbcsqlite3":"sqlite3", "database" => 'test.sqlite3'})
7
+ begin
8
+ ActiveRecord::Base.connection.execute("drop table mock_records");
9
+ rescue
10
+ end
11
+ ActiveRecord::Base.connection.execute("create table mock_records(id int)");
12
+
13
+ require File.dirname(__FILE__) + '/../init.rb'
14
+
15
+ class MockRecord < ActiveRecord::Base
16
+ include AfterCommit::ActiveRecord
17
+ attr_accessor :after_commit_on_create_called, :after_commit_on_update_called, :after_commit_on_destroy_called
18
+
19
+ def after_commit_on_create
20
+ self.after_commit_on_create_called = true
21
+ end
22
+
23
+ def after_commit_on_update
24
+ self.after_commit_on_update_called = true
25
+ end
26
+
27
+ def after_commit_on_destroy
28
+ self.after_commit_on_destroy_called = true
29
+ end
30
+ end
31
+
32
+ class AfterCommitTest < Test::Unit::TestCase
33
+ def test_after_commit_on_create_is_called
34
+ assert_equal true, MockRecord.create!.after_commit_on_create_called
35
+ end
36
+
37
+ def test_after_commit_on_update_is_called
38
+ record = MockRecord.create!
39
+ record.save
40
+ assert_equal true, record.after_commit_on_update_called
41
+ end
42
+
43
+ def test_after_commit_on_destroy_is_called
44
+ assert_equal true, MockRecord.create!.destroy.after_commit_on_destroy_called
45
+ end
46
+ end
metadata ADDED
@@ -0,0 +1,55 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: chrismuc-after_commit
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.9.0
5
+ platform: ruby
6
+ authors:
7
+ - Christian Seiler
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2009-06-02 00:00:00 -07:00
13
+ default_executable:
14
+ dependencies: []
15
+
16
+ description: Threadsafe after_commit callbacks for ActiveRecord models.
17
+ email: chr.seiler@gmail.com
18
+ executables: []
19
+
20
+ extensions: []
21
+
22
+ extra_rdoc_files: []
23
+
24
+ files:
25
+ - README
26
+ - test/after_commit_test.rb
27
+ - lib/after_commit.rb
28
+ has_rdoc: false
29
+ homepage: http://github.com/mislav/will_paginate/wikis
30
+ post_install_message:
31
+ rdoc_options: []
32
+
33
+ require_paths:
34
+ - lib
35
+ required_ruby_version: !ruby/object:Gem::Requirement
36
+ requirements:
37
+ - - ">="
38
+ - !ruby/object:Gem::Version
39
+ version: "0"
40
+ version:
41
+ required_rubygems_version: !ruby/object:Gem::Requirement
42
+ requirements:
43
+ - - ">="
44
+ - !ruby/object:Gem::Version
45
+ version: "0"
46
+ version:
47
+ requirements: []
48
+
49
+ rubyforge_project:
50
+ rubygems_version: 1.2.0
51
+ signing_key:
52
+ specification_version: 2
53
+ summary: Threadsafe after_commit callbacks for ActiveRecord models
54
+ test_files:
55
+ - test/after_commit_test.rb