class Attachment < ActiveRecord::Base
belongs_to :user, foreign_key: :creator_id
belongs_to :deal_task, foreign_key: :relation_id
end
class DealTask < ActiveRecord::Base
has_many :attachments, foreign_key: :relation_id
end
I have parent table called DealTask and child table called Attachment
I want a list of DealTask records with associated total number of attachments
I found the best solution for Parent child relationship count
counter_cache: true
because all above queries take too much time to load from database
so you all must prefer to use this
1-> Add one column in Parent table called DealTask
rails g migration AddAttachmentsCountToDealTask attachments_count:integer
2-> Open Migration add Edit it
class AddAttachmentCountToDealTask < ActiveRecord::Migration[5.0]
def up
add_column :deal_tasks, :attachments_count, :integer, default: 0
DealTask.reset_column_information
DealTask.find_each do |deal_task|
DealTask.reset_counters deal_task.id, :attachments
end
end
def down
remove_column :deal_tasks, attachments_count
end
end
So when you rollback the migration it will not raise an error or exception
you can also use any loop instead of using
find_each, DealTask.all.each do...end
but yes, While resetting counter Must use class name like
DealTask.reset_counters
3-> Set Counter cache
class Attachment < ActiveRecord::Base
belongs_to :deal_task, foreign_key: :relation_id, counter_cache: true
end
class DealTask < ActiveRecord::Base
has_many :attachments, foreign_key: :relation_id
end
suppose name of your model is sub_tasks than your counter_cache column must be
sub_tasks_count
if you want your own column name than you have to specify that column name in counter_cache
suppose column name is total_subtasks than
belongs_to :deal_task, foreign_key: :relation_id, counter_cache: :total_subtasks
and make changes accordingly for updating counter_cache
now when you Add any Attachment, attachments_count column increase by 1 and this is done automatically by **counter_cache
one Problem is there ** when you delete any child counter_cache is unable to decrease **
so for that solution make a callback
class Attachment < ActiveRecord::Base
belongs_to :deal_task, foreign_key: :relation_id, counter_cache: true
before_destroy :reset_counter
private
def reset_counter
DealTask.reset_counters(self.relation.id, :attachments)
end
end
so when you delete any attachments it will reset countet_cache for its Parent by relation_id which is parent_id or Foreign_key for attachments
for more info see video on Railscast counter cache 23