counter-cache 0.0.1 → 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 381fdac0060611f59b5314096aa953310c927a98
4
- data.tar.gz: 94cfd0f2f7f91c8e7fd3e6c2f2579d26fee90904
3
+ metadata.gz: 005de7af8ad6de2ac4db333a51a0b69037b415da
4
+ data.tar.gz: 82e11a2ff62767df0275d60e12ef8f6208f76dc3
5
5
  SHA512:
6
- metadata.gz: 41ac6baff5ade8a503c71244efcbfd584982e0ec9ea00bde813c0797100f30044e9304c922e3f20afbab0a3e82b3c5e4c9efb5cc90125cadab6d52901b85e0b8
7
- data.tar.gz: aa2e8b95531190a0cddcc33d5f88f4a7a332a2646f8ff39784db5ecaea567e431a6fb7af23ab06375172b613d6f28c24081cc6f5b9b043bd7f65bf7066cbd041
6
+ metadata.gz: a19850cde42e9e3d8413bc8d2b0f8ab134736c16df4171c788c2cc611363429d6830191d29027084bd93d2466d64dcda731949d2313d0f07311db87faa96dbce
7
+ data.tar.gz: e90d15bae6c2de8781dcb792e90f9b7f1e40fe4fdbefa7d83b9a5bc91515dbc01ced62ff68f3f3450716f0e23319e845a38767528a8e5b3bd221bcbd72da8460
data/.gitignore CHANGED
@@ -7,7 +7,6 @@ Gemfile.lock
7
7
  InstalledFiles
8
8
  _yardoc
9
9
  coverage
10
- doc/
11
10
  lib/bundler/man
12
11
  pkg
13
12
  rdoc
@@ -1,10 +1,10 @@
1
- language: ruby
2
1
  rvm:
3
- - 2.1.1
4
- - 2.1.0
5
- - 2.0.0
6
- - 1.9.3
2
+ - "1.9.3"
3
+ - "2.1.1"
4
+ gemfile:
5
+ - gemfiles/activerecord_3.gemfile
6
+ - gemfiles/activerecord_4.0.gemfile
7
+ - gemfiles/activerecord_4.1.gemfile
7
8
  notifications:
8
- email:
9
- on_success: never
10
- webhooks: "http://ci.wanelo.com/projects/2f4c3438-a0bc-434e-a9fb-30c0c335b432/status"
9
+ email: false
10
+ webhooks: "http://ci.wanelo.com/projects/d6108a07-a333-487a-97ed-0df78d8464c0/status"
@@ -0,0 +1,11 @@
1
+ appraise "activerecord-3" do
2
+ gem "activerecord", "~> 3.2.19"
3
+ end
4
+
5
+ appraise "activerecord-4.0" do
6
+ gem "activerecord", "~> 4.0.8"
7
+ end
8
+
9
+ appraise "activerecord-4.1" do
10
+ gem "activerecord", "~> 4.1.4"
11
+ end
data/README.md CHANGED
@@ -1,6 +1,82 @@
1
1
  # Counter::Cache
2
2
 
