counter_cache_with_conditions 0.9.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.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 9c4e95d3320ffd49431b25befe2d0aad3ef178b9
4
+ data.tar.gz: a6e2b5e5b8ff04731cdc1f18297517da4198c52e
5
+ SHA512:
6
+ metadata.gz: d3eb25c1cc41a0cde506c5b8b35360a21101c733a2363010df54b188550c95447d335f637facbc6e9210f65d0b652ca1cabbe3fc6999c2f4781237b2ce426a16
7
+ data.tar.gz: 5b6f62df86215a04dbfe85d5f6c93e08fb5b6163b965aca7c4fc192994c98852eb69e268580285a4e5a981b7b9735c1ff9eb4856951d1cec6c8ef9c76b944023
data/.gitignore ADDED
@@ -0,0 +1,8 @@
1
+ *.gem
2
+ .DS_Store
3
+ /.bundle
4
+ /Gemfile.lock
5
+ /tmp
6
+ /test/debug.log
7
+ /.ruby-gemset
8
+ /.ruby-version
data/Gemfile ADDED
@@ -0,0 +1,5 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gemspec
4
+
5
+ gem 'sqlite3', '~> 1.3.8'
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2013 Sergey Kojin
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,36 @@
1
+ # Counter Cache With Conditions
2
+
3
+ Replacement for ActiveRecord belongs_to :counter_cache with ability to specify conditions.
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ gem 'counter_cache_with_conditions'
10
+
11
+ And then execute:
12
+
13
+ $ bundle
14
+
15
+ Or install it yourself as:
16
+
17
+ $ gem install counter_cache_with_conditions
18
+
19
+ ## Usage
20
+
21
+ When additional counter cache need
22
+
23
+ belongs_to :folder, :counter_cache => true
24
+ counter_cache_with_conditions :folder, :unread_messages_count, :unread => true
25
+
26
+ Or as replacement for rails build in solution.
27
+
28
+ belongs_to :folder
29
+ counter_cache_with_conditions :folder, :messages_count, {}
30
+ counter_cache_with_conditions :folder, :unread_messages_count, :unread => true
31
+ counter_cache_with_conditions :folder, :unread_messages_count, [:read, :source], lambda{|read, source| read == false && source == 'message'}
32
+ counter_cache_with_conditions :folder, :published_events_count, [:published_at], lambda{|published_at| published_at != nil }
33
+
34
+
35
+
36
+ Copyright (c) 2010 Sergey Kojin, released under the MIT license
data/Rakefile ADDED
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env rake
2
+
3
+ require "bundler/gem_tasks"
4
+ require "rake/testtask"
5
+
6
+ desc "Default: run unit tests."
7
+ task :default => :test
8
+
9
+ desc "Test the acts_as_archival plugin."
10
+ Rake::TestTask.new(:test) do |t|
11
+ t.libs << "test"
12
+ t.pattern = "test/**/*_test.rb"
13
+ t.verbose = true
14
+ end
@@ -0,0 +1,19 @@
1
+ # coding: utf-8
2
+
3
+ Gem::Specification.new do |s|
4
+ s.name = "counter_cache_with_conditions"
5
+ s.version = "0.9.2"
6
+ s.authors = ["Sergey Kojin"]
7
+ s.email = ["sergey.kojin@gmail.com"]
8
+ s.description = %q{Replacement for ActiveRecord belongs_to :counter_cache with ability to specify conditions.}
9
+ s.summary = %q{ActiveRecord counter_cache with conditions.}
10
+ s.homepage = "https://github.com/skojin/counter_cache_with_conditions"
11
+ s.license = "MIT"
12
+
13
+ s.files = `git ls-files`.split($/)
14
+ s.executables = s.files.grep(%r{^bin/}) { |f| File.basename(f) }
15
+ s.test_files = s.files.grep(%r{^(test|spec|features)/})
16
+ s.require_paths = ["lib"]
17
+
18
+ s.add_dependency "activerecord", '>= 3.2'
19
+ end
@@ -0,0 +1,3 @@
1
+ require 'counter_cache_with_conditions/active_record'
2
+
3
+ ActiveRecord::Base.extend CounterCacheWithConditions::ActiveRecord
@@ -0,0 +1,100 @@
1
+ module CounterCacheWithConditions
2
+ module ActiveRecord
3
+
4
+ # @param association_name extended belongs_to association name (like :user)
5
+ # @param counter_name name of counter cache column
6
+ # @param conditions hash with equal conditions, like {:read => false, :source => 'message'}, no nesting
7
+ # @param conditions array with checked attributes names, in this case block is required.
8
+ # usage looks like [:read, :source], lambda{|read, source| read == false && source == 'message'}
9
+ # @param block proc object that take list of arguments specified in conditions parameter, should compare them and return boolean
10
+ def counter_cache_with_conditions(association_name, counter_name, conditions, block = nil)
11
+ unless ancestors.include? InstanceMethods
12
+ include InstanceMethods
13
+ after_create :counter_cache_with_conditions_after_create
14
+ before_update :counter_cache_with_conditions_before_update
15
+ before_destroy :counter_cache_with_conditions_before_destroy
16
+
17
+ cattr_accessor :counter_cache_with_conditions_options
18
+ self.counter_cache_with_conditions_options = []
19
+ end
20
+
21
+ # TODO make readonly
22
+ ref = reflect_on_association(association_name)
23
+ ref.klass.send(:attr_readonly, counter_name.to_sym) if ref.klass.respond_to?(:attr_readonly)
24
+ conditions = [conditions, block] if conditions.is_a? Array
25
+ self.counter_cache_with_conditions_options << [ref.klass, ref.foreign_key, counter_name, conditions]
26
+ end
27
+
28
+ module InstanceMethods
29
+ private
30
+ def counter_cache_with_conditions_after_create
31
+ self.counter_cache_with_conditions_options.each do |klass, foreign_key, counter_name, conditions|
32
+ if counter_conditions_match?(conditions)
33
+ association_id = send(foreign_key)
34
+ klass.increment_counter(counter_name, association_id) if association_id
35
+ end
36
+ end
37
+ end
38
+
39
+ def counter_cache_with_conditions_before_update
40
+ self.counter_cache_with_conditions_options.each do |klass, foreign_key, counter_name, conditions|
41
+ match_before = counter_conditions_without_changes_match?(conditions)
42
+ match_now = counter_conditions_match?(conditions)
43
+ if match_now && !match_before
44
+ ccwc_update_counter_on(klass, foreign_key, counter_name, 1, 0)
45
+ elsif !match_now && match_before && send("#{foreign_key}_changed?")
46
+ # decrement only old, if association changed and condition broken
47
+ ccwc_update_counter_on(klass, foreign_key, counter_name, 0, -1)
48
+ elsif !match_now && match_before
49
+ ccwc_update_counter_on(klass, foreign_key, counter_name, -1, -1)
50
+ elsif match_now && send("#{foreign_key}_changed?")
51
+ # if just association changed, decrement old, increment new
52
+ ccwc_update_counter_on(klass, foreign_key, counter_name, 1, -1)
53
+ end
54
+ end
55
+ end
56
+
57
+ def counter_cache_with_conditions_before_destroy
58
+ self.counter_cache_with_conditions_options.each do |klass, foreign_key, counter_name, conditions|
59
+ if counter_conditions_without_changes_match?(conditions)
60
+ association_was = attribute_was(foreign_key.to_s)
61
+ klass.decrement_counter(counter_name, association_was) if association_was
62
+ end
63
+ end
64
+ end
65
+
66
+
67
+ def counter_conditions_match?(conditions)
68
+ if conditions.is_a? Array
69
+ attr_names, block = conditions
70
+ block.call(*attr_names.map { |attr| send(attr) })
71
+ else
72
+ conditions.all? { |attr, value| send(attr) == value }
73
+ end
74
+ end
75
+
76
+ def counter_conditions_without_changes_match?(conditions)
77
+ if conditions.is_a? Array
78
+ attr_names, block = conditions
79
+ block.call(*attr_names.map { |attr| attribute_was(attr.to_s) })
80
+ else
81
+ conditions.all? { |attr, value| attribute_was(attr.to_s) == value }
82
+ end
83
+ end
84
+
85
+ # e.g. increment counter on association, and decrement it on old association if association was changed, and vice versa
86
+ # @param value (+1, -1)
87
+ # @param value_was value for old association (if association was changed)
88
+ def ccwc_update_counter_on(klass, foreign_key, counter_name, value, value_was = 0)
89
+ association_id = send(foreign_key)
90
+ klass.update_counters(association_id, counter_name => value) if association_id
91
+ if value_was != 0
92
+ association_was = attribute_was(foreign_key.to_s)
93
+ klass.update_counters(association_was, counter_name => value_was) if association_was && association_was != association_id
94
+ end
95
+ end
96
+
97
+ end
98
+
99
+ end
100
+ end
@@ -0,0 +1,73 @@
1
+ require File.dirname(__FILE__) + '/test_helper.rb'
2
+
3
+ class ActiveRecordCounterCacheTest < Test::Unit::TestCase
4
+ load_schema
5
+
6
+ class Folder < ActiveRecord::Base
7
+ has_many :messages
8
+ end
9
+
10
+ class Message < ActiveRecord::Base
11
+ # uncomment this, and comment out lines below, too see active record counter cache error
12
+ #belongs_to :folder, :counter_cache => true
13
+
14
+ belongs_to :folder
15
+ counter_cache_with_conditions :folder, :messages_count, {}
16
+ end
17
+
18
+ def teardown
19
+ Message.delete_all
20
+ Folder.delete_all
21
+ end
22
+
23
+ def test_schema_has_loaded_correctly
24
+ assert_equal [], Folder.all
25
+ assert_equal [], Message.all
26
+ end
27
+
28
+ # default rails counter tests
29
+ def test_default_counter_cache_should_increment_on_create
30
+ f, _ = build_fixture
31
+ assert_equal 1, f.reload.messages_count
32
+ end
33
+
34
+ def test_default_counter_cache_should_decrement_on_destroy
35
+ f, m = build_fixture
36
+ assert_equal 1, f.reload.messages_count
37
+ m.destroy
38
+ assert_equal 0, f.reload.messages_count
39
+ end
40
+
41
+ # active record counter cache fail on this
42
+ def test_default_counter_cache_not_update_counters_when_change_association_but_not_save
43
+ f1, m = build_fixture
44
+ assert_equal 1, f1.reload.messages_count
45
+ f2 = Folder.create
46
+ assert_equal 0, f2.reload.messages_count
47
+ m.folder = f2
48
+ assert_equal f1, m.reload.folder, "folder not changed"
49
+ assert_equal 1, f1.reload.messages_count
50
+ assert_equal 0, f2.reload.messages_count
51
+ end
52
+
53
+ # active record counter cache fail on this
54
+ def fail_test_default_counter_cache_update_counters_when_change_association_via_id
55
+ f1, m = build_fixture
56
+ assert_equal 1, f1.reload.messages_count
57
+ f2 = Folder.create
58
+ assert_equal 0, f2.reload.messages_count
59
+ m.folder_id = f2.id
60
+ m.save
61
+ assert_equal 0, f1.reload.messages_count
62
+ assert_equal 1, f2.reload.messages_count
63
+ end
64
+
65
+ private
66
+ def build_fixture(attributes = {})
67
+ f = Folder.create
68
+ m = f.messages.create attributes
69
+ [f, m]
70
+ end
71
+
72
+ end
73
+
@@ -0,0 +1,23 @@
1
+ require File.dirname(__FILE__) + '/test_helper'
2
+
3
+
4
+ class CounterCacheWithHashConditionsTest < Test::Unit::TestCase
5
+ load_schema
6
+ class Folder < ActiveRecord::Base
7
+ has_many :messages
8
+ end
9
+
10
+ class Message < ActiveRecord::Base
11
+ belongs_to :folder, :counter_cache => true
12
+ counter_cache_with_conditions :folder, :unread_messages_count, :unread => true
13
+ end
14
+
15
+ def teardown
16
+ Message.delete_all
17
+ Folder.delete_all
18
+ end
19
+
20
+ eval IO.read(File.dirname(__FILE__) + '/unread_messages_count_tests.rb')
21
+
22
+ end
23
+
@@ -0,0 +1,25 @@
1
+ require File.dirname(__FILE__) + '/test_helper'
2
+ require File.dirname(__FILE__) + '/unread_messages_count_tests'
3
+
4
+ class CounterCacheWithLambdaConditionsTest < Test::Unit::TestCase
5
+ load_schema
6
+
7
+ class Folder < ActiveRecord::Base
8
+ has_many :messages
9
+ end
10
+
11
+ class Message < ActiveRecord::Base
12
+ belongs_to :folder, :counter_cache => true
13
+ counter_cache_with_conditions :folder, :unread_messages_count, [:unread], lambda{|unread| unread == true}
14
+ end
15
+
16
+
17
+ def teardown
18
+ Message.delete_all
19
+ Folder.delete_all
20
+ end
21
+
22
+ eval IO.read(File.dirname(__FILE__) + '/unread_messages_count_tests.rb')
23
+
24
+ end
25
+
data/test/database.yml ADDED
@@ -0,0 +1,5 @@
1
+ sqlite3:
2
+ database: ":memory:"
3
+ adapter: sqlite3
4
+ timeout: 500
5
+
data/test/schema.rb ADDED
@@ -0,0 +1,15 @@
1
+ ActiveRecord::Schema.define do
2
+
3
+ create_table "folders", :force => true do |t|
4
+ t.integer "messages_count", :null => false, :default => 0
5
+ t.integer "unread_messages_count", :null => false, :default => 0
6
+ t.datetime "created_at"
7
+ t.datetime "updated_at"
8
+ end
9
+
10
+ create_table "messages", :force => true do |t|
11
+ t.belongs_to :folder
12
+ t.boolean "unread", :null => false, :default => true
13
+ end
14
+
15
+ end
@@ -0,0 +1,17 @@
1
+ $:.unshift(File.dirname(__FILE__) + '/../lib')
2
+ require "bundler/setup"
3
+ require "minitest/autorun"
4
+
5
+ require "active_record"
6
+
7
+ require 'test/unit'
8
+ require File.dirname(__FILE__) + '/../init.rb'
9
+ # ::ActiveRecord::Base.extend(ActiveRecord)
10
+
11
+ def load_schema
12
+ conf = YAML::load(File.open(File.dirname(__FILE__) + '/database.yml'))
13
+ # ActiveRecord::Base.logger = Logger.new(File.dirname(__FILE__) + "/debug.log")
14
+
15
+ ActiveRecord::Base.establish_connection(conf['sqlite3'])
16
+ load(File.dirname(__FILE__) + "/schema.rb")
17
+ end
@@ -0,0 +1,239 @@
1
+ # default rails counter tests
2
+ def test_default_counter_cache_should_increment_on_create
3
+ f, _ = build_fixture
4
+ assert_equal 1, f.reload.messages_count
5
+ end
6
+
7
+ def test_default_counter_cache_should_decrement_on_destroy
8
+ f, m = build_fixture
9
+ assert_equal 1, f.reload.messages_count
10
+ m.destroy
11
+ assert_equal 0, f.reload.messages_count
12
+ end
13
+
14
+ # custom counter tests
15
+
16
+ def test_should_increment_counter_on_create_when_condition_match
17
+ f, _ = build_fixture(:unread => true)
18
+ assert_equal 1, f.reload.unread_messages_count
19
+ end
20
+
21
+ def test_should_not_increment_counter_on_create_when_condition_not_match
22
+ f, _ = build_fixture(:unread => false)
23
+ assert_equal 0, f.reload.unread_messages_count
24
+ end
25
+
26
+ def test_should_decrement_counter_on_destroy_when_condition_match
27
+ f, m = build_fixture(:unread => true)
28
+ m.destroy
29
+ assert_equal 0, f.reload.unread_messages_count
30
+ end
31
+
32
+ def test_should_not_decrement_counter_on_destroy_when_condition_not_match
33
+ f, m = build_fixture(:unread => false)
34
+ m.destroy
35
+ assert_equal 0, f.reload.unread_messages_count
36
+ end
37
+
38
+ def test_should_decrement_counter_when_unread_unset_just_before_destroy
39
+ f, m = build_fixture(:unread => true)
40
+ m.unread = false
41
+ m.destroy
42
+ assert_equal 0, f.reload.unread_messages_count
43
+ end
44
+
45
+ def test_should_not_decrement_counter_when_unread_set_just_before_destroy
46
+ f, m = build_fixture(:unread => false)
47
+ m.unread = true
48
+ m.destroy
49
+ assert_equal 0, f.reload.unread_messages_count
50
+ end
51
+
52
+ def test_should_increment_counter_when_unread_set_on_update
53
+ f, m = build_fixture(:unread => false)
54
+ assert_equal 0, f.reload.unread_messages_count
55
+ m.update_attribute :unread, true
56
+ assert_equal 1, f.reload.unread_messages_count
57
+ end
58
+
59
+ def test_should_decrement_counter_when_unread_unset_on_update
60
+ f, m = build_fixture(:unread => true)
61
+ m.unread = false
62
+ m.save!
63
+ assert_equal 0, f.reload.unread_messages_count
64
+
65
+ f, m = build_fixture(:unread => true)
66
+ m.unread = true
67
+ m.save!
68
+ assert_equal 1, f.reload.unread_messages_count
69
+ end
70
+
71
+ def test_should_not_change_counter_when_unread_set_to_same_value_on_update
72
+ f, m = build_fixture(:unread => true)
73
+ assert_equal 1, f.reload.unread_messages_count
74
+ m.unread = true
75
+ m.save!
76
+ assert_equal 1, f.reload.unread_messages_count
77
+ end
78
+
79
+ # ---------- when association nillified ------------
80
+
81
+ def test_should_change_counter_when_unset_folder_for_unread
82
+ f, m = build_fixture(:unread => true)
83
+ m.folder = nil
84
+ m.save!
85
+ assert_equal 0, f.reload.unread_messages_count
86
+ end
87
+ def test_should_change_counter_when_unset_folder_id_for_unread
88
+ f, m = build_fixture(:unread => true)
89
+ m.folder_id = nil
90
+ m.save!
91
+ assert_equal 0, f.reload.unread_messages_count
92
+ end
93
+ def test_should_change_counter_when_unset_folder_and_unset_unread
94
+ f, m = build_fixture(:unread => true)
95
+ m.folder = nil
96
+ m.unread = false
97
+ m.save!
98
+ assert_equal 0, f.reload.unread_messages_count
99
+ end
100
+
101
+ def test_should_not_change_counter_when_unset_folder_id_for_read
102
+ f, m = build_fixture(:unread => false)
103
+ m.folder_id = nil
104
+ m.save!
105
+ assert_equal 0, f.reload.unread_messages_count
106
+ end
107
+
108
+ def test_should_not_change_counter_when_unset_folder_set_unread
109
+ f, m = build_fixture(:unread => false)
110
+ m.folder = nil
111
+ m.unread = true
112
+ m.save!
113
+ assert_equal 0, f.reload.unread_messages_count
114
+ end
115
+
116
+ # ---------- when association changed ------------
117
+
118
+ def test_should_not_change_counters_when_change_folder_for_read
119
+ f, m = build_fixture(:unread => false)
120
+ f2 = Folder.create!
121
+ m.folder = f2
122
+ m.save!
123
+ assert_equal 0, f.reload.unread_messages_count
124
+ assert_equal 0, f2.reload.unread_messages_count
125
+ end
126
+
127
+ def test_should_change_counter_when_change_folder_for_unread
128
+ f, m = build_fixture(:unread => true)
129
+ f2 = Folder.create!
130
+ m.folder = f2
131
+ m.save!
132
+ assert_equal 0, f.reload.unread_messages_count
133
+ assert_equal 1, f2.reload.unread_messages_count
134
+ end
135
+
136
+ # this test is important, it fail in process
137
+ def test_should_change_counter_on_old_and_skip_counter_on_new_when_change_folder_for_unread_with_status_change
138
+ f, m = build_fixture(:unread => true)
139
+ f2 = Folder.create!
140
+ m.folder = f2
141
+ m.unread = false
142
+ m.save!
143
+ assert_equal 0, f.reload.unread_messages_count
144
+ assert_equal 0, f2.reload.unread_messages_count
145
+ end
146
+
147
+ def test_should_ignore_counter_on_old_and_icrement_counter_on_new_when_change_folder_for_read_with_status_change
148
+ f, m = build_fixture(:unread => false)
149
+ f2 = Folder.create!
150
+ m.folder = f2
151
+ m.unread = true
152
+ m.save!
153
+ assert_equal 0, f.reload.unread_messages_count
154
+ assert_equal 1, f2.reload.unread_messages_count
155
+ end
156
+
157
+ # ---------- when association was nil ------------
158
+
159
+ def test_should_icrement_counter_when_assing_folder_for_unread
160
+ m = Message.create!(:unread => true)
161
+ f = Folder.create!
162
+ m.folder = f
163
+ m.save!
164
+ assert_equal 1, f.reload.unread_messages_count
165
+ end
166
+
167
+ def test_should_ignore_counter_when_assing_folder_for_read
168
+ m = Message.create!(:unread => false)
169
+ f = Folder.create!
170
+ m.folder = f
171
+ m.save!
172
+ assert_equal 0, f.reload.unread_messages_count
173
+ end
174
+
175
+ def test_should_ignore_counter_when_assing_folder_for_unread_and_mark_as_read
176
+ m = Message.create!(:unread => true)
177
+ f = Folder.create!
178
+ m.folder = f
179
+ m.unread = false
180
+ m.save!
181
+ assert_equal 0, f.reload.unread_messages_count
182
+ end
183
+
184
+ def test_should_increment_counter_when_assing_folder_for_read_and_mark_as_unread
185
+ m = Message.create!(:unread => false)
186
+ f = Folder.create!
187
+ m.folder = f
188
+ m.unread = true
189
+ m.save!
190
+ assert_equal 1, f.reload.unread_messages_count
191
+ end
192
+
193
+
194
+ # ---------- when association changed before destroy ------------
195
+
196
+ def test_should_decrement_counter_when_association_unset_just_before_destroy_when_match
197
+ f, m = build_fixture(:unread => true)
198
+ m.folder = nil
199
+ m.destroy
200
+ assert_equal 0, f.reload.unread_messages_count
201
+
202
+ # just to be sure, dublicate test with attribute change
203
+ f, m = build_fixture(:unread => true)
204
+ m.folder = nil
205
+ m.unread = false
206
+ m.destroy
207
+ assert_equal 0, f.reload.unread_messages_count
208
+ end
209
+
210
+ def test_should_not_decrement_counter_when_association_unset_just_before_destroy_when_not_match
211
+ f, m = build_fixture(:unread => false)
212
+ m.folder = nil
213
+ m.unread = true
214
+ m.destroy
215
+ assert_equal 0, f.reload.unread_messages_count
216
+
217
+ # just to be sure, dublicate test with attribute change
218
+ f, m = build_fixture(:unread => false)
219
+ m.folder = nil
220
+ m.unread = true
221
+ m.destroy
222
+ assert_equal 0, f.reload.unread_messages_count
223
+ end
224
+
225
+ def test_should_decrement_counter_when_association_changed_just_before_destroy_when_match
226
+ f, m = build_fixture(:unread => true)
227
+ f2 = Folder.create!
228
+ m.folder = f2
229
+ m.destroy
230
+ assert_equal 0, f.reload.unread_messages_count
231
+ assert_equal 0, f2.reload.unread_messages_count
232
+ end
233
+
234
+ private
235
+ def build_fixture(attributes = {})
236
+ f = Folder.create
237
+ m = f.messages.create attributes
238
+ [f, m]
239
+ end
metadata ADDED
@@ -0,0 +1,81 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: counter_cache_with_conditions
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.9.2
5
+ platform: ruby
6
+ authors:
7
+ - Sergey Kojin
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2017-03-10 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: activerecord
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - '>='
18
+ - !ruby/object:Gem::Version
19
+ version: '3.2'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - '>='
25
+ - !ruby/object:Gem::Version
26
+ version: '3.2'
27
+ description: Replacement for ActiveRecord belongs_to :counter_cache with ability to
28
+ specify conditions.
29
+ email:
30
+ - sergey.kojin@gmail.com
31
+ executables: []
32
+ extensions: []
33
+ extra_rdoc_files: []
34
+ files:
35
+ - .gitignore
36
+ - Gemfile
37
+ - LICENSE.txt
38
+ - README.md
39
+ - Rakefile
40
+ - counter_cache_with_conditions.gemspec
41
+ - lib/counter_cache_with_conditions.rb
42
+ - lib/counter_cache_with_conditions/active_record.rb
43
+ - test/active_record_counter_cache_test.rb
44
+ - test/counter_cache_with_hash_conditions_test.rb
45
+ - test/counter_cache_with_lambda_conditions_test.rb
46
+ - test/database.yml
47
+ - test/schema.rb
48
+ - test/test_helper.rb
49
+ - test/unread_messages_count_tests.rb
50
+ homepage: https://github.com/skojin/counter_cache_with_conditions
51
+ licenses:
52
+ - MIT
53
+ metadata: {}
54
+ post_install_message:
55
+ rdoc_options: []
56
+ require_paths:
57
+ - lib
58
+ required_ruby_version: !ruby/object:Gem::Requirement
59
+ requirements:
60
+ - - '>='
61
+ - !ruby/object:Gem::Version
62
+ version: '0'
63
+ required_rubygems_version: !ruby/object:Gem::Requirement
64
+ requirements:
65
+ - - '>='
66
+ - !ruby/object:Gem::Version
67
+ version: '0'
68
+ requirements: []
69
+ rubyforge_project:
70
+ rubygems_version: 2.2.1
71
+ signing_key:
72
+ specification_version: 4
73
+ summary: ActiveRecord counter_cache with conditions.
74
+ test_files:
75
+ - test/active_record_counter_cache_test.rb
76
+ - test/counter_cache_with_hash_conditions_test.rb
77
+ - test/counter_cache_with_lambda_conditions_test.rb
78
+ - test/database.yml
79
+ - test/schema.rb
80
+ - test/test_helper.rb
81
+ - test/unread_messages_count_tests.rb