ar-async-counter-cache 0.0.1 → 0.0.2
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 +68 -0
- data/VERSION +1 -1
- data/ar-async-counter-cache.gemspec +5 -4
- data/lib/ar-async-counter-cache.rb +3 -2
- data/lib/ar_async_counter_cache/active_record.rb +4 -17
- data/lib/ar_async_counter_cache/{resque_job.rb → increment_counters_job.rb} +6 -5
- data/pkg/ar-async-counter-cache-0.0.1.gem +0 -0
- data/spec/ar_async_counter_cache/active_record_spec.rb +1 -1
- data/spec/integration_spec.rb +2 -2
- data/spec/spec_helper.rb +1 -4
- metadata +5 -11
data/README
CHANGED
@@ -0,0 +1,68 @@
|
|
1
|
+
ar-async-counter-cache
|
2
|
+
----------------------
|
3
|
+
|
4
|
+
This gem allows you to update ActiveRecord counter cache columns
|
5
|
+
asynchronously. You may want to do this in situations where you want really
|
6
|
+
speedy inserts and have models that "belong_to" many different parents.
|
7
|
+
|
8
|
+
You use it like such:
|
9
|
+
|
10
|
+
class User < ActiveRecord::Base
|
11
|
+
has_many :comments
|
12
|
+
has_many :posts
|
13
|
+
end
|
14
|
+
|
15
|
+
class Post < ActiveRecord::Base
|
16
|
+
belongs_to :user, :async_counter_cache => true
|
17
|
+
has_many :comments
|
18
|
+
end
|
19
|
+
|
20
|
+
class Comment < ActiveRecord::Base
|
21
|
+
belongs_to :user, :async_counter_cache => true
|
22
|
+
belongs_to :post, :async_counter_cache => "count_of_comments"
|
23
|
+
end
|
24
|
+
|
25
|
+
Notice, you may specify the name of the counter cache column just as you can
|
26
|
+
with the normal belongs_to :counter_cache option. You also may not use both
|
27
|
+
the :async_counter_cache and :counter_cache options in the same belongs_to
|
28
|
+
call.
|
29
|
+
|
30
|
+
All you should need to do is require this gem in your project that uses
|
31
|
+
ActiveRecord and you should be good to go;
|
32
|
+
|
33
|
+
e.g. In your Gemfile:
|
34
|
+
|
35
|
+
gem 'ar-async-counter-cache', '0.0.1'
|
36
|
+
|
37
|
+
and then in RAILS_ROOT/config/environment.rb somewhere:
|
38
|
+
|
39
|
+
require 'ar-async-counter-cache'
|
40
|
+
|
41
|
+
This gem has built-in support for Resque (http://github.com/defunkt/resque).
|
42
|
+
Al you need is resque in your loadpath:
|
43
|
+
|
44
|
+
e.g. In your Gemfile:
|
45
|
+
|
46
|
+
gem 'resque', '1.9.4'
|
47
|
+
|
48
|
+
By default, the Resque job is placed on the :default queue:
|
49
|
+
|
50
|
+
@queue = :default
|
51
|
+
|
52
|
+
However, you can change this:
|
53
|
+
|
54
|
+
in RAILS_ROOT/config/environment.rb somewhere:
|
55
|
+
|
56
|
+
ArAsyncCounterCache.resque_job_queue = :low_priority
|
57
|
+
|
58
|
+
If you don't want to use Resque, you must define one instance method for your
|
59
|
+
models using ar-async-counter-cache:
|
60
|
+
|
61
|
+
e.g.:
|
62
|
+
|
63
|
+
Comment#async_increment_counters
|
64
|
+
|
65
|
+
That method should pass a message onto a queue for a background processor to
|
66
|
+
handle later. That background processor should call:
|
67
|
+
|
68
|
+
Comment#update_async_counters(:increment)
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.0.
|
1
|
+
0.0.2
|
@@ -5,7 +5,7 @@
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = %q{ar-async-counter-cache}
|
8
|
-
s.version = "0.0.
|
8
|
+
s.version = "0.0.2"
|
9
9
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
11
|
s.authors = ["Aaron Gibralter"]
|
@@ -22,7 +22,8 @@ Gem::Specification.new do |s|
|
|
22
22
|
"ar-async-counter-cache.gemspec",
|
23
23
|
"lib/ar-async-counter-cache.rb",
|
24
24
|
"lib/ar_async_counter_cache/active_record.rb",
|
25
|
-
"lib/ar_async_counter_cache/
|
25
|
+
"lib/ar_async_counter_cache/increment_counters_job.rb",
|
26
|
+
"pkg/ar-async-counter-cache-0.0.1.gem",
|
26
27
|
"spec/ar_async_counter_cache/active_record_spec.rb",
|
27
28
|
"spec/integration_spec.rb",
|
28
29
|
"spec/models.rb",
|
@@ -32,7 +33,7 @@ Gem::Specification.new do |s|
|
|
32
33
|
s.homepage = %q{http://github.com/agibralter/ar-async-counter-cache}
|
33
34
|
s.rdoc_options = ["--charset=UTF-8"]
|
34
35
|
s.require_paths = ["lib"]
|
35
|
-
s.rubygems_version = %q{1.3.
|
36
|
+
s.rubygems_version = %q{1.3.6}
|
36
37
|
s.summary = %q{Increment ActiveRecord's counter cache column asynchronously (using Resque).}
|
37
38
|
s.test_files = [
|
38
39
|
"spec/ar_async_counter_cache/active_record_spec.rb",
|
@@ -45,7 +46,7 @@ Gem::Specification.new do |s|
|
|
45
46
|
current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
|
46
47
|
s.specification_version = 3
|
47
48
|
|
48
|
-
if Gem::Version.new(Gem::
|
49
|
+
if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
|
49
50
|
s.add_runtime_dependency(%q<activerecord>, [">= 2.3.5"])
|
50
51
|
else
|
51
52
|
s.add_dependency(%q<activerecord>, [">= 2.3.5"])
|
@@ -1,10 +1,11 @@
|
|
1
|
+
require 'active_record'
|
2
|
+
|
1
3
|
begin
|
2
4
|
require 'resque'
|
3
|
-
require 'ar_async_counter_cache/
|
5
|
+
require 'ar_async_counter_cache/increment_counters_job'
|
4
6
|
rescue LoadError
|
5
7
|
end
|
6
8
|
|
7
|
-
require 'active_record'
|
8
9
|
require 'ar_async_counter_cache/active_record'
|
9
10
|
|
10
11
|
ActiveRecord::Base.send(:include, ArAsyncCounterCache::ActiveRecord)
|
@@ -9,13 +9,6 @@ module ArAsyncCounterCache
|
|
9
9
|
}.gsub(/\s+/, ' ').strip
|
10
10
|
end
|
11
11
|
|
12
|
-
def async_decrement_counters
|
13
|
-
raise %{
|
14
|
-
Since you don't have resque installed, please define #{self.class.to_s}#async_decrement_counters.
|
15
|
-
Basically it should queue a job that calls #{self.class.to_s}#update_async_counters(:decrement).
|
16
|
-
}.gsub(/\s+/, ' ').strip
|
17
|
-
end
|
18
|
-
|
19
12
|
def update_async_counters(dir, *parent_types)
|
20
13
|
(parent_types.empty? ? self.class.async_counter_types.keys : parent_types).each do |parent_type|
|
21
14
|
if (col = self.class.async_counter_types[parent_type]) && (parent = send(parent_type))
|
@@ -53,9 +46,9 @@ module ArAsyncCounterCache
|
|
53
46
|
def add_callbacks
|
54
47
|
# Define after_create callback method.
|
55
48
|
method_name = "belongs_to_async_counter_cache_after_create".to_sym
|
56
|
-
if defined?(ArAsyncCounterCache::
|
49
|
+
if defined?(ArAsyncCounterCache::IncrementCountersJob)
|
57
50
|
define_method(method_name) do
|
58
|
-
Resque.enqueue(ArAsyncCounterCache::
|
51
|
+
Resque.enqueue(ArAsyncCounterCache::IncrementCountersJob, self.class.to_s, self.id)
|
59
52
|
end
|
60
53
|
else
|
61
54
|
define_method(method_name) do
|
@@ -65,14 +58,8 @@ module ArAsyncCounterCache
|
|
65
58
|
after_create(method_name)
|
66
59
|
# Define before_destroy callback method.
|
67
60
|
method_name = "belongs_to_async_counter_cache_before_destroy".to_sym
|
68
|
-
|
69
|
-
|
70
|
-
Resque.enqueue(ArAsyncCounterCache::UpdateCountersJob, self.class.to_s, self.id, :decrement)
|
71
|
-
end
|
72
|
-
else
|
73
|
-
define_method(method_name) do
|
74
|
-
self.async_decrement_counters
|
75
|
-
end
|
61
|
+
define_method(method_name) do
|
62
|
+
update_async_counters(:decrement)
|
76
63
|
end
|
77
64
|
before_destroy(method_name)
|
78
65
|
end
|
@@ -1,25 +1,26 @@
|
|
1
1
|
module ArAsyncCounterCache
|
2
2
|
|
3
3
|
def self.resque_job_queue=(sym)
|
4
|
-
ArAsyncCounterCache::
|
4
|
+
ArAsyncCounterCache::IncrementCountersJob.class_eval do
|
5
5
|
@queue = sym
|
6
6
|
end
|
7
7
|
end
|
8
8
|
|
9
|
-
class
|
9
|
+
class IncrementCountersJob
|
10
10
|
@queue = :default
|
11
11
|
|
12
12
|
# Take advantage of resque-retry if possible.
|
13
13
|
begin
|
14
14
|
require 'resque-retry'
|
15
|
+
require 'active_record/base'
|
15
16
|
extend Resque::Plugins::ExponentialBackoff
|
16
|
-
@retry_exceptions = [ActiveRecord::RecordNotFound]
|
17
|
+
@retry_exceptions = [::ActiveRecord::RecordNotFound]
|
17
18
|
@backoff_strategy = [0, 10, 100]
|
18
19
|
rescue LoadError
|
19
20
|
end
|
20
21
|
|
21
|
-
def self.perform(klass_name, id
|
22
|
-
Object.const_get(klass_name).find(id).update_async_counters(
|
22
|
+
def self.perform(klass_name, id)
|
23
|
+
Object.const_get(klass_name).find(id).update_async_counters(:increment)
|
23
24
|
end
|
24
25
|
end
|
25
26
|
end
|
Binary file
|
@@ -16,7 +16,7 @@ describe ArAsyncCounterCache::ActiveRecord do
|
|
16
16
|
end
|
17
17
|
|
18
18
|
it "should queue job" do
|
19
|
-
Resque.should_receive(:enqueue).with(ArAsyncCounterCache::
|
19
|
+
Resque.should_receive(:enqueue).with(ArAsyncCounterCache::IncrementCountersJob, "Post", an_instance_of(Fixnum))
|
20
20
|
@user.posts.create(:body => "I have a cat!")
|
21
21
|
end
|
22
22
|
end
|
data/spec/integration_spec.rb
CHANGED
@@ -44,11 +44,11 @@ describe "integration" do
|
|
44
44
|
@post2.reload.count_of_comments.should == 1
|
45
45
|
end
|
46
46
|
|
47
|
-
it "should decrement
|
47
|
+
it "should decrement synchronously" do
|
48
|
+
perform_all_jobs
|
48
49
|
@comment1.destroy
|
49
50
|
@comment2.destroy
|
50
51
|
@comment3.destroy
|
51
|
-
perform_all_jobs
|
52
52
|
@user1.reload.posts_count.should == 2
|
53
53
|
@user1.reload.comments_count.should == 0
|
54
54
|
@user2.reload.posts_count.should == 0
|
data/spec/spec_helper.rb
CHANGED
@@ -1,13 +1,10 @@
|
|
1
1
|
spec_dir = File.expand_path(File.dirname(__FILE__))
|
2
|
-
|
3
|
-
$: << File.expand_path(File.join(File.dirname(__FILE__), '..', 'lib'))
|
4
|
-
$: << spec_dir
|
2
|
+
$:.unshift(File.expand_path(File.join(File.dirname(__FILE__), '..', 'lib')))
|
5
3
|
|
6
4
|
require 'rubygems'
|
7
5
|
# Ensure resque for tests.
|
8
6
|
require 'resque'
|
9
7
|
require 'ar-async-counter-cache'
|
10
|
-
|
11
8
|
require 'spec'
|
12
9
|
require 'models'
|
13
10
|
|
metadata
CHANGED
@@ -1,13 +1,12 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: ar-async-counter-cache
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash: 29
|
5
4
|
prerelease: false
|
6
5
|
segments:
|
7
6
|
- 0
|
8
7
|
- 0
|
9
|
-
-
|
10
|
-
version: 0.0.
|
8
|
+
- 2
|
9
|
+
version: 0.0.2
|
11
10
|
platform: ruby
|
12
11
|
authors:
|
13
12
|
- Aaron Gibralter
|
@@ -22,11 +21,9 @@ dependencies:
|
|
22
21
|
name: activerecord
|
23
22
|
prerelease: false
|
24
23
|
requirement: &id001 !ruby/object:Gem::Requirement
|
25
|
-
none: false
|
26
24
|
requirements:
|
27
25
|
- - ">="
|
28
26
|
- !ruby/object:Gem::Version
|
29
|
-
hash: 9
|
30
27
|
segments:
|
31
28
|
- 2
|
32
29
|
- 3
|
@@ -49,7 +46,8 @@ files:
|
|
49
46
|
- ar-async-counter-cache.gemspec
|
50
47
|
- lib/ar-async-counter-cache.rb
|
51
48
|
- lib/ar_async_counter_cache/active_record.rb
|
52
|
-
- lib/ar_async_counter_cache/
|
49
|
+
- lib/ar_async_counter_cache/increment_counters_job.rb
|
50
|
+
- pkg/ar-async-counter-cache-0.0.1.gem
|
53
51
|
- spec/ar_async_counter_cache/active_record_spec.rb
|
54
52
|
- spec/integration_spec.rb
|
55
53
|
- spec/models.rb
|
@@ -65,27 +63,23 @@ rdoc_options:
|
|
65
63
|
require_paths:
|
66
64
|
- lib
|
67
65
|
required_ruby_version: !ruby/object:Gem::Requirement
|
68
|
-
none: false
|
69
66
|
requirements:
|
70
67
|
- - ">="
|
71
68
|
- !ruby/object:Gem::Version
|
72
|
-
hash: 3
|
73
69
|
segments:
|
74
70
|
- 0
|
75
71
|
version: "0"
|
76
72
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
77
|
-
none: false
|
78
73
|
requirements:
|
79
74
|
- - ">="
|
80
75
|
- !ruby/object:Gem::Version
|
81
|
-
hash: 3
|
82
76
|
segments:
|
83
77
|
- 0
|
84
78
|
version: "0"
|
85
79
|
requirements: []
|
86
80
|
|
87
81
|
rubyforge_project:
|
88
|
-
rubygems_version: 1.3.
|
82
|
+
rubygems_version: 1.3.6
|
89
83
|
signing_key:
|
90
84
|
specification_version: 3
|
91
85
|
summary: Increment ActiveRecord's counter cache column asynchronously (using Resque).
|