counter_culture 1.6.0 → 1.6.1

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: 40d222184acc3b81f1abf7dfd2dbede253eacb7a
4
- data.tar.gz: bdf081ac5294d1a5a8b693c3639ccf82b0642e0b
3
+ metadata.gz: b2cbcbac5a73c66f70195da9047859c849d67166
4
+ data.tar.gz: 712abce425aae48e7b8decf15edaee9c921cf95c
5
5
  SHA512:
6
- metadata.gz: e81781257cff2487c108d441dfe92ea65bd5f8b42a90c61752d68fe7233d8aa30ebc90c8625c487626b7e461edfb36eaadde30aa539760dcb277a1a2fdd4f0bb
7
- data.tar.gz: f0c9a1687eff220ccd4d703e901e49f7ad0193207f5fbdcb3a00b5dbb6aea8fd6e288c1f77ad037c9125bee0ce07873ca8f0fb2c5ecddfdc40fc2698532d9d04
6
+ metadata.gz: c6fac4dfb787d6f232daa3d3387415b11504b965503a33d685bb6eb2730a6301a13d5c7e15e83f8f508d76c26be0d98da0c832e161dd4904159ac6d59a4d622a
7
+ data.tar.gz: 787de2041877eb28f2ef2027689c38c00fffdf8caa924cbe0538cdf159b774fdedfa5030a257ce2a9606e586aff9e9d350f81b8a07b7d750c3f448ca831405dd
data/CHANGELOG.md CHANGED
@@ -1,3 +1,8 @@
1
+ ## 1.6.1 (April 26, 2017)
2
+
3
+ Bugfixes:
4
+ - Fix `counter_culture_fix_counts` for a multi-level relation where an intermediate link is `has_one`, rather than `belongs_to`
5
+
1
6
  ## 1.6.0 (April 24, 2017)
2
7
 
3
8
  Improvements:
data/VERSION CHANGED
@@ -1 +1 @@
1
- 1.6.0
1
+ 1.6.1
@@ -2,16 +2,16 @@
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.6.0 ruby lib
5
+ # stub: counter_culture 1.6.1 ruby lib
6
6
 
7
7
  Gem::Specification.new do |s|
8
8
  s.name = "counter_culture".freeze
9
- s.version = "1.6.0"
9
+ s.version = "1.6.1"
10
10
 
11
11
  s.required_rubygems_version = Gem::Requirement.new(">= 0".freeze) if s.respond_to? :required_rubygems_version=
12
12
  s.require_paths = ["lib".freeze]
13
13
  s.authors = ["Magnus von Koeller".freeze]
14
- s.date = "2017-04-24"
14
+ s.date = "2017-04-26"
15
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
16
  s.email = "magnus@vonkoeller.de".freeze
17
17
  s.extra_rdoc_files = [
@@ -40,11 +40,14 @@ Gem::Specification.new do |s|
40
40
  "spec/counter_culture_spec.rb",
41
41
  "spec/models/another_post.rb",
42
42
  "spec/models/another_post_comment.rb",
43
+ "spec/models/candidate.rb",
44
+ "spec/models/candidate_profile.rb",
43
45
  "spec/models/categ.rb",
44
46
  "spec/models/category.rb",
45
47
  "spec/models/company.rb",
46
48
  "spec/models/conditional_dependent.rb",
47
49
  "spec/models/conditional_main.rb",
50
+ "spec/models/conversation.rb",
48
51
  "spec/models/has_string_id.rb",
49
52
  "spec/models/industry.rb",
50
53
  "spec/models/person.rb",
@@ -154,35 +154,55 @@ module CounterCulture
154
154
  def join_clauses
155
155
  return @join_clauses if defined?(@join_clauses)
156
156
 
157
- # we need to work our way back from the end-point of the relation to this class itself;
158
- # make a list of arrays pointing to the second-to-last, third-to-last, etc.
159
- reverse_relation = (1..relation.length).to_a.reverse.inject([]) { |a, i| a << relation[0, i]; a }
160
-
161
- # store joins in an array so that we can later apply column-specific conditions
157
+ # we need to work our way back from the end-point of the relation to
158
+ # this class itself; make a list of arrays pointing to the
159
+ # second-to-last, third-to-last, etc.
160
+ reverse_relation = (1..relation.length).to_a.reverse.
161
+ inject([]) { |a, i| a << relation[0, i]; a }
162
+
163
+ # store joins in an array so that we can later apply column-specific
164
+ # conditions
162
165
  @join_clauses = reverse_relation.map do |cur_relation|
163
166
  reflect = relation_reflect(cur_relation)
164
- if relation_class.table_name == reflect.active_record.table_name
165
- join_table_name = "#{relation_class.table_name}_#{relation_class.table_name}"
166
- else
167
- join_table_name = reflect.active_record.table_name
167
+
168
+ target_table_alias = target_table = reflect.active_record.table_name
169
+ if relation_class.table_name == target_table
170
+ # join with alias to avoid ambiguous table name in
171
+ # self-referential models
172
+ target_table_alias += "_#{target_table}"
168
173
  end
174
+
169
175
  if polymorphic?
170
176
  # NB: polymorphic only supports one level of relation (at present)
171
177
  association_primary_key = reflect.association_primary_key(relation_class)
172
- reflect_table_name = relation_class.table_name
178
+ source_table = relation_class.table_name
173
179
  else
174
180
  association_primary_key = reflect.association_primary_key
175
- reflect_table_name = reflect.table_name
181
+ source_table = reflect.table_name
176
182
  end
177
183
 
178
- # join with alias to avoid ambiguous table name with self-referential models:
179
- joins_sql = "LEFT JOIN #{reflect.active_record.table_name} AS #{join_table_name} ON #{reflect_table_name}.#{association_primary_key} = #{join_table_name}.#{reflect.foreign_key}"
180
- # adds 'type' condition to JOIN clause if the current model is a child in a Single Table Inheritance
181
- joins_sql = "#{joins_sql} AND #{reflect.active_record.table_name}.type IN ('#{model.name}')" if reflect.active_record.column_names.include?('type') && !model.descends_from_active_record?
184
+ source_table_key = association_primary_key
185
+ target_table_key = reflect.foreign_key
186
+ if reflect.has_one?
187
+ # a has_one relation flips the location of the keys on the tables
188
+ # around
189
+ (source_table_key, target_table_key) =
190
+ [target_table_key, source_table_key]
191
+ end
192
+
193
+ joins_sql = "LEFT JOIN #{target_table} AS #{target_table_alias} "\
194
+ "ON #{source_table}.#{source_table_key} = #{target_table_alias}.#{target_table_key}"
195
+ # adds 'type' condition to JOIN clause if the current model is a
196
+ # child in a Single Table Inheritance
197
+ if reflect.active_record.column_names.include?('type') &&
198
+ !model.descends_from_active_record?
199
+ joins_sql += " AND #{target_table}.type IN ('#{model.name}')"
200
+ end
182
201
  if polymorphic?
183
- # adds 'type' condition to JOIN clause if the current model is a polymorphic relation
202
+ # adds 'type' condition to JOIN clause if the current model is a
203
+ # polymorphic relation
184
204
  # NB only works for one-level relations
185
- joins_sql = "#{joins_sql} AND #{reflect.active_record.table_name}.#{reflect.foreign_type} = '#{relation_class.name}'"
205
+ joins_sql += " AND #{target_table}.#{reflect.foreign_type} = '#{relation_class.name}'"
186
206
  end
187
207
  joins_sql
188
208
  end
@@ -22,6 +22,9 @@ require 'models/another_post_comment'
22
22
  require 'models/person'
23
23
  require 'models/transaction'
24
24
  require 'models/soft_delete'
25
+ require 'models/conversation'
26
+ require 'models/candidate_profile'
27
+ require 'models/candidate'
25
28
 
26
29
  require 'database_cleaner'
27
30
  DatabaseCleaner.strategy = :deletion
@@ -1495,6 +1498,44 @@ describe "CounterCulture" do
1495
1498
  expect(categ.reload.posts_count).to eq(1)
1496
1499
  end
1497
1500
 
1501
+ it "works correctly with a has_one association in the middle" do
1502
+ candidate_profile1 = CandidateProfile.create(candidate: Candidate.create)
1503
+ candidate1 = candidate_profile1.candidate
1504
+ candidate_profile2 = CandidateProfile.create(candidate: Candidate.create)
1505
+ candidate2 = candidate_profile2.candidate
1506
+
1507
+ expect(candidate_profile1.conversations_count).to eq(0)
1508
+ expect(candidate_profile2.conversations_count).to eq(0)
1509
+
1510
+ conversation1 = Conversation.create(candidate: candidate1)
1511
+ expect(candidate_profile1.reload.conversations_count).to eq(1)
1512
+
1513
+ conversation2 = Conversation.create(candidate: candidate2)
1514
+ expect(candidate_profile2.reload.conversations_count).to eq(1)
1515
+
1516
+ conversation2.candidate = candidate1
1517
+ conversation2.save!
1518
+
1519
+ expect(candidate_profile1.reload.conversations_count).to eq(2)
1520
+ expect(candidate_profile2.reload.conversations_count).to eq(0)
1521
+
1522
+ candidate_profile1.update_column(:conversations_count, 99)
1523
+ candidate_profile2.update_column(:conversations_count, 99)
1524
+
1525
+ Conversation.counter_culture_fix_counts
1526
+
1527
+ expect(candidate_profile1.reload.conversations_count).to eq(2)
1528
+ expect(candidate_profile2.reload.conversations_count).to eq(0)
1529
+
1530
+ conversation2.destroy
1531
+ expect(candidate_profile1.reload.conversations_count).to eq(1)
1532
+ expect(candidate_profile2.reload.conversations_count).to eq(0)
1533
+
1534
+ conversation1.destroy
1535
+ expect(candidate_profile1.reload.conversations_count).to eq(0)
1536
+ expect(candidate_profile2.reload.conversations_count).to eq(0)
1537
+ end
1538
+
1498
1539
  describe "#previous_model" do
1499
1540
  let(:user){User.create :name => "John Smith", :manages_company_id => 1}
1500
1541
 
@@ -0,0 +1,3 @@
1
+ class Candidate < ActiveRecord::Base
2
+ has_one :candidate_profile, inverse_of: :candidate
3
+ end
@@ -0,0 +1,3 @@
1
+ class CandidateProfile < ActiveRecord::Base
2
+ belongs_to :candidate
3
+ end
@@ -0,0 +1,4 @@
1
+ class Conversation < ActiveRecord::Base
2
+ belongs_to :candidate
3
+ counter_culture [:candidate, :candidate_profile]
4
+ end
data/spec/schema.rb CHANGED
@@ -201,4 +201,16 @@ ActiveRecord::Schema.define(:version => 20120522160158) do
201
201
  t.integer "poly_images_count_dup", :default => 0, :null => false
202
202
  t.integer "special_poly_images_count", :default => 0, :null => false
203
203
  end
204
+
205
+ create_table "conversations", :force => true do |t|
206
+ t.integer "candidate_id"
207
+ end
208
+
209
+ create_table "candidates", :force => true do |t|
210
+ end
211
+
212
+ create_table "candidate_profiles", :force => true do |t|
213
+ t.integer "candidate_id"
214
+ t.integer "conversations_count", :default => 0, :null => false
215
+ end
204
216
  end
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.6.0
4
+ version: 1.6.1
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-04-24 00:00:00.000000000 Z
11
+ date: 2017-04-26 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: after_commit_action
@@ -210,11 +210,14 @@ files:
210
210
  - spec/counter_culture_spec.rb
211
211
  - spec/models/another_post.rb
212
212
  - spec/models/another_post_comment.rb
213
+ - spec/models/candidate.rb
214
+ - spec/models/candidate_profile.rb
213
215
  - spec/models/categ.rb
214
216
  - spec/models/category.rb
215
217
  - spec/models/company.rb
216
218
  - spec/models/conditional_dependent.rb
217
219
  - spec/models/conditional_main.rb
220
+ - spec/models/conversation.rb
218
221
  - spec/models/has_string_id.rb
219
222
  - spec/models/industry.rb
220
223
  - spec/models/person.rb