counter_culture 1.3.1 → 1.4.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.travis.yml +1 -0
- data/CHANGELOG.md +10 -0
- data/README.md +31 -32
- data/VERSION +1 -1
- data/counter_culture.gemspec +46 -47
- data/lib/counter_culture/counter.rb +16 -5
- data/lib/counter_culture/extensions.rb +11 -6
- data/spec/counter_culture_spec.rb +6 -0
- data/spec/rails_app/config/environments/test.rb +0 -3
- data/spec/spec_helper.rb +7 -2
- data/test_rails_versions.sh +5 -1
- metadata +3 -4
- data/Gemfile.lock +0 -189
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 8651d71833facf2f685c6fcbd0ae922bb55e295d
|
4
|
+
data.tar.gz: dab5d1dfecaa1a880171f5378de590385cf11218
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 817f09ec93f18c4a638b1db6e34ac811a73abe2b96179bc471547cce713bc8029d7131e9577f9aac152ad82993db2e922f1a2f68d3d0541de6b7e944db05ce1c
|
7
|
+
data.tar.gz: a7332118c2325d9124ad1053dddb6a947e2fc2e416bdb6999e7d5c36e3cb5452c8a8ba48a6ea21d0a13d364334990cf9ee2a840bfb00b7dd738683465fdb9ed4
|
data/.travis.yml
CHANGED
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,13 @@
|
|
1
|
+
## 1.4.0 (March 21, 2017)
|
2
|
+
|
3
|
+
Improvements:
|
4
|
+
- Avoid Rails 5.1 deprecation warnings
|
5
|
+
|
6
|
+
## 1.3.1 (February 23, 2017)
|
7
|
+
|
8
|
+
Bugfixes:
|
9
|
+
- Removed requirement for Rails 5 added by mistake (in fact, this gem supports and tests Rails versions as far back as Rails 3.2 now)
|
10
|
+
|
1
11
|
## 1.3.0 (February 21, 2017)
|
2
12
|
Removed features:
|
3
13
|
- Removed support for `has_one`; this did not work properly. If you need this, consider adding the `counter_culture` call on the model with the `belongs_to` instead.
|
data/README.md
CHANGED
@@ -2,11 +2,13 @@
|
|
2
2
|
|
3
3
|
Turbo-charged counter caches for your Rails app. Huge improvements over the Rails standard counter caches:
|
4
4
|
|
5
|
-
* Updates counter cache when values change, not just when creating and destroying
|
5
|
+
* Updates counter cache when values change, not just when creating and destroying
|
6
6
|
* Supports counter caches through multiple levels of relations
|
7
7
|
* Supports dynamic column names, making it possible to split up the counter cache for different types of objects
|
8
8
|
* Can keep a running count, or a running total
|
9
9
|
|
10
|
+
Tested against Ruby 2.2.5 and 2.3.1 and against the latest patch releases of Rails 3.2, 4.0, 4.1, 4.2, 5.0 and 5.1.
|
11
|
+
|
10
12
|
## Installation
|
11
13
|
|
12
14
|
Add counter_culture to your Gemfile:
|
@@ -27,7 +29,7 @@ rails generate counter_culture Category products_count
|
|
27
29
|
|
28
30
|
Which will generate a migration with code like the following:
|
29
31
|
```ruby
|
30
|
-
add_column :categories, :products_count, :integer, :
|
32
|
+
add_column :categories, :products_count, :integer, null: false, default: 0
|
31
33
|
```
|
32
34
|
Note that the column must be ```NOT NULL``` and have a default of zero for this gem to work correctly.
|
33
35
|
|
@@ -85,7 +87,7 @@ end
|
|
85
87
|
```ruby
|
86
88
|
class Product < ActiveRecord::Base
|
87
89
|
belongs_to :category
|
88
|
-
counter_culture :category, :
|
90
|
+
counter_culture :category, column_name: "products_counter_cache"
|
89
91
|
end
|
90
92
|
|
91
93
|
class Category < ActiveRecord::Base
|
@@ -100,7 +102,7 @@ Now, the ```Category``` model will keep an up-to-date counter-cache in the ```pr
|
|
100
102
|
```ruby
|
101
103
|
class Product < ActiveRecord::Base
|
102
104
|
belongs_to :category
|
103
|
-
counter_culture :category, :
|
105
|
+
counter_culture :category, column_name: proc {|model| "#{model.product_type}_count" }
|
104
106
|
# attribute product_type may be one of ['awesome', 'sucky']
|
105
107
|
end
|
106
108
|
|
@@ -143,7 +145,7 @@ Now adding a `Product` will increase the `weight` column in its `Category` by 3;
|
|
143
145
|
```ruby
|
144
146
|
class Product < ActiveRecord::Base
|
145
147
|
belongs_to :category
|
146
|
-
counter_culture :category, :
|
148
|
+
counter_culture :category, column_name: proc {|model| model.special? ? 'special_count' : nil }
|
147
149
|
end
|
148
150
|
|
149
151
|
class Category < ActiveRecord::Base
|
@@ -164,7 +166,7 @@ total of the weight for all the products in the Category model's ```product_weig
|
|
164
166
|
```ruby
|
165
167
|
class Product < ActiveRecord::Base
|
166
168
|
belongs_to :category
|
167
|
-
counter_culture :category, :
|
169
|
+
counter_culture :category, column_name: 'product_weight_ounces', delta_column: 'weight_ounces'
|
168
170
|
end
|
169
171
|
|
170
172
|
class Category < ActiveRecord::Base
|
@@ -182,14 +184,14 @@ The ```:delta_column``` option supports all numeric column types, not just ```:i
|
|
182
184
|
```ruby
|
183
185
|
class Product < ActiveRecord::Base
|
184
186
|
belongs_to :category
|
185
|
-
counter_culture :category, :
|
187
|
+
counter_culture :category, foreign_key_values:
|
186
188
|
proc {|category_id| [category_id, Category.find_by_id(category_id).try(:parent_category).try(:id)] }
|
187
189
|
end
|
188
190
|
|
189
191
|
class Category < ActiveRecord::Base
|
190
|
-
belongs_to :parent_category, :
|
191
|
-
has_many :children, :
|
192
|
-
|
192
|
+
belongs_to :parent_category, class_name: 'Category', foreign_key: 'parent_id'
|
193
|
+
has_many :children, class_name: 'Category', foreign_key: 'parent_id'
|
194
|
+
|
193
195
|
has_many :products
|
194
196
|
end
|
195
197
|
```
|
@@ -200,7 +202,7 @@ Now, the ```Category``` model will keep an up-to-date counter-cache in the ```pr
|
|
200
202
|
|
201
203
|
By default, counter_culture does not update the timestamp of models when it updates their counter caches. If you would like every change in the counter cache column to result in an updated timestamp, simply set the touch option to true:
|
202
204
|
```ruby
|
203
|
-
counter_culture :category, :
|
205
|
+
counter_culture :category, touch: true
|
204
206
|
```
|
205
207
|
|
206
208
|
This is useful when you require your caches to get invalidated when the counter cache changes.
|
@@ -209,7 +211,7 @@ This is useful when you require your caches to get invalidated when the counter
|
|
209
211
|
|
210
212
|
You may also specify a custom timestamp column that gets updated only when a particular counter cache changes:
|
211
213
|
```ruby
|
212
|
-
counter_culture :category, :
|
214
|
+
counter_culture :category, touch: 'category_count_changed'
|
213
215
|
```
|
214
216
|
|
215
217
|
With this option, any time the `category_counter_cache` changes both the `category_count_changed` and `updated_at` columns will get updated.
|
@@ -218,9 +220,12 @@ With this option, any time the `category_counter_cache` changes both the `catego
|
|
218
220
|
|
219
221
|
By default, counter_culture will run counter cache updates inside of the same ActiveRecord transaction that triggered it. (Note that this bevavior [changed from version 0.2.3 to 1.0.0](CHANGELOG.md#100-november-15-2016).) If you would like to run counter cache updates outside of that transaction, for example because you are experiencing [deadlocks with older versions of PostgreSQL](http://mina.naguib.ca/blog/2010/11/22/postgresql-foreign-key-deadlocks.html), you can enable that behavior:
|
220
222
|
```ruby
|
221
|
-
counter_culture :category, :
|
223
|
+
counter_culture :category, execute_after_commit: true
|
222
224
|
```
|
223
225
|
|
226
|
+
Please note that using `execute_after_commit` in conjunction with transactional
|
227
|
+
fixtures will lead to your tests no longer seeing updated counter values.
|
228
|
+
|
224
229
|
### Manually populating counter cache values
|
225
230
|
|
226
231
|
You will sometimes want to populate counter-cache values from primary data. This is required when adding counter-caches to existing data. It is also recommended to run this regularly (at BestVendor, we run it once a week) to catch any incorrect values in the counter caches.
|
@@ -229,16 +234,16 @@ You will sometimes want to populate counter-cache values from primary data. This
|
|
229
234
|
Product.counter_culture_fix_counts
|
230
235
|
# will automatically fix counts for all counter caches defined on Product
|
231
236
|
|
232
|
-
Product.counter_culture_fix_counts :
|
237
|
+
Product.counter_culture_fix_counts except: :category
|
233
238
|
# will automatically fix counts for all counter caches defined on Product, except for the :category relation
|
234
239
|
|
235
|
-
Product.counter_culture_fix_counts :
|
240
|
+
Product.counter_culture_fix_counts only: :category
|
236
241
|
# will automatically fix counts only on the :category relation on Product
|
237
242
|
|
238
243
|
# :except and :only also accept arrays of one level relations
|
239
244
|
# if you want to fix counts on a more than one level relation you need to use convention below:
|
240
245
|
|
241
|
-
Product.counter_culture_fix_counts :
|
246
|
+
Product.counter_culture_fix_counts only: [[:subcategory, :category]]
|
242
247
|
# will automatically fix counts only on the two-level [:subcategory, :category] relation on Product
|
243
248
|
|
244
249
|
# :except and :only also accept arrays
|
@@ -252,17 +257,17 @@ CounterCulture.config.batch_size = 100
|
|
252
257
|
or by passing the :batch_size option to the method call
|
253
258
|
|
254
259
|
```ruby
|
255
|
-
Product.counter_culture_fix_counts :
|
260
|
+
Product.counter_culture_fix_counts batch_size: 100
|
256
261
|
```
|
257
262
|
|
258
263
|
```counter_culture_fix_counts``` returns an array of hashes of all incorrect values for debugging purposes. The hashes have the following format:
|
259
264
|
|
260
265
|
```ruby
|
261
|
-
{ :
|
262
|
-
:
|
263
|
-
:
|
264
|
-
:
|
265
|
-
:
|
266
|
+
{ entity: which model the count was fixed on,
|
267
|
+
id: the id of the model that had the incorrect count,
|
268
|
+
what: which column contained the incorrect count,
|
269
|
+
wrong: the previously saved, incorrect count,
|
270
|
+
right: the newly fixed, correct count }
|
266
271
|
```
|
267
272
|
|
268
273
|
```counter_culture_fix_counts``` is optimized to minimize the number of queries and runs very quickly.
|
@@ -274,9 +279,9 @@ Manually populating counter caches with dynamic column names requires additional
|
|
274
279
|
```ruby
|
275
280
|
class Product < ActiveRecord::Base
|
276
281
|
belongs_to :category
|
277
|
-
counter_culture :category,
|
278
|
-
:
|
279
|
-
:
|
282
|
+
counter_culture :category,
|
283
|
+
column_name: proc {|model| "#{model.product_type}_count" },
|
284
|
+
column_names: {
|
280
285
|
["products.product_type = ?", 'awesome'] => 'awesome_count',
|
281
286
|
["products.product_type = ?", 'sucky'] => 'sucky_count'
|
282
287
|
}
|
@@ -292,14 +297,8 @@ Manually populating counter caches with dynamically over-written foreign keys (`
|
|
292
297
|
|
293
298
|
counter_culture currently does *not* support polymorphic associations. Check [this issue](https://github.com/magnusvk/counter_culture/issues/4) for progress and alternatives.
|
294
299
|
|
295
|
-
## A note on testing
|
296
|
-
|
297
|
-
counter_culture will not update counters in your automated tests *if* you use transactional fixtures. That's because transactional fixtures roll back all your database transactions and they are never committed. But counter_culture will only update its counters in the ```after_commit``` callback, which in this case will never run.
|
298
|
-
|
299
|
-
counter_culture itself has extensive automated tests so there should not be a need to test counter caches in your own tests. I therefore recommend removing any checks of counter caches as that will avoid this issue. If that is not an option for you, you can use the [`test_after_commit` gem](https://github.com/grosser/test_after_commit) to trigger `after_commit` callbacks even with transactional fixtures enabled. Another option is to turn off transactional fixtures and use something like [database_cleaner](https://github.com/bmabey/database_cleaner) instead to clean your database between tests.
|
300
|
-
|
301
300
|
## Contributing to counter_culture
|
302
|
-
|
301
|
+
|
303
302
|
* Check out the latest master to make sure the feature hasn't been implemented or the bug hasn't been fixed yet.
|
304
303
|
* Check out the issue tracker to make sure someone already hasn't requested it and/or contributed it.
|
305
304
|
* Fork the project.
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
1.
|
1
|
+
1.4.0
|
data/counter_culture.gemspec
CHANGED
@@ -2,18 +2,18 @@
|
|
2
2
|
# DO NOT EDIT THIS FILE DIRECTLY
|
3
3
|
# Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
|
4
4
|
# -*- encoding: utf-8 -*-
|
5
|
-
# stub: counter_culture 1.
|
5
|
+
# stub: counter_culture 1.4.0 ruby lib
|
6
6
|
|
7
7
|
Gem::Specification.new do |s|
|
8
|
-
s.name = "counter_culture"
|
9
|
-
s.version = "1.
|
8
|
+
s.name = "counter_culture".freeze
|
9
|
+
s.version = "1.4.0"
|
10
10
|
|
11
|
-
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
12
|
-
s.require_paths = ["lib"]
|
13
|
-
s.authors = ["Magnus von Koeller"]
|
14
|
-
s.date = "2017-
|
15
|
-
s.description = "counter_culture provides turbo-charged counter caches that are kept up-to-date not just on create and destroy, that support multiple levels of indirection through relationships, allow dynamic column names and that avoid deadlocks by updating in the after_commit callback."
|
16
|
-
s.email = "magnus@vonkoeller.de"
|
11
|
+
s.required_rubygems_version = Gem::Requirement.new(">= 0".freeze) if s.respond_to? :required_rubygems_version=
|
12
|
+
s.require_paths = ["lib".freeze]
|
13
|
+
s.authors = ["Magnus von Koeller".freeze]
|
14
|
+
s.date = "2017-03-21"
|
15
|
+
s.description = "counter_culture provides turbo-charged counter caches that are kept up-to-date not just on create and destroy, that support multiple levels of indirection through relationships, allow dynamic column names and that avoid deadlocks by updating in the after_commit callback.".freeze
|
16
|
+
s.email = "magnus@vonkoeller.de".freeze
|
17
17
|
s.extra_rdoc_files = [
|
18
18
|
"CHANGELOG.md",
|
19
19
|
"LICENSE.txt",
|
@@ -25,7 +25,6 @@ Gem::Specification.new do |s|
|
|
25
25
|
".travis.yml",
|
26
26
|
"CHANGELOG.md",
|
27
27
|
"Gemfile",
|
28
|
-
"Gemfile.lock",
|
29
28
|
"LICENSE.txt",
|
30
29
|
"README.md",
|
31
30
|
"Rakefile",
|
@@ -112,51 +111,51 @@ Gem::Specification.new do |s|
|
|
112
111
|
"spec/spec_helper.rb",
|
113
112
|
"test_rails_versions.sh"
|
114
113
|
]
|
115
|
-
s.homepage = "http://github.com/magnusvk/counter_culture"
|
116
|
-
s.licenses = ["MIT"]
|
117
|
-
s.rubygems_version = "2.
|
118
|
-
s.summary = "Turbo-charged counter caches for your Rails app."
|
114
|
+
s.homepage = "http://github.com/magnusvk/counter_culture".freeze
|
115
|
+
s.licenses = ["MIT".freeze]
|
116
|
+
s.rubygems_version = "2.6.10".freeze
|
117
|
+
s.summary = "Turbo-charged counter caches for your Rails app.".freeze
|
119
118
|
|
120
119
|
if s.respond_to? :specification_version then
|
121
120
|
s.specification_version = 4
|
122
121
|
|
123
122
|
if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
|
124
|
-
s.add_runtime_dependency(%q<after_commit_action
|
125
|
-
s.add_runtime_dependency(%q<activerecord
|
126
|
-
s.add_runtime_dependency(%q<activesupport
|
127
|
-
s.add_development_dependency(%q<rake
|
128
|
-
s.add_development_dependency(%q<rails
|
129
|
-
s.add_development_dependency(%q<rspec
|
130
|
-
s.add_development_dependency(%q<awesome_print
|
131
|
-
s.add_development_dependency(%q<timecop
|
132
|
-
s.add_development_dependency(%q<rdoc
|
133
|
-
s.add_development_dependency(%q<bundler
|
134
|
-
s.add_development_dependency(%q<jeweler
|
123
|
+
s.add_runtime_dependency(%q<after_commit_action>.freeze, ["~> 1.0"])
|
124
|
+
s.add_runtime_dependency(%q<activerecord>.freeze, [">= 3.0.0"])
|
125
|
+
s.add_runtime_dependency(%q<activesupport>.freeze, [">= 3.0.0"])
|
126
|
+
s.add_development_dependency(%q<rake>.freeze, [">= 0"])
|
127
|
+
s.add_development_dependency(%q<rails>.freeze, [">= 3.1.0"])
|
128
|
+
s.add_development_dependency(%q<rspec>.freeze, ["~> 3.0"])
|
129
|
+
s.add_development_dependency(%q<awesome_print>.freeze, [">= 0"])
|
130
|
+
s.add_development_dependency(%q<timecop>.freeze, [">= 0"])
|
131
|
+
s.add_development_dependency(%q<rdoc>.freeze, ["~> 3.12"])
|
132
|
+
s.add_development_dependency(%q<bundler>.freeze, [">= 1.2.0"])
|
133
|
+
s.add_development_dependency(%q<jeweler>.freeze, ["~> 2.1"])
|
135
134
|
else
|
136
|
-
s.add_dependency(%q<after_commit_action
|
137
|
-
s.add_dependency(%q<activerecord
|
138
|
-
s.add_dependency(%q<activesupport
|
139
|
-
s.add_dependency(%q<rake
|
140
|
-
s.add_dependency(%q<rails
|
141
|
-
s.add_dependency(%q<rspec
|
142
|
-
s.add_dependency(%q<awesome_print
|
143
|
-
s.add_dependency(%q<timecop
|
144
|
-
s.add_dependency(%q<rdoc
|
145
|
-
s.add_dependency(%q<bundler
|
146
|
-
s.add_dependency(%q<jeweler
|
135
|
+
s.add_dependency(%q<after_commit_action>.freeze, ["~> 1.0"])
|
136
|
+
s.add_dependency(%q<activerecord>.freeze, [">= 3.0.0"])
|
137
|
+
s.add_dependency(%q<activesupport>.freeze, [">= 3.0.0"])
|
138
|
+
s.add_dependency(%q<rake>.freeze, [">= 0"])
|
139
|
+
s.add_dependency(%q<rails>.freeze, [">= 3.1.0"])
|
140
|
+
s.add_dependency(%q<rspec>.freeze, ["~> 3.0"])
|
141
|
+
s.add_dependency(%q<awesome_print>.freeze, [">= 0"])
|
142
|
+
s.add_dependency(%q<timecop>.freeze, [">= 0"])
|
143
|
+
s.add_dependency(%q<rdoc>.freeze, ["~> 3.12"])
|
144
|
+
s.add_dependency(%q<bundler>.freeze, [">= 1.2.0"])
|
145
|
+
s.add_dependency(%q<jeweler>.freeze, ["~> 2.1"])
|
147
146
|
end
|
148
147
|
else
|
149
|
-
s.add_dependency(%q<after_commit_action
|
150
|
-
s.add_dependency(%q<activerecord
|
151
|
-
s.add_dependency(%q<activesupport
|
152
|
-
s.add_dependency(%q<rake
|
153
|
-
s.add_dependency(%q<rails
|
154
|
-
s.add_dependency(%q<rspec
|
155
|
-
s.add_dependency(%q<awesome_print
|
156
|
-
s.add_dependency(%q<timecop
|
157
|
-
s.add_dependency(%q<rdoc
|
158
|
-
s.add_dependency(%q<bundler
|
159
|
-
s.add_dependency(%q<jeweler
|
148
|
+
s.add_dependency(%q<after_commit_action>.freeze, ["~> 1.0"])
|
149
|
+
s.add_dependency(%q<activerecord>.freeze, [">= 3.0.0"])
|
150
|
+
s.add_dependency(%q<activesupport>.freeze, [">= 3.0.0"])
|
151
|
+
s.add_dependency(%q<rake>.freeze, [">= 0"])
|
152
|
+
s.add_dependency(%q<rails>.freeze, [">= 3.1.0"])
|
153
|
+
s.add_dependency(%q<rspec>.freeze, ["~> 3.0"])
|
154
|
+
s.add_dependency(%q<awesome_print>.freeze, [">= 0"])
|
155
|
+
s.add_dependency(%q<timecop>.freeze, [">= 0"])
|
156
|
+
s.add_dependency(%q<rdoc>.freeze, ["~> 3.12"])
|
157
|
+
s.add_dependency(%q<bundler>.freeze, [">= 1.2.0"])
|
158
|
+
s.add_dependency(%q<jeweler>.freeze, ["~> 2.1"])
|
160
159
|
end
|
161
160
|
end
|
162
161
|
|
@@ -38,8 +38,7 @@ module CounterCulture
|
|
38
38
|
|
39
39
|
if id_to_change && change_counter_column
|
40
40
|
delta_magnitude = if delta_column
|
41
|
-
|
42
|
-
obj.send(delta_attr_name) || 0
|
41
|
+
(options[:was] ? attribute_was(obj, delta_column) : obj.public_send(delta_column)) || 0
|
43
42
|
else
|
44
43
|
counter_delta_magnitude_for(obj)
|
45
44
|
end
|
@@ -112,7 +111,7 @@ module CounterCulture
|
|
112
111
|
first_relation = relation.first
|
113
112
|
if was
|
114
113
|
first = relation.shift
|
115
|
-
foreign_key_value = obj
|
114
|
+
foreign_key_value = attribute_was(obj, relation_foreign_key(first))
|
116
115
|
klass = relation_klass(first)
|
117
116
|
value = klass.where("#{klass.table_name}.#{relation_primary_key(first)} = ?", foreign_key_value).first if foreign_key_value
|
118
117
|
else
|
@@ -181,8 +180,10 @@ module CounterCulture
|
|
181
180
|
def previous_model(obj)
|
182
181
|
prev = obj.dup
|
183
182
|
|
184
|
-
|
185
|
-
|
183
|
+
changes_method = Rails.version >= "5.1.0" ? :saved_changes : :changed_attributes
|
184
|
+
obj.public_send(changes_method).each do |key, value|
|
185
|
+
old_value = Rails.version >= "5.1.0" ? value.first : value
|
186
|
+
prev.public_send("#{key}=", old_value)
|
186
187
|
end
|
187
188
|
|
188
189
|
prev
|
@@ -197,5 +198,15 @@ module CounterCulture
|
|
197
198
|
yield
|
198
199
|
end
|
199
200
|
end
|
201
|
+
|
202
|
+
def attribute_was(obj, attr)
|
203
|
+
changes_method =
|
204
|
+
if Rails.version >= "5.1.0"
|
205
|
+
"_before_last_save"
|
206
|
+
else
|
207
|
+
"_was"
|
208
|
+
end
|
209
|
+
obj.public_send("#{attr}#{changes_method}")
|
210
|
+
end
|
200
211
|
end
|
201
212
|
end
|
@@ -1,7 +1,7 @@
|
|
1
1
|
module CounterCulture
|
2
2
|
module Extensions
|
3
3
|
extend ActiveSupport::Concern
|
4
|
-
|
4
|
+
|
5
5
|
module ClassMethods
|
6
6
|
# this holds all configuration data
|
7
7
|
def after_commit_counter_cache
|
@@ -27,7 +27,7 @@ module CounterCulture
|
|
27
27
|
end
|
28
28
|
|
29
29
|
if options[:column_names] && !options[:column_names].is_a?(Hash)
|
30
|
-
raise ":column_names must be a Hash of conditions and column names"
|
30
|
+
raise ":column_names must be a Hash of conditions and column names"
|
31
31
|
end
|
32
32
|
|
33
33
|
# add the counter to our collection
|
@@ -111,9 +111,14 @@ module CounterCulture
|
|
111
111
|
counter_cache_name_was = counter.counter_cache_name_for(counter.previous_model(self))
|
112
112
|
counter_cache_name = counter.counter_cache_name_for(self)
|
113
113
|
|
114
|
-
if
|
115
|
-
|
116
|
-
|
114
|
+
if Rails.version >= "5.1.0"
|
115
|
+
foreign_key_changed = saved_changes[counter.first_level_relation_foreign_key].present?
|
116
|
+
delta_column_changed = (counter.delta_column && saved_changes[counter.delta_column].present?)
|
117
|
+
else
|
118
|
+
foreign_key_changed = attribute_changed?(counter.first_level_relation_foreign_key)
|
119
|
+
delta_column_changed = (counter.delta_column && attribute_changed?(counter.delta_column))
|
120
|
+
end
|
121
|
+
if foreign_key_changed || delta_column_changed || counter_cache_name != counter_cache_name_was
|
117
122
|
|
118
123
|
# increment the counter cache of the new value
|
119
124
|
counter.change_counter_cache(self, :increment => true, :counter_column => counter_cache_name)
|
@@ -125,4 +130,4 @@ module CounterCulture
|
|
125
130
|
end
|
126
131
|
|
127
132
|
end
|
128
|
-
end
|
133
|
+
end
|
@@ -1500,6 +1500,12 @@ describe "CounterCulture" do
|
|
1500
1500
|
it "should return a copy of the original model" do
|
1501
1501
|
user.name = "Joe Smith"
|
1502
1502
|
user.manages_company_id = 2
|
1503
|
+
|
1504
|
+
if Rails.version >= "5.1.0"
|
1505
|
+
# must save to make the actual "saved_changes" available in Rails 5.1
|
1506
|
+
# whereas we simply use the "changed_attributes" before that
|
1507
|
+
user.save!
|
1508
|
+
end
|
1503
1509
|
prev = CounterCulture::Counter.new(user, :foobar, {}).previous_model(user)
|
1504
1510
|
|
1505
1511
|
expect(prev.name).to eq("John Smith")
|
@@ -7,9 +7,6 @@ RailsApp::Application.configure do
|
|
7
7
|
# and recreated between test runs. Don't rely on the data there!
|
8
8
|
config.cache_classes = true
|
9
9
|
|
10
|
-
# Configure static asset server for tests with Cache-Control for performance
|
11
|
-
config.serve_static_files = true
|
12
|
-
|
13
10
|
# Show full error reports and disable caching
|
14
11
|
config.consider_all_requests_local = true
|
15
12
|
config.action_controller.perform_caching = false
|
data/spec/spec_helper.rb
CHANGED
@@ -8,10 +8,15 @@ require "rails_app/config/environment"
|
|
8
8
|
require 'rspec'
|
9
9
|
require 'counter_culture'
|
10
10
|
|
11
|
-
load "#{File.dirname(__FILE__)}/schema.rb"
|
12
|
-
|
13
11
|
CI_TEST_RUN = (ENV['TRAVIS'] && 'TRAVIS') || (ENV['CIRCLECI'] && 'CIRCLE') || ENV["CI"] && 'CI'
|
14
12
|
|
13
|
+
begin
|
14
|
+
was, ActiveRecord::Migration.verbose = ActiveRecord::Migration.verbose, false unless ENV['SHOW_MIGRATION_MESSAGES']
|
15
|
+
load "#{File.dirname(__FILE__)}/schema.rb"
|
16
|
+
ensure
|
17
|
+
ActiveRecord::Migration.verbose = was unless ENV['SHOW_MIGRATION_MESSAGES']
|
18
|
+
end
|
19
|
+
|
15
20
|
# Requires supporting files with custom matchers and macros, etc,
|
16
21
|
# in ./support/ and its subdirectories.
|
17
22
|
Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each {|f| require f}
|
data/test_rails_versions.sh
CHANGED
@@ -2,8 +2,12 @@
|
|
2
2
|
|
3
3
|
set -e
|
4
4
|
|
5
|
-
for RAILS_VERSION in "3.2.0" "4.0.0" "4.1.0" "5.0.0"
|
5
|
+
for RAILS_VERSION in "3.2.0" "4.0.0" "4.1.0" "4.2.0" "5.0.0" "5.1.0.rc1"
|
6
6
|
do
|
7
|
+
export RAILS_VERSION
|
8
|
+
echo "Rails $RAILS_VERSION"
|
7
9
|
bundle update
|
8
10
|
bundle exec rspec spec
|
9
11
|
done
|
12
|
+
|
13
|
+
unset RAILS_VERSION
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: counter_culture
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.4.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Magnus von Koeller
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2017-
|
11
|
+
date: 2017-03-21 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: after_commit_action
|
@@ -181,7 +181,6 @@ files:
|
|
181
181
|
- ".travis.yml"
|
182
182
|
- CHANGELOG.md
|
183
183
|
- Gemfile
|
184
|
-
- Gemfile.lock
|
185
184
|
- LICENSE.txt
|
186
185
|
- README.md
|
187
186
|
- Rakefile
|
@@ -287,7 +286,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
287
286
|
version: '0'
|
288
287
|
requirements: []
|
289
288
|
rubyforge_project:
|
290
|
-
rubygems_version: 2.
|
289
|
+
rubygems_version: 2.6.10
|
291
290
|
signing_key:
|
292
291
|
specification_version: 4
|
293
292
|
summary: Turbo-charged counter caches for your Rails app.
|
data/Gemfile.lock
DELETED
@@ -1,189 +0,0 @@
|
|
1
|
-
GEM
|
2
|
-
remote: https://rubygems.org/
|
3
|
-
specs:
|
4
|
-
actioncable (5.0.1)
|
5
|
-
actionpack (= 5.0.1)
|
6
|
-
nio4r (~> 1.2)
|
7
|
-
websocket-driver (~> 0.6.1)
|
8
|
-
actionmailer (5.0.1)
|
9
|
-
actionpack (= 5.0.1)
|
10
|
-
actionview (= 5.0.1)
|
11
|
-
activejob (= 5.0.1)
|
12
|
-
mail (~> 2.5, >= 2.5.4)
|
13
|
-
rails-dom-testing (~> 2.0)
|
14
|
-
actionpack (5.0.1)
|
15
|
-
actionview (= 5.0.1)
|
16
|
-
activesupport (= 5.0.1)
|
17
|
-
rack (~> 2.0)
|
18
|
-
rack-test (~> 0.6.3)
|
19
|
-
rails-dom-testing (~> 2.0)
|
20
|
-
rails-html-sanitizer (~> 1.0, >= 1.0.2)
|
21
|
-
actionview (5.0.1)
|
22
|
-
activesupport (= 5.0.1)
|
23
|
-
builder (~> 3.1)
|
24
|
-
erubis (~> 2.7.0)
|
25
|
-
rails-dom-testing (~> 2.0)
|
26
|
-
rails-html-sanitizer (~> 1.0, >= 1.0.2)
|
27
|
-
activejob (5.0.1)
|
28
|
-
activesupport (= 5.0.1)
|
29
|
-
globalid (>= 0.3.6)
|
30
|
-
activemodel (5.0.1)
|
31
|
-
activesupport (= 5.0.1)
|
32
|
-
activerecord (5.0.1)
|
33
|
-
activemodel (= 5.0.1)
|
34
|
-
activesupport (= 5.0.1)
|
35
|
-
arel (~> 7.0)
|
36
|
-
activesupport (5.0.1)
|
37
|
-
concurrent-ruby (~> 1.0, >= 1.0.2)
|
38
|
-
i18n (~> 0.7)
|
39
|
-
minitest (~> 5.1)
|
40
|
-
tzinfo (~> 1.1)
|
41
|
-
addressable (2.5.0)
|
42
|
-
public_suffix (~> 2.0, >= 2.0.2)
|
43
|
-
after_commit_action (1.0.1)
|
44
|
-
activerecord (>= 3.0.0)
|
45
|
-
activesupport (>= 3.0.0)
|
46
|
-
arel (7.1.4)
|
47
|
-
awesome_print (1.7.0)
|
48
|
-
builder (3.2.3)
|
49
|
-
concurrent-ruby (1.0.4)
|
50
|
-
database_cleaner (1.5.3)
|
51
|
-
descendants_tracker (0.0.4)
|
52
|
-
thread_safe (~> 0.3, >= 0.3.1)
|
53
|
-
diff-lcs (1.3)
|
54
|
-
erubis (2.7.0)
|
55
|
-
faraday (0.9.2)
|
56
|
-
multipart-post (>= 1.2, < 3)
|
57
|
-
git (1.3.0)
|
58
|
-
github_api (0.11.3)
|
59
|
-
addressable (~> 2.3)
|
60
|
-
descendants_tracker (~> 0.0.1)
|
61
|
-
faraday (~> 0.8, < 0.10)
|
62
|
-
hashie (>= 1.2)
|
63
|
-
multi_json (>= 1.7.5, < 2.0)
|
64
|
-
nokogiri (~> 1.6.0)
|
65
|
-
oauth2
|
66
|
-
globalid (0.3.7)
|
67
|
-
activesupport (>= 4.1.0)
|
68
|
-
hashie (3.5.3)
|
69
|
-
highline (1.7.8)
|
70
|
-
i18n (0.8.0)
|
71
|
-
jeweler (2.3.3)
|
72
|
-
builder
|
73
|
-
bundler (>= 1.0)
|
74
|
-
git (>= 1.2.5)
|
75
|
-
github_api (~> 0.11.0)
|
76
|
-
highline (>= 1.6.15)
|
77
|
-
nokogiri (>= 1.5.10)
|
78
|
-
psych (~> 2.2)
|
79
|
-
rake
|
80
|
-
rdoc
|
81
|
-
semver2
|
82
|
-
json (1.8.6)
|
83
|
-
jwt (1.5.6)
|
84
|
-
loofah (2.0.3)
|
85
|
-
nokogiri (>= 1.5.9)
|
86
|
-
mail (2.6.4)
|
87
|
-
mime-types (>= 1.16, < 4)
|
88
|
-
method_source (0.8.2)
|
89
|
-
mime-types (3.1)
|
90
|
-
mime-types-data (~> 3.2015)
|
91
|
-
mime-types-data (3.2016.0521)
|
92
|
-
mini_portile2 (2.1.0)
|
93
|
-
minitest (5.10.1)
|
94
|
-
multi_json (1.12.1)
|
95
|
-
multi_xml (0.6.0)
|
96
|
-
multipart-post (2.0.0)
|
97
|
-
nio4r (1.2.1)
|
98
|
-
nokogiri (1.6.8.1)
|
99
|
-
mini_portile2 (~> 2.1.0)
|
100
|
-
oauth2 (1.3.0)
|
101
|
-
faraday (>= 0.8, < 0.11)
|
102
|
-
jwt (~> 1.0)
|
103
|
-
multi_json (~> 1.3)
|
104
|
-
multi_xml (~> 0.5)
|
105
|
-
rack (>= 1.2, < 3)
|
106
|
-
psych (2.2.2)
|
107
|
-
public_suffix (2.0.5)
|
108
|
-
rack (2.0.1)
|
109
|
-
rack-test (0.6.3)
|
110
|
-
rack (>= 1.0)
|
111
|
-
rails (5.0.1)
|
112
|
-
actioncable (= 5.0.1)
|
113
|
-
actionmailer (= 5.0.1)
|
114
|
-
actionpack (= 5.0.1)
|
115
|
-
actionview (= 5.0.1)
|
116
|
-
activejob (= 5.0.1)
|
117
|
-
activemodel (= 5.0.1)
|
118
|
-
activerecord (= 5.0.1)
|
119
|
-
activesupport (= 5.0.1)
|
120
|
-
bundler (>= 1.3.0, < 2.0)
|
121
|
-
railties (= 5.0.1)
|
122
|
-
sprockets-rails (>= 2.0.0)
|
123
|
-
rails-dom-testing (2.0.2)
|
124
|
-
activesupport (>= 4.2.0, < 6.0)
|
125
|
-
nokogiri (~> 1.6)
|
126
|
-
rails-html-sanitizer (1.0.3)
|
127
|
-
loofah (~> 2.0)
|
128
|
-
railties (5.0.1)
|
129
|
-
actionpack (= 5.0.1)
|
130
|
-
activesupport (= 5.0.1)
|
131
|
-
method_source
|
132
|
-
rake (>= 0.8.7)
|
133
|
-
thor (>= 0.18.1, < 2.0)
|
134
|
-
rake (12.0.0)
|
135
|
-
rdoc (3.12.2)
|
136
|
-
json (~> 1.4)
|
137
|
-
rspec (3.5.0)
|
138
|
-
rspec-core (~> 3.5.0)
|
139
|
-
rspec-expectations (~> 3.5.0)
|
140
|
-
rspec-mocks (~> 3.5.0)
|
141
|
-
rspec-core (3.5.4)
|
142
|
-
rspec-support (~> 3.5.0)
|
143
|
-
rspec-expectations (3.5.0)
|
144
|
-
diff-lcs (>= 1.2.0, < 2.0)
|
145
|
-
rspec-support (~> 3.5.0)
|
146
|
-
rspec-extra-formatters (1.0.0)
|
147
|
-
rspec-mocks (3.5.0)
|
148
|
-
diff-lcs (>= 1.2.0, < 2.0)
|
149
|
-
rspec-support (~> 3.5.0)
|
150
|
-
rspec-support (3.5.0)
|
151
|
-
semver2 (3.4.2)
|
152
|
-
sprockets (3.7.1)
|
153
|
-
concurrent-ruby (~> 1.0)
|
154
|
-
rack (> 1, < 3)
|
155
|
-
sprockets-rails (3.2.0)
|
156
|
-
actionpack (>= 4.0)
|
157
|
-
activesupport (>= 4.0)
|
158
|
-
sprockets (>= 3.0.0)
|
159
|
-
sqlite3 (1.3.13)
|
160
|
-
thor (0.19.4)
|
161
|
-
thread_safe (0.3.5)
|
162
|
-
timecop (0.8.1)
|
163
|
-
tzinfo (1.2.2)
|
164
|
-
thread_safe (~> 0.1)
|
165
|
-
websocket-driver (0.6.5)
|
166
|
-
websocket-extensions (>= 0.1.0)
|
167
|
-
websocket-extensions (0.1.2)
|
168
|
-
|
169
|
-
PLATFORMS
|
170
|
-
ruby
|
171
|
-
|
172
|
-
DEPENDENCIES
|
173
|
-
activerecord (>= 3.0.0)
|
174
|
-
activesupport (>= 3.0.0)
|
175
|
-
after_commit_action (~> 1.0)
|
176
|
-
awesome_print
|
177
|
-
bundler (>= 1.2.0)
|
178
|
-
database_cleaner (>= 1.1.1)
|
179
|
-
jeweler (~> 2.1)
|
180
|
-
rails (>= 3.1.0)
|
181
|
-
rake
|
182
|
-
rdoc (~> 3.12)
|
183
|
-
rspec (~> 3.0)
|
184
|
-
rspec-extra-formatters
|
185
|
-
sqlite3
|
186
|
-
timecop
|
187
|
-
|
188
|
-
BUNDLED WITH
|
189
|
-
1.14.4
|