Rails 4: counter_cache in has_many :through association with dependent: :destroy
Well, dependent: :destroy
will destroy the associated records, but it won't update the counter_cache
, so you may have wrong count in counter_cache
. Instead you can implement a callback that will destroy the associated records, and update your counter_cache
.
class Calendar < ActiveRecord::Base
has_many :administrations
has_many :users, through: :administrations
before_destroy :delete_dependents
private
def delete_dependents
user_ids = self.user_ids
User.delete_all(:calendar_id => self.id)
user_ids.each do |u_id|
Calendar.reset_counters u_id, :users
end
end
end
And similarly, implement this for User
model too
Rails counter_cache on has_many through
Short answer is no. You cannot use post.update(authors: [])
and trigger callbacks.
counter_culture
gem that you provided builds its functionality on top of rails callbacks execution, I pointed in that url code which does it.
post.update(authors: [])
this code doesn't trigger ActiveRecord callbacks.
Neither this one post.authors.find(1).delete
.
So in order to trigger your callbacks and update counter_cache
column, you will need to write some function that will resolve authors and trigger destroy
Consider this
some_conditions = { id: [1,2,3] }
post.authors.where(some_conditions).each(&:destroy)
For further reading you refer to this well-described answer about ActiveRecord callbacks
ActiveRecord has_many :through duplicating counter caches on mass assignment
So far my research has told me this is probably a bug. Here are some github issues already filed for this problem:
https://github.com/rails/rails/issues/3903
https://github.com/rails/rails/issues/3085
Apparently there is an undocumented automatic counter cache caused by has_many :through relations. So if Teacher.has_many :students, :through => :classrooms
then teacher.students << student
collection assignments already look for and increment teacher.students_count
if that column exists.
If you add Classroom.belongs_to :teacher, :counter_cache => :students_count
then an additional callback is triggered when the Classroom model is created, and the column gets incremented twice.
Effective work around: rename the counter cache columns to something else. Student#teacherz_count
and Teacher#studentz_count
were effective at allowing my test case to pass.
https://github.com/carlzulauf/test_app/commit/707a33f948d5d55a8aa942e825841fdd8a7e7705
I haven't yet been able to find where the problem lies in the ActiveRecord code base, so I won't accept my own answer for a while in case someone knows why has_many :through
works this way and where the offending code lives.
Update
I believe I found the offending line of code. Commenting out this line resolves the problem:
https://github.com/rails/rails/blob/889e8bee82ea4f75adb6de5badad512d2c615b7f/activerecord/lib/active_record/associations/has_many_through_association.rb#L53
I can't seem to get edge rails up and running so I can't submit a pull for this bug yet. If someone else is able, please do.
Finding the offending line allowed me to craft a more effective monkey patch in my test app that resolves the issue without renaming any columns.
https://github.com/carlzulauf/test_app/commit/3c421b035bd032b91ff60e3d74b957651c37c7fa
Counter cache for a model with a many-to-many association
It seems like there is no real easy way to do this. If you look at this previous post. It seems like this comes up fairly often and sadly rails does not have an easy way to complete this task. What you will need to do is write some code like this.
Although, I would also suggest looking into has_and_belongs_to_many relationships as that might be what you have here.
A(Tag) has many C(posts) through B(tagging)
class C < ActiveRecord::Base
belongs_to :B
after_create :increment_A_counter_cache
after_destroy :decrement_A_counter_cache
private
def increment_A_counter_cache
A.increment_counter( 'c_count', self.B.A.id )
end
def decrement_A_counter_cache
A.decrement_counter( 'c_count', self.B.A.id )
end
end
counter_cache not decrementing for has_many associations in ActiveReord
Same issues here but on Rails 2.3.
Worth noticing that also adding a touch, like:
belongs_to :user, :counter_cache => :saved_shows_count, :touch => true
Won't update counter cache nor the related updated_at field on association.delete(object).
To workaround the issue usually we manipulate the join model, but that also have some drawbacks.
Patch is here: https://rails.lighthouseapp.com/projects/8994-ruby-on-rails/tickets/2824-patch-has_many-through-doesnt-update-counter_cache-on-join-model-correctly#ticket-2824-18
Related Topics
Installing Jekyll on Ubuntu 14.04
How to Make Part of a Regular Expression Optional in Ruby
Does Ruby Provide a Way to Do File.Read() with Specified Encoding
Call Controller from Rake Task
How to Use Rspec's Should_Raise with Any Kind of Exception
Ruby on Rails Plural (Controller) and Singular (Model) Convention - Explanation
Error While Installing Nokogiri (1.6.7) on El Capitan
Best Practice for Rails App to Run a Long Task in the Background
Ruby on Rails: Can You Put Ruby Code in a Yaml Config File
Including One Erb File into Another
Rails on Windows - Install Issue
Activerecord::Adapternotspecified Database Configuration Does Not Specify Adapter
Rails - Cannot Run App: Unable to Load the Eventmachine C Extension;
How to Run a Single Test in Minitest
Error Installing Nokogiri on Bundle Install But Already Installed