diff --git a/lib/counter_culture/counter.rb b/lib/counter_culture/counter.rb index 19b753d..f3765d4 100644 --- a/lib/counter_culture/counter.rb +++ b/lib/counter_culture/counter.rb @@ -182,7 +182,11 @@ def foreign_key_value(obj, relation, was = false) value = value.send(relation.shift) end - return value.try(relation_primary_key(original_relation, source: obj, was: was).try(:to_sym)) + if value.is_a?(ActiveRecord::Associations::CollectionProxy) + value.map { |v| v.try(relation_primary_key(original_relation, source: obj, was: was).try(:to_sym)) } + else + value.try(relation_primary_key(original_relation, source: obj, was: was).try(:to_sym)) + end end # gets the reflect object on the given relation diff --git a/spec/counter_culture_spec.rb b/spec/counter_culture_spec.rb index 31a67eb..e8d35aa 100644 --- a/spec/counter_culture_spec.rb +++ b/spec/counter_culture_spec.rb @@ -34,6 +34,11 @@ require 'models/group' require 'models/sub_group' require 'models/group_item' +require 'models/many_to_many/article' +require 'models/many_to_many/author' +require 'models/many_to_many/reader' +require 'models/many_to_many/authors_article' +require 'models/many_to_many/readers_article' if ENV['DB'] == 'postgresql' require 'models/purchase_order' @@ -2766,4 +2771,42 @@ def mess_up_counts po.reload expect(po.total_amount).to eq(0.0) end + + describe "many to many association counter caches" do + let!(:reader) { Reader.create! } + let!(:author) { Author.create! } + let(:article) { Article.new(readers: [reader], authors: [author]) } + + context "when the relation is a single-level one" do + context "when creating a new record" do + it "updates the counter cache" do + expect { article.save }.to change { author.reload.articles_count }.by(1) + end + end + + context "when deleting an existing record" do + before { article.save } + + it "updates the counter cache" do + expect { article.destroy }.to change { author.reload.articles_count }.by(-1) + end + end + end + + context "when the relation is a multi-level one" do + context "when creating a new record" do + it "updates the counter cache" do + expect { article.save }.to change { author.reload.readers_count }.by(1) + end + end + + context "when deleting an existing record" do + before { article.save } + + it "updates the counter cache" do + expect { article.destroy }.to change { author.reload.readers_count }.by(-1) + end + end + end + end end diff --git a/spec/models/many_to_many/article.rb b/spec/models/many_to_many/article.rb new file mode 100644 index 0000000..cb1c9cb --- /dev/null +++ b/spec/models/many_to_many/article.rb @@ -0,0 +1,7 @@ +class Article < ActiveRecord::Base + has_many :readers_articles, dependent: :destroy + has_many :authors_articles, dependent: :destroy + + has_many :readers, through: :readers_articles, dependent: :destroy + has_many :authors, through: :authors_articles, dependent: :destroy +end diff --git a/spec/models/many_to_many/author.rb b/spec/models/many_to_many/author.rb new file mode 100644 index 0000000..994cc34 --- /dev/null +++ b/spec/models/many_to_many/author.rb @@ -0,0 +1,4 @@ +class Author < ActiveRecord::Base + has_many :authors_articles, dependent: :destroy + has_many :articles, through: :authors_articles, dependent: :destroy +end diff --git a/spec/models/many_to_many/authors_article.rb b/spec/models/many_to_many/authors_article.rb new file mode 100644 index 0000000..01ca7ae --- /dev/null +++ b/spec/models/many_to_many/authors_article.rb @@ -0,0 +1,6 @@ +class AuthorsArticle < ActiveRecord::Base + belongs_to :author + belongs_to :article + + counter_culture :author, column_name: :articles_count +end diff --git a/spec/models/many_to_many/reader.rb b/spec/models/many_to_many/reader.rb new file mode 100644 index 0000000..490d611 --- /dev/null +++ b/spec/models/many_to_many/reader.rb @@ -0,0 +1,4 @@ +class Reader < ActiveRecord::Base + has_many :readers_articles, dependent: :destroy + has_many :articles, through: :readers_articles, dependent: :destroy +end diff --git a/spec/models/many_to_many/readers_article.rb b/spec/models/many_to_many/readers_article.rb new file mode 100644 index 0000000..495997e --- /dev/null +++ b/spec/models/many_to_many/readers_article.rb @@ -0,0 +1,6 @@ +class ReadersArticle < ActiveRecord::Base + belongs_to :reader + belongs_to :article + + counter_culture [:article, :authors], column_name: :readers_count +end diff --git a/spec/schema.rb b/spec/schema.rb index 59d3139..53c310e 100644 --- a/spec/schema.rb +++ b/spec/schema.rb @@ -281,6 +281,31 @@ t.string "sub_group_uuid", :null => false end + create_table "readers", :force => true do |t| + t.string "name" + end + + create_table "articles", :force => true do |t| + t.string "title" + end + + create_table "authors", :force => true do |t| + t.string "name" + + t.integer "articles_count", default: 0, null: false + t.integer "readers_count", default: 0, null: false + end + + create_table "readers_articles", :force => true do |t| + t.integer "reader_id", null: false + t.integer "article_id", null: false + end + + create_table "authors_articles", :force => true do |t| + t.integer "author_id", null: false + t.integer "article_id", null: false + end + if ENV['DB'] == 'postgresql' && Gem::Version.new(Rails.version) >= Gem::Version.new('5.0') create_table :purchase_orders, :force => true do |t| t.money "total_amount", scale: 2, default: "0.0", null: false