3
- TODO: Write a gem description
3
+ [![Build Status](https://travis-ci.org/wanelo/counter-cache.svg?branch=master)](https://travis-ci.org/wanelo/counter-cache)
4
+
5
+ Counting things is hard, counting them at scale is even harder, so control when things are counted.
6
+
7
+ [Rails Counter Caches](http://railscasts.com/episodes/23-counter-cache-column) are a convenient way to keep counters on
8
+ models that have many children. Without them, you always do live counts, which do not scale. But at high scale, Rails
9
+ counter caches create update contention on singe models, especially for social sites where any single model might become
10
+ extremely popular. Many web requests trying to update the same row creates database deadlocks and kills performance due
11
+ to locking and an uncontrollable increase in iops.
12
+
13
+ This library provides all the benefits of rails counter cache, without the penalty of the contention on updates,
14
+ by serializing, buffering, and delaying updates via a queue. Counts becoming slightly less realtime, but with a guarantee that
15
+ single models will never be updated more than once in certain time periods.
16
+
17
+ ![Counter Cache Flow](doc/counter-cache-flow.png)
18
+
19
+ By default, a Buffer Counter is used which implements two modes of counting. The two modes are deferred and recalculation.
20
+
21
+ IMPORTANT: If Sidekiq is to be used as the delayed job framework, using `sidekiq-unique-jobs` is essential: https://github.com/mhenrixon/sidekiq-unique-jobs
22
+
23
+ ### Mode: Deferred
24
+
25
+ Initial mode that is used to provide roughly realtime counters.
26
+
27
+ This mode is meant to provide very reasonably up to date counters using values buffered into Redis, without asking the database
28
+ for the count at all. An example of how this works is described:
29
+
30
+ Scenario: User has many posts. We want to keep track of the number of posts on the user model (posts_count column).
31
+
32
+ When a post is created:
33
+
34
+ 1. Increment a key in Redis that corresponds to the field and user that relates to the post.
35
+ 2. Enqueue a delayed job that will later reconcile the counter column based on the key in redis.
36
+ 3. When the job runs, it picks up the value from redis (which can be zero or more) and adds the value to user.posts_count
37
+ column on the associated model.
38
+
39
+ ```ruby
40
+ user = User.find_by_id(100)
41
+ user.posts_count # 10
42
+ user.posts.create(...) # => Job is enqueued
43
+ user.posts.create(...) # => Job is already enqueued
44
+
45
+ # come back later (after a delay)
46
+ user = User.find_by_id(100)
47
+ user.posts_count # 12
48
+ ```
49
+
50
+ ### Mode: Recalculation
51
+
52
+ Runs later and ensures values are completely up to date.
53
+
54
+ This mode is used to compensate for transient errors that may cause the deferred counters to drift from the actual
55
+ values. The exact reasons this happens are undefined, redis could hang, go away, the universe could skip ahead in time,
56
+ who knows.
57
+
58
+ Using the same scenario as above:
59
+
60
+ Scenario: User has many posts. We want to keep track of the number of posts on the user model (posts_count column).
61
+
62
+ 1. Enqueue a job that is delayed by many hours (customizable)
63
+ 2. When the job runs, run a full count query to find the true count from the database and save the value to the database.
64
+
65
+ ```ruby
66
+ user = User.find_by_id(100)
67
+ user.posts_count # 10
68
+ user.posts.create(...)
69
+ user.posts.create(...)
70
+
71
+ # redis crashes, world explodes, etc.. we miss on deferred update.
72
+
73
+ user = User.find_by_id(100)
74
+ user.posts_count # 11, due to only one deferred update having run.
75
+
76
+ # come back later in a couple hours
77
+ user = User.find_by_id(100)
78
+ user.posts_count # 12
79
+ ```
4
80
 
5
81
  ## Installation
6
82
 
@@ -18,7 +94,163 @@ Or install it yourself as:
18
94
 
19
95
  ## Usage
20
96
 
21
- TODO: Write usage instructions here
97
+ Counter caches are configured on the models from the perspective of the child model to the parent that contains the counter.
98
+
99
+ #### Basic Counter with recalculation:
100
+
101
+ ```ruby
102
+ class Post
103
+ include Counter::Cache
104
+
105
+ counter_cache_on column: :posts_count, # users.posts_count
106
+ relation: :user,
107
+ relation_class_name: "User",
108
+ method: :calculate_posts_count, # This is a method on the user.
109
+ end
110
+ ```
111
+
112
+ #### To control when recalculation happens:
113
+
114
+ ```ruby
115
+ class Post
116
+ include Counter::Cache
117
+
118
+ counter_cache_on column: :posts_count, # users.posts_count
119
+ relation: :user,
120
+ relation_class_name: "User",
121
+ method: :calculate_posts_count, # This is a method on the user.
122
+ recalculation: true|false, # whether to ever recalculate this counter.
123
+ recalculation_delay: 10.seconds # Only a hard value that defines when to perform a full recalculation.
124
+ end
125
+ ```
126
+
127
+ #### To control when the deferred job runs:
128
+
129
+ ```ruby
130
+ class Post
131
+ include Counter::Cache
132
+
133
+ counter_cache_on column: :posts_count, # users.posts_count
134
+ relation: :user,
135
+ relation_class_name: "User",
136
+ method: :calculate_posts_count, # This is a method on the user.
137
+ wait: 10.seconds # This can be a hard value
138
+
139
+ counter_cache_on column: :posts_count, # users.posts_count
140
+ relation: :user,
141
+ relation_class_name: "User",
142
+ method: :calculate_posts_count, # This is a method on the user.
143
+ wait: ->(user) { user.posts_count * 10 } # .. or a proc, in this case, the more posts a user has, the less frequently it will be updated.
144
+ end
145
+ ```
146
+
147
+ #### To control if an update should even happen:
148
+
149
+ ```ruby
150
+ class Post
151
+ include Counter::Cache
152
+
153
+ counter_cache_on column: :posts_count, # users.posts_count
154
+ relation: :user,
155
+ relation_class_name: "User",
156
+ method: :calculate_posts_count, # This is a method on the user.
157
+ if: ->(post) { post.public? ? false : true }
158
+ end
159
+ ```
160
+
161
+ #### Polymorphism (because YAY)
162
+
163
+ Setting `polymorphic: true`, will ask ActiveRecord what the class is (User, Store), based on followee_type, and update
164
+ the appropriate model. So if a user is followed, then that users followers_count will increment.
165
+
166
+ ```ruby
167
+ class User
168
+ attr_accessible :followers_count
169
+ end
170
+
171
+ class Store
172
+ attr_accessible :followers_count
173
+ end
174
+
175
+ class Follow
176
+ attr_accessible :user_id, :followee_id, :followee_type
177
+
178
+ belongs_to :followee, polymorphic: true
179
+
180
+ include Counter::Cache
181
+
182
+ counter_cache_on column: :followers_count,
183
+ relation: :followee,
184
+ polymorphic: true
185
+ end
186
+ ```
187
+
188
+ ## Configuration
189
+
190
+ In an initializer such as `config/initializers/counter_cache.rb`, write the configuration as:
191
+
192
+ ```ruby
193
+ Counter::Cache.configure do |c|
194
+ c.default_worker_adapter = MyCustomWorkAdapter
195
+ c.recalculation_delay = 6.hours # Default delay for recalculations
196
+ c.redis_pool = Redis.new
197
+ c.counting_data_store = MyCustomDataStore # Default is Counter::Cache::Redis
198
+ end
199
+ ```
200
+
201
+ ### default_worker_adapter
202
+
203
+ The worker adapter allows you to control how jobs are delayed/enqueued for later execution. Three options are passed:
204
+
205
+ - delay: This is the delay in seconds that the execution should be delayed. Can be ignored or adjusted. We pass this to
206
+ sidekiq.
207
+ - base_class: This is the class name of the source object.
208
+ - options: This will be a hash of options that should be passed to the instance of the counter.
209
+
210
+ An example of a dummy adapter is like so:
211
+
212
+ ```ruby
213
+ class TestWorkerAdapter
214
+ def enqueue(delay, base_class, options)
215
+ options[:source_object_class_name] = base_class.constantize
216
+ counter_class = options[:counter].constantize # options[:counter] is the class name of the counter that called the adapter.
217
+ counter = counter_class.new(nil, options)
218
+ counter.save!
219
+ end
220
+ end
221
+ ```
222
+
223
+ An example of a dummy adapter that uses Sidekiq is like so:
224
+
225
+ ```ruby
226
+ class CounterWorker
227
+ include Sidekiq::Worker
228
+
229
+ def perform(base_class, options)
230
+ options.symbolize_keys! # From ActiveSupport, Sidekiq looses symbol information from hashes.
231
+ options[:source_object_class_name] = base_class.constantize
232
+ counter_class = options[:counter].constantize # options[:counter] is the class name of the counter that called the adapter.
233
+ counter = counter_class.new(nil, options)
234
+ counter.save!
235
+ end
236
+
237
+ def self.enqueue(delay, base_class, options)
238
+ perform_in(delay, base_class, options)
239
+ end
240
+ end
241
+ ```
242
+
243
+ ### recalculation_delay
244
+
245
+ This should be set to the default delay for recalculations, in seconds.
246
+
247
+ ### redis_pool
248
+
249
+ This can either be a single redis connection or a ConnectionPool instance (https://github.com/mperham/connection_pool).
250
+
251
+ ### counting_data_store
252
+
253
+ This defaults to Counter::Cache::Redis but can be set to anything. The Redis store describes what the API would be.
22
254
 
23
255
  ## Contributing
24
256
 
@@ -27,3 +259,15 @@ TODO: Write usage instructions here
27
259
  3. Commit your changes (`git commit -am 'Add some feature'`)
28
260
  4. Push to the branch (`git push origin my-new-feature`)
29
261
  5. Create a new Pull Request
262
+
263
+ ### Running specs:
264
+
265
+ Appraisal is used to test against multiple versions of activerecord. 3.2, 4.0, and 4.1 are currently supported.
266
+
267
+ To install dependencies:
268
+
269
+ $ bundle exec appraisal install
270
+
271
+ To run specs across versions:
272
+
273
+ $ bundle exec appraisal rspec
@@ -20,6 +20,7 @@ Gem::Specification.new do |spec|
20
20
 
21
21
  spec.add_dependency "activerecord", ">= 3.0"
22
22
 
23
+ spec.add_development_dependency "appraisal"
23
24
  spec.add_development_dependency "bundler", "~> 1.6"
24
25
  spec.add_development_dependency "rake"
25
26
  spec.add_development_dependency "rspec", ">= 3.0"
@@ -0,0 +1,7 @@
1
+ # This file was generated by Appraisal
2
+
3
+ source "https://rubygems.org"
4
+
5
+ gem "activerecord", "~> 3.2.19"
6
+
7
+ gemspec :path => "../"
@@ -0,0 +1,92 @@
1
+ PATH
2
+ remote: ../
3
+ specs:
4
+ counter-cache (0.0.2)
5
+ activerecord (>= 3.0)
6
+
7
+ GEM
8
+ remote: https://rubygems.org/
9
+ specs:
10
+ activemodel (3.2.19)
11
+ activesupport (= 3.2.19)
12
+ builder (~> 3.0.0)
13
+ activerecord (3.2.19)
14
+ activemodel (= 3.2.19)
15
+ activesupport (= 3.2.19)
16
+ arel (~> 3.0.2)
17
+ tzinfo (~> 0.3.29)
18
+ activesupport (3.2.19)
19
+ i18n (~> 0.6, >= 0.6.4)
20
+ multi_json (~> 1.0)
21
+ appraisal (1.0.0)
22
+ bundler
23
+ rake
24
+ thor (>= 0.14.0)
25
+ arel (3.0.3)
26
+ builder (3.0.4)
27
+ celluloid (0.15.2)
28
+ timers (~> 1.1.0)
29
+ coderay (1.1.0)
30
+ diff-lcs (1.2.5)
31
+ fakeredis (0.5.0)
32
+ redis (~> 3.0)
33
+ ffi (1.9.3)
34
+ formatador (0.2.5)
35
+ guard (2.6.1)
36
+ formatador (>= 0.2.4)
37
+ listen (~> 2.7)
38
+ lumberjack (~> 1.0)
39
+ pry (>= 0.9.12)
40
+ thor (>= 0.18.1)
41
+ guard-rspec (4.3.1)
42
+ guard (~> 2.1)
43
+ rspec (>= 2.14, < 4.0)
44
+ i18n (0.6.11)
45
+ listen (2.7.9)
46
+ celluloid (>= 0.15.2)
47
+ rb-fsevent (>= 0.9.3)
48
+ rb-inotify (>= 0.9)
49
+ lumberjack (1.0.9)
50
+ method_source (0.8.2)
51
+ multi_json (1.10.1)
52
+ pry (0.10.0)
53
+ coderay (~> 1.1.0)
54
+ method_source (~> 0.8.1)
55
+ slop (~> 3.4)
56
+ rake (10.3.2)
57
+ rb-fsevent (0.9.4)
58
+ rb-inotify (0.9.5)
59
+ ffi (>= 0.5.0)
60
+ redis (3.1.0)
61
+ rspec (3.0.0)
62
+ rspec-core (~> 3.0.0)
63
+ rspec-expectations (~> 3.0.0)
64
+ rspec-mocks (~> 3.0.0)
65
+ rspec-core (3.0.3)
66
+ rspec-support (~> 3.0.0)
67
+ rspec-expectations (3.0.3)
68
+ diff-lcs (>= 1.2.0, < 2.0)
69
+ rspec-support (~> 3.0.0)
70
+ rspec-mocks (3.0.3)
71
+ rspec-support (~> 3.0.0)
72
+ rspec-support (3.0.3)
73
+ slop (3.6.0)
74
+ sqlite3 (1.3.9)
75
+ thor (0.19.1)
76
+ timers (1.1.0)
77
+ tzinfo (0.3.39)
78
+
79
+ PLATFORMS
80
+ ruby
81
+
82
+ DEPENDENCIES
83
+ activerecord (~> 3.2.19)
84
+ appraisal
85
+ bundler (~> 1.6)
86
+ counter-cache!
87
+ fakeredis
88
+ guard
89
+ guard-rspec
90
+ rake
91
+ rspec (>= 3.0)
92
+ sqlite3
@@ -0,0 +1,7 @@
1
+ # This file was generated by Appraisal
2
+
3
+ source "https://rubygems.org"
4
+
5
+ gem "activerecord", "~> 4.0.8"
6
+
7
+ gemspec :path => "../"
@@ -0,0 +1,98 @@
1
+ PATH
2
+ remote: ../
3
+ specs:
4
+ counter-cache (0.0.2)
5
+ activerecord (>= 3.0)
6
+
7
+ GEM
8
+ remote: https://rubygems.org/
9
+ specs:
10
+ activemodel (4.0.8)
11
+ activesupport (= 4.0.8)
12
+ builder (~> 3.1.0)
13
+ activerecord (4.0.8)
14
+ activemodel (= 4.0.8)
15
+ activerecord-deprecated_finders (~> 1.0.2)
16
+ activesupport (= 4.0.8)
17
+ arel (~> 4.0.0)
18
+ activerecord-deprecated_finders (1.0.3)
19
+ activesupport (4.0.8)
20
+ i18n (~> 0.6, >= 0.6.9)
21
+ minitest (~> 4.2)
22
+ multi_json (~> 1.3)
23
+ thread_safe (~> 0.1)
24
+ tzinfo (~> 0.3.37)
25
+ appraisal (1.0.0)
26
+ bundler
27
+ rake
28
+ thor (>= 0.14.0)
29
+ arel (4.0.2)
30
+ builder (3.1.4)
31
+ celluloid (0.15.2)
32
+ timers (~> 1.1.0)
33
+ coderay (1.1.0)
34
+ diff-lcs (1.2.5)
35
+ fakeredis (0.5.0)
36
+ redis (~> 3.0)
37
+ ffi (1.9.3)
38
+ formatador (0.2.5)
39
+ guard (2.6.1)
40
+ formatador (>= 0.2.4)
41
+ listen (~> 2.7)
42
+ lumberjack (~> 1.0)
43
+ pry (>= 0.9.12)
44
+ thor (>= 0.18.1)
45
+ guard-rspec (4.3.1)
46
+ guard (~> 2.1)
47
+ rspec (>= 2.14, < 4.0)
48
+ i18n (0.6.11)
49
+ listen (2.7.9)
50
+ celluloid (>= 0.15.2)
51
+ rb-fsevent (>= 0.9.3)
52
+ rb-inotify (>= 0.9)
53
+ lumberjack (1.0.9)
54
+ method_source (0.8.2)
55
+ minitest (4.7.5)
56
+ multi_json (1.10.1)
57
+ pry (0.10.0)
58
+ coderay (~> 1.1.0)
59
+ method_source (~> 0.8.1)
60
+ slop (~> 3.4)
61
+ rake (10.3.2)
62
+ rb-fsevent (0.9.4)
63
+ rb-inotify (0.9.5)
64
+ ffi (>= 0.5.0)
65
+ redis (3.1.0)
66
+ rspec (3.0.0)
67
+ rspec-core (~> 3.0.0)
68
+ rspec-expectations (~> 3.0.0)
69
+ rspec-mocks (~> 3.0.0)
70
+ rspec-core (3.0.3)
71
+ rspec-support (~> 3.0.0)
72
+ rspec-expectations (3.0.3)
73
+ diff-lcs (>= 1.2.0, < 2.0)
74
+ rspec-support (~> 3.0.0)
75
+ rspec-mocks (3.0.3)
76
+ rspec-support (~> 3.0.0)
77
+ rspec-support (3.0.3)
78
+ slop (3.6.0)
79
+ sqlite3 (1.3.9)
80
+ thor (0.19.1)
81
+ thread_safe (0.3.4)
82
+ timers (1.1.0)
83
+ tzinfo (0.3.40)
84
+
85
+ PLATFORMS
86
+ ruby
87
+
88
+ DEPENDENCIES
89
+ activerecord (~> 4.0.8)
90
+ appraisal
91
+ bundler (~> 1.6)
92
+ counter-cache!
93
+ fakeredis
94
+ guard
95
+ guard-rspec
96
+ rake
97
+ rspec (>= 3.0)
98
+ sqlite3
@@ -0,0 +1,7 @@
1
+ # This file was generated by Appraisal
2
+
3
+ source "https://rubygems.org"
4
+
5
+ gem "activerecord", "~> 4.1.4"
6
+
7
+ gemspec :path => "../"
@@ -0,0 +1,97 @@
1
+ PATH
2
+ remote: ../
3
+ specs:
4
+ counter-cache (0.0.2)
5
+ activerecord (>= 3.0)
6
+
7
+ GEM
8
+ remote: https://rubygems.org/
9
+ specs:
10
+ activemodel (4.1.4)
11
+ activesupport (= 4.1.4)
12
+ builder (~> 3.1)
13
+ activerecord (4.1.4)
14
+ activemodel (= 4.1.4)
15
+ activesupport (= 4.1.4)
16
+ arel (~> 5.0.0)
17
+ activesupport (4.1.4)
18
+ i18n (~> 0.6, >= 0.6.9)
19
+ json (~> 1.7, >= 1.7.7)
20
+ minitest (~> 5.1)
21
+ thread_safe (~> 0.1)
22
+ tzinfo (~> 1.1)
23
+ appraisal (1.0.0)
24
+ bundler
25
+ rake
26
+ thor (>= 0.14.0)
27
+ arel (5.0.1.20140414130214)
28
+ builder (3.2.2)
29
+ celluloid (0.15.2)
30
+ timers (~> 1.1.0)
31
+ coderay (1.1.0)
32
+ diff-lcs (1.2.5)
33
+ fakeredis (0.5.0)
34
+ redis (~> 3.0)
35
+ ffi (1.9.3)
36
+ formatador (0.2.5)
37
+ guard (2.6.1)
38
+ formatador (>= 0.2.4)
39
+ listen (~> 2.7)
40
+ lumberjack (~> 1.0)
41
+ pry (>= 0.9.12)
42
+ thor (>= 0.18.1)
43
+ guard-rspec (4.3.1)
44
+ guard (~> 2.1)
45
+ rspec (>= 2.14, < 4.0)
46
+ i18n (0.6.11)
47
+ json (1.8.1)
48
+ listen (2.7.9)
49
+ celluloid (>= 0.15.2)
50
+ rb-fsevent (>= 0.9.3)
51
+ rb-inotify (>= 0.9)
52
+ lumberjack (1.0.9)
53
+ method_source (0.8.2)
54
+ minitest (5.4.0)
55
+ pry (0.10.0)
56
+ coderay (~> 1.1.0)
57
+ method_source (~> 0.8.1)
58
+ slop (~> 3.4)
59
+ rake (10.3.2)
60
+ rb-fsevent (0.9.4)
61
+ rb-inotify (0.9.5)
62
+ ffi (>= 0.5.0)
63
+ redis (3.1.0)
64
+ rspec (3.0.0)
65
+ rspec-core (~> 3.0.0)
66
+ rspec-expectations (~> 3.0.0)
67
+ rspec-mocks (~> 3.0.0)
68
+ rspec-core (3.0.3)
69
+ rspec-support (~> 3.0.0)
70
+ rspec-expectations (3.0.3)
71
+ diff-lcs (>= 1.2.0, < 2.0)
72
+ rspec-support (~> 3.0.0)
73
+ rspec-mocks (3.0.3)
74
+ rspec-support (~> 3.0.0)
75
+ rspec-support (3.0.3)
76
+ slop (3.6.0)
77
+ sqlite3 (1.3.9)
78
+ thor (0.19.1)
79
+ thread_safe (0.3.4)
80
+ timers (1.1.0)
81
+ tzinfo (1.2.1)
82
+ thread_safe (~> 0.1)
83
+
84
+ PLATFORMS
85
+ ruby
86
+
87
+ DEPENDENCIES
88
+ activerecord (~> 4.1.4)
89
+ appraisal
90
+ bundler (~> 1.6)
91
+ counter-cache!
92
+ fakeredis
93
+ guard
94
+ guard-rspec
95
+ rake
96
+ rspec (>= 3.0)
97
+ sqlite3
@@ -20,7 +20,7 @@ module Counter
20
20
  end
21
21
 
22
22
  def reflection_type
23
- source_object.reflections[options.relation.to_sym].class_name.to_s.camelize # let AR give us the correct class name :)
23
+ source_object.class.reflections[options.relation.to_sym].class_name.to_s.camelize # let AR give us the correct class name :)
24
24
  end
25
25
  end
26
26
  end
@@ -1,5 +1,5 @@
1
1
  module Counter
2
2
  module Cache
3
- VERSION = "0.0.1"
3
+ VERSION = "0.0.2"
4
4
  end
5
5
  end
@@ -6,7 +6,7 @@ require 'fakeredis'
6
6
  RSpec.describe "Counting" do
7
7
 
8
8
  before do
9
- ActiveRecord::Base.silence { CreateModelsForTest.migrate(:up) }
9
+ CreateModelsForTest.migrate(:up)
10
10
  Counter::Cache.configure do |c|
11
11
  c.redis_pool = Redis.new
12
12
  c.default_worker_adapter = TestWorkerAdapter.new
@@ -14,7 +14,7 @@ RSpec.describe "Counting" do
14
14
  end
15
15
 
16
16
  after do
17
- ActiveRecord::Base.silence { CreateModelsForTest.migrate(:down) }
17
+ CreateModelsForTest.migrate(:down)
18
18
  end
19
19
 
20
20
  let(:user) { User.create }
@@ -29,7 +29,7 @@ RSpec.describe Counter::Cache::Counters::BufferCounter::RelationFinder do
29
29
  before do
30
30
  reflection = double
31
31
  expect(reflection).to receive_message_chain("class_name.to_s.camelize") { "Boo" }
32
- expect(source_object).to receive(:reflections).and_return({:boo => reflection})
32
+ expect(source_object.class).to receive(:reflections).and_return({:boo => reflection})
33
33
  end
34
34
 
35
35
  it 'asks active record for the class name' do
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: counter-cache
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: 0.0.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Paul Henry & Matt Camuto
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-06-17 00:00:00.000000000 Z
11
+ date: 2014-07-28 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activerecord
@@ -24,6 +24,20 @@ dependencies:
24
24
  - - ">="
25
25
  - !ruby/object:Gem::Version
26
26
  version: '3.0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: appraisal
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
27
41
  - !ruby/object:Gem::Dependency
28
42
  name: bundler
29
43
  requirement: !ruby/object:Gem::Requirement
@@ -132,12 +146,20 @@ files:
132
146
  - ".gitignore"
133
147
  - ".rspec"
134
148
  - ".travis.yml"
149
+ - Appraisals
135
150
  - Gemfile
136
151
  - Guardfile
137
152
  - LICENSE.txt
138
153
  - README.md
139
154
  - Rakefile
140
155
  - counter-cache.gemspec
156
+ - doc/counter-cache-flow.png
157
+ - gemfiles/activerecord_3.gemfile
158
+ - gemfiles/activerecord_3.gemfile.lock
159
+ - gemfiles/activerecord_4.0.gemfile
160
+ - gemfiles/activerecord_4.0.gemfile.lock
161
+ - gemfiles/activerecord_4.1.gemfile
162
+ - gemfiles/activerecord_4.1.gemfile.lock
141
163
  - lib/counter/cache.rb
142
164
  - lib/counter/cache/active_record_updater.rb
143
165
  - lib/counter/cache/config.rb
@@ -185,7 +207,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
185
207
  version: '0'
186
208
  requirements: []
187
209
  rubyforge_project:
188
- rubygems_version: 2.2.2
210
+ rubygems_version: 2.2.0
189
211
  signing_key:
190
212
  specification_version: 4
191
213
  summary: Counting is hard.