ar-resque-counter-cache 2.1.0 → 3.0.0.rc1

Sign up to get free protection for your applications and to get access to all the features.
@@ -4,7 +4,7 @@ require "ar-resque-counter-cache/version"
4
4
 
5
5
  Gem::Specification.new do |s|
6
6
  s.name = "ar-resque-counter-cache"
7
- s.version = ArAsyncCounterCache::VERSION
7
+ s.version = ArResqueCounterCache::VERSION
8
8
  s.platform = Gem::Platform::RUBY
9
9
  s.authors = ["Aaron Gibralter"]
10
10
  s.email = ["aaron.gibralter@gmail.com"]
@@ -1,5 +1,3 @@
1
1
  require 'active_record'
2
2
  require 'ar-resque-counter-cache/increment_counters_worker'
3
3
  require 'ar-resque-counter-cache/active_record'
4
-
5
- ActiveRecord::Base.send(:include, ArAsyncCounterCache::ActiveRecord)
@@ -1,72 +1,130 @@
1
- module ArAsyncCounterCache
1
+ module ArResqueCounterCache
2
2
 
3
3
  module ActiveRecord
4
4
 
5
- def update_async_counters(dir, *association_ids)
6
- association_ids.each do |association_id|
7
- reflection = self.class.reflect_on_association(association_id)
8
- parent_class = reflection.klass
9
- column = self.class.async_counter_types[association_id]
10
- if parent_id = send(reflection.foreign_key)
11
- ArAsyncCounterCache::IncrementCountersWorker.cache_and_enqueue(parent_class, parent_id, column, dir)
5
+ ORIG_BT = ::ActiveRecord::Associations::BelongsToAssociation
6
+ ORIG_BTP = ::ActiveRecord::Associations::BelongsToPolymorphicAssociation
7
+
8
+ module Associations
9
+
10
+ module AsyncUpdateCounters
11
+ def update_counters_with_async(record)
12
+ # TODO make async?
13
+ update_counters_without_async(record)
12
14
  end
13
- end
14
- end
15
15
 
16
- module ClassMethods
17
-
18
- def belongs_to(association_id, options={})
19
- column = async_counter_cache_column(options.delete(:async_counter_cache))
20
- raise "Please don't use both async_counter_cache and counter_cache." if column && options[:counter_cache]
21
- super(association_id, options)
22
- if column
23
- # Store the async_counter_cache column for the update_async_counters
24
- # helper method.
25
- self.async_counter_types[association_id] = column
26
- # Fetch the reflection.
27
- reflection = self.reflect_on_association(association_id)
28
- parent_class = reflection.klass
29
- # Let's make the column read-only like the normal belongs_to
30
- # counter_cache.
31
- parent_class.send(:attr_readonly, column.to_sym) if defined?(parent_class) && parent_class.respond_to?(:attr_readonly)
32
- parent_id_column = reflection.foreign_key
33
- add_callbacks(parent_class.to_s, parent_id_column, column)
16
+ def self.included(base)
17
+ base.class_eval do
18
+ alias_method_chain :update_counters, :async
19
+ end
34
20
  end
35
21
  end
36
22
 
37
- def async_counter_types
38
- @async_counter_types ||= {}
23
+ class AsyncBelongsToAssociation < ORIG_BT
24
+ include AsyncUpdateCounters
39
25
  end
40
26
 
41
- private
27
+ class AsyncBelongsToPolymorphicAssociation < ORIG_BTP
28
+ include AsyncUpdateCounters
29
+ end
30
+ end
42
31
 
43
- def add_callbacks(parent_class, parent_id_column, column)
44
- base_method_name = "async_counter_cache_#{parent_class}_#{column}"
45
- # Define after_create callback method.
46
- method_name = "#{base_method_name}_after_create".to_sym
47
- define_method(method_name) do
48
- if parent_id = send(parent_id_column)
49
- ArAsyncCounterCache::IncrementCountersWorker.cache_and_enqueue(parent_class, parent_id, column, :increment)
32
+ module AssociationReflectionTweaks
33
+ def association_class_with_async
34
+ if macro == :belongs_to && options[:async_counter_cache]
35
+ if options[:polymorphic]
36
+ Associations::AsyncBelongsToPolymorphicAssociation
37
+ else
38
+ Associations::AsyncBelongsToAssociation
50
39
  end
40
+ else
41
+ association_class_without_async
51
42
  end
52
- after_commit(method_name, :on => :create)
53
- # Define after_destroy callback method.
54
- method_name = "#{base_method_name}_after_destroy".to_sym
55
- define_method(method_name) do
56
- if parent_id = send(parent_id_column)
57
- ArAsyncCounterCache::IncrementCountersWorker.cache_and_enqueue(parent_class, parent_id, column, :decrement)
58
- end
43
+ end
44
+
45
+ def counter_cache_column_with_async
46
+ if options[:async_counter_cache] == true
47
+ "#{active_record.name.demodulize.underscore.pluralize}_count"
48
+ elsif options[:async_counter_cache]
49
+ options[:async_counter_cache].to_s
50
+ else
51
+ counter_cache_column_without_async
59
52
  end
60
- after_commit(method_name, :on => :destroy)
61
53
  end
62
54
 
63
- def async_counter_cache_column(opt)
64
- opt === true ? "#{self.table_name}_count" : opt
55
+ def self.included(base)
56
+ base.class_eval do
57
+ alias_method_chain :association_class, :async
58
+ alias_method_chain :counter_cache_column, :async
59
+ end
65
60
  end
66
61
  end
67
62
 
68
- def self.included(base)
69
- base.extend(ClassMethods)
63
+ module AsyncBuilderBehavior
64
+ def build_with_async
65
+ reflection = build_without_async
66
+ if options[:async_counter_cache] && options[:counter_cache]
67
+ raise 'Do not mix `:async_counter_cache` and `:counter_cache`.'
68
+ end
69
+ if options[:async_counter_cache]
70
+ add_async_counter_cache_callbacks(reflection)
71
+ end
72
+ reflection
73
+ end
74
+
75
+ def self.included(base)
76
+ base.class_eval do
77
+ alias_method_chain :build, :async
78
+ self.valid_options += [:async_counter_cache]
79
+ end
80
+ end
81
+
82
+ private
83
+
84
+ def add_async_counter_cache_callbacks(reflection)
85
+ cache_column = reflection.counter_cache_column
86
+ name = self.name
87
+
88
+ method_name = "belongs_to_async_counter_cache_on_create_for_#{name}"
89
+ model.redefine_method(method_name) do
90
+ record = send(name)
91
+ ArResqueCounterCache::IncrementCountersWorker.cache_and_enqueue(
92
+ record.class.to_s,
93
+ record.id,
94
+ cache_column,
95
+ :increment
96
+ ) unless record.nil?
97
+ end
98
+ model.after_commit(method_name, :on => :create)
99
+
100
+ method_name = "belongs_to_async_counter_cache_on_destroy_for_#{name}"
101
+ model.redefine_method(method_name) do
102
+ record = send(name)
103
+ ArResqueCounterCache::IncrementCountersWorker.cache_and_enqueue(
104
+ record.class.to_s,
105
+ record.id,
106
+ cache_column,
107
+ :decrement
108
+ ) unless record.nil?
109
+ end
110
+ model.after_commit(method_name, :on => :destroy)
111
+
112
+ model.send(
113
+ :module_eval,
114
+ "#{reflection.class_name}.send(:attr_readonly,\"#{cache_column}\".intern) if defined?(#{reflection.class_name}) && #{reflection.class_name}.respond_to?(:attr_readonly)",
115
+ __FILE__,
116
+ __LINE__
117
+ )
118
+ end
70
119
  end
71
120
  end
72
121
  end
122
+
123
+ ActiveRecord::Reflection::AssociationReflection.send(
124
+ :include,
125
+ ArResqueCounterCache::ActiveRecord::AssociationReflectionTweaks
126
+ )
127
+ ActiveRecord::Associations::Builder::BelongsTo.send(
128
+ :include,
129
+ ArResqueCounterCache::ActiveRecord::AsyncBuilderBehavior
130
+ )
@@ -1,7 +1,7 @@
1
1
  require 'resque'
2
2
  require 'resque-lock-timeout'
3
3
 
4
- module ArAsyncCounterCache
4
+ module ArResqueCounterCache
5
5
 
6
6
  # The default Resque queue is :counter_caches.
7
7
  def self.resque_job_queue=(queue)
@@ -25,7 +25,7 @@ module ArAsyncCounterCache
25
25
  end
26
26
  end
27
27
 
28
- # ArAsyncCounterCache will very quickly increment a counter cache in Redis,
28
+ # ArResqueCounterCache will very quickly increment a counter cache in Redis,
29
29
  # which will then later be updated by a Resque job. Using
30
30
  # require-lock-timeout, we can ensure that only one job per ___ is running
31
31
  # at a time.
@@ -43,7 +43,7 @@ module ArAsyncCounterCache
43
43
  elsif direction == :decrement
44
44
  redis.decr(key)
45
45
  else
46
- raise ArgumentError, "Must call ArAsyncCounterCache::IncrementCountersWorker with :increment or :decrement"
46
+ raise ArgumentError, "Must call ArResqueCounterCache::IncrementCountersWorker with :increment or :decrement"
47
47
  end
48
48
  ::Resque.enqueue(self, parent_class, id, column)
49
49
  end
@@ -1,3 +1,3 @@
1
- module ArAsyncCounterCache
2
- VERSION = "2.1.0"
1
+ module ArResqueCounterCache
2
+ VERSION = '3.0.0.rc1'
3
3
  end
@@ -1,20 +1,20 @@
1
1
  require 'spec_helper'
2
2
 
3
- describe ArAsyncCounterCache::ActiveRecord do
3
+ describe ArResqueCounterCache::ActiveRecord do
4
4
 
5
5
  context "callbacks" do
6
6
 
7
7
  subject { User.create(:name => "Susan") }
8
8
 
9
9
  it "should increment" do
10
- ArAsyncCounterCache::IncrementCountersWorker.should_receive(:cache_and_enqueue).with("User", subject.id, "posts_count", :increment)
10
+ ArResqueCounterCache::IncrementCountersWorker.should_receive(:cache_and_enqueue).with("User", subject.id, "posts_count", :increment)
11
11
  subject.posts.create(:body => "I have a cat!")
12
12
  end
13
13
 
14
14
  it "should increment" do
15
- ArAsyncCounterCache::IncrementCountersWorker.stub(:cache_and_enqueue)
15
+ ArResqueCounterCache::IncrementCountersWorker.stub(:cache_and_enqueue)
16
16
  post = subject.posts.create(:body => "I have a cat!")
17
- ArAsyncCounterCache::IncrementCountersWorker.should_receive(:cache_and_enqueue).with("User", subject.id, "posts_count", :decrement)
17
+ ArResqueCounterCache::IncrementCountersWorker.should_receive(:cache_and_enqueue).with("User", subject.id, "posts_count", :decrement)
18
18
  post.destroy
19
19
  end
20
20
  end
@@ -28,7 +28,7 @@ describe "integration" do
28
28
  # 3 for comments incrementing posts' comments counts
29
29
  Resque.size(:testing).should == 8
30
30
 
31
- # [ArAsyncCounterCache::IncrementCountersWorker, "User", 1, "posts_count"]
31
+ # [ArResqueCounterCache::IncrementCountersWorker, "User", 1, "posts_count"]
32
32
  perform_next_job
33
33
  @user1.reload.posts_count.should == 2
34
34
  @user1.reload.comments_count.should == 0
@@ -37,7 +37,7 @@ describe "integration" do
37
37
  @post1.reload.count_of_comments.should == 0
38
38
  @post2.reload.count_of_comments.should == 0
39
39
 
40
- # [ArAsyncCounterCache::IncrementCountersWorker, "Post", 1, "count_of_comments"]
40
+ # [ArResqueCounterCache::IncrementCountersWorker, "Post", 1, "count_of_comments"]
41
41
  perform_next_job
42
42
  @user1.reload.posts_count.should == 2
43
43
  @user1.reload.comments_count.should == 0
@@ -46,7 +46,7 @@ describe "integration" do
46
46
  @post1.reload.count_of_comments.should == 2
47
47
  @post2.reload.count_of_comments.should == 0
48
48
 
49
- # [ArAsyncCounterCache::IncrementCountersWorker, "User", 2, "comments_count"]
49
+ # [ArResqueCounterCache::IncrementCountersWorker, "User", 2, "comments_count"]
50
50
  perform_next_job
51
51
  @user1.reload.posts_count.should == 2
52
52
  @user1.reload.comments_count.should == 0
@@ -55,7 +55,7 @@ describe "integration" do
55
55
  @post1.reload.count_of_comments.should == 2
56
56
  @post2.reload.count_of_comments.should == 0
57
57
 
58
- # [ArAsyncCounterCache::IncrementCountersWorker, "User", 1, "comments_count"]
58
+ # [ArResqueCounterCache::IncrementCountersWorker, "User", 1, "comments_count"]
59
59
  perform_next_job
60
60
  @user1.reload.posts_count.should == 2
61
61
  @user1.reload.comments_count.should == 1
@@ -64,7 +64,7 @@ describe "integration" do
64
64
  @post1.reload.count_of_comments.should == 2
65
65
  @post2.reload.count_of_comments.should == 0
66
66
 
67
- # [ArAsyncCounterCache::IncrementCountersWorker, "Post", 2, "count_of_comments"]
67
+ # [ArResqueCounterCache::IncrementCountersWorker, "Post", 2, "count_of_comments"]
68
68
  perform_next_job
69
69
  @user1.reload.posts_count.should == 2
70
70
  @user1.reload.comments_count.should == 1
@@ -32,7 +32,7 @@ Resque.redis = '127.0.0.1:9736'
32
32
 
33
33
  RSpec.configure do |config|
34
34
  config.before(:all) do
35
- ArAsyncCounterCache.resque_job_queue = :testing
35
+ ArResqueCounterCache.resque_job_queue = :testing
36
36
  end
37
37
  config.before(:each) do
38
38
  ActiveRecord::Base.silence { CreateModelsForTest.migrate(:up) }
metadata CHANGED
@@ -1,19 +1,19 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ar-resque-counter-cache
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.1.0
5
- prerelease:
4
+ version: 3.0.0.rc1
5
+ prerelease: 6
6
6
  platform: ruby
7
7
  authors:
8
8
  - Aaron Gibralter
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2011-09-07 00:00:00.000000000Z
12
+ date: 2012-01-16 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: activerecord
16
- requirement: &2153292200 !ruby/object:Gem::Requirement
16
+ requirement: &70293402116900 !ruby/object:Gem::Requirement
17
17
  none: false
18
18
  requirements:
19
19
  - - ~>
@@ -21,10 +21,10 @@ dependencies:
21
21
  version: '3.1'
22
22
  type: :runtime
23
23
  prerelease: false
24
- version_requirements: *2153292200
24
+ version_requirements: *70293402116900
25
25
  - !ruby/object:Gem::Dependency
26
26
  name: resque
27
- requirement: &2153291700 !ruby/object:Gem::Requirement
27
+ requirement: &70293402116100 !ruby/object:Gem::Requirement
28
28
  none: false
29
29
  requirements:
30
30
  - - ~>
@@ -32,10 +32,10 @@ dependencies:
32
32
  version: '1.0'
33
33
  type: :runtime
34
34
  prerelease: false
35
- version_requirements: *2153291700
35
+ version_requirements: *70293402116100
36
36
  - !ruby/object:Gem::Dependency
37
37
  name: resque-lock-timeout
38
- requirement: &2153291220 !ruby/object:Gem::Requirement
38
+ requirement: &70293402115180 !ruby/object:Gem::Requirement
39
39
  none: false
40
40
  requirements:
41
41
  - - ~>
@@ -43,10 +43,10 @@ dependencies:
43
43
  version: 0.3.1
44
44
  type: :runtime
45
45
  prerelease: false
46
- version_requirements: *2153291220
46
+ version_requirements: *70293402115180
47
47
  - !ruby/object:Gem::Dependency
48
48
  name: rspec
49
- requirement: &2153290740 !ruby/object:Gem::Requirement
49
+ requirement: &70293402114700 !ruby/object:Gem::Requirement
50
50
  none: false
51
51
  requirements:
52
52
  - - ~>
@@ -54,10 +54,10 @@ dependencies:
54
54
  version: 2.4.0
55
55
  type: :development
56
56
  prerelease: false
57
- version_requirements: *2153290740
57
+ version_requirements: *70293402114700
58
58
  - !ruby/object:Gem::Dependency
59
59
  name: sqlite3-ruby
60
- requirement: &2153290280 !ruby/object:Gem::Requirement
60
+ requirement: &70293402114200 !ruby/object:Gem::Requirement
61
61
  none: false
62
62
  requirements:
63
63
  - - ~>
@@ -65,7 +65,7 @@ dependencies:
65
65
  version: 1.3.3
66
66
  type: :development
67
67
  prerelease: false
68
- version_requirements: *2153290280
68
+ version_requirements: *70293402114200
69
69
  description: Increment ActiveRecord's counter cache column asynchronously using Resque
70
70
  (and resque-lock-timeout).
71
71
  email:
@@ -104,9 +104,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
104
104
  required_rubygems_version: !ruby/object:Gem::Requirement
105
105
  none: false
106
106
  requirements:
107
- - - ! '>='
107
+ - - ! '>'
108
108
  - !ruby/object:Gem::Version
109
- version: '0'
109
+ version: 1.3.1
110
110
  requirements: []
111
111
  rubyforge_project: ar-resque-counter-cache
112
112
  rubygems_version: 1.8.10