Reputation: 1772
I am trying to "counter cache" the number of posts in each tag. The after save callback is working but the after destroy is not. Looks like destroy sql is not correct.
class Post < ActiveRecord::Base
has_many :post_tags, :dependent => :destroy
has_many :tags, :through => :post_tags
end
class Tag < ActiveRecord::Base
has_many :post_tags, :dependent => :destroy
has_many :posts, :through => :post_tags
end
class PostTag < ActiveRecord::Base
self.table_name = :posts_tags
belongs_to :post
belongs_to :tag
after_save :update_tag_posts_count
after_destroy :update_tag_posts_count
def update_tag_posts_count
tag.posts_count = tag.posts.count
tag.save
end
end
The test fails
# @tag.posts_count == 10
Failure/Error: @tag.posts.first.destroy
ActiveRecord::StatementInvalid:
Mysql2::Error: Unknown column 'posts_tags.' in 'where clause': DELETE FROM `posts_tags` WHERE `posts_tags`.`` = NULL
The correct sql should be
DELETE FROM `posts_tags` WHERE `posts_tags`.`post_id` = {the post id}
Upvotes: 5
Views: 1152
Reputation: 734
I had the exact same issue, the fix for me was to add a primary key column to the join table (PostTag in your case).
It seems that rails needs a primary key for the :dependent => :destroy
option to work.
Upvotes: 3
Reputation: 6981
I'd suggest separate increment/decrement functions and not using count + save. This should function properly, perform well, not trigger side-effects on Tag, and not mess up your count in race conditions.
class PostTag < ActiveRecord::Base
belongs_to :post
belongs_to :tag
after_create :increment_tag_posts_counter
after_destroy :decrement_tag_posts_counter
private
def increment_tag_posts_counter
Tag.increment_counter :posts_count, post_id
end
def decrement_tag_posts_counter
Tag.decrement_counter :posts_count, post_id
end
end
Upvotes: 0
Reputation: 185
May be because in models you used
#post.rb
has_many :post_tags, :dependent => :destroy
#tag.rb
has_many :post_tags, :dependent => :destroy
instead of
#post.rb
has_many :posts_tags, :dependent => :destroy
#tag.rb
has_many :posts_tags, :dependent => :destroy
?
Upvotes: 0