3

I have a Forum model which has many discussions. Each discussion has many posts. Discussion is more or less just a collection of post objects.

Now I'd like to have a counter_cache available in Forum for the posts contained in that forums discussions.

So really, it seems like I should be using a :through association instead of two separate associations to accomplish this.

However I can't find any reference that suggest mixing a has_many :through and has_one :through association, just for one-to-one and many-to-many, not for one-to-many.

class Forum < ActiveRecord::Base
  has_many :discussions
  has_many :posts, :through => :discussions
end

class Post < ActiveRecord::Base
  belongs_to :discussion
  has_one :forum, :through => discussion
end

class Discussion < ActiveRecord::Base
  has_many :posts
  belongs_to :forum
end

Is something like the above advisable, or should I just handle the counter cache manually?

DVG
  • 17,392
  • 7
  • 61
  • 88

2 Answers2

2

Something like this should work.

class Forum < ActiveRecord::Base
  has_many :discussions
  has_many :posts, :through => :discussions
end

class Post < ActiveRecord::Base
  belongs_to :discussion, counter_cache: true
  has_one :forum, :through => discussion

  after_create :increment_forum_counter_cache

  private

  def increment_forum_counter_cache
     Forum.increment_counter( 'discussions_count', self.discussion.forum.id )
  end
end

class Discussion < ActiveRecord::Base
  has_many :posts
  belongs_to :forum

end

I seem to remember having trouble setting up counter_cache through a has_one relationship previously. The method above should work.

Andy Harvey
  • 12,333
  • 17
  • 93
  • 185
  • Why didn't you write `forum.id` instead of `self.discussion.forum.id`? Post `has_one` forum and `self` doesn't seem to be needed. – jdoe Jun 09 '12 at 18:08
-1

So the normal counter cache seems to be working just fine, as does mixing the relationship types

class Post < ActiveRecord::Base
  belongs_to :user
  belongs_to :discussion
  has_one :forum, :through => :discussion,
            :counter_cache => :posts_counter
end
class Forum < ActiveRecord::Base
  has_many :discussions
  has_many :posts, :through => :discussions
end

class Discussion < ActiveRecord::Base
  has_many :posts
  belongs_to :forum
  belongs_to :user
end
DVG
  • 17,392
  • 7
  • 61
  • 88
  • Isn't that posts_counter is within Post table and counting quantity of forums (which should be 1)? – Ivan Wang Mar 02 '14 at 17:56
  • No. The counter cache lives in the associated table. See here: http://guides.rubyonrails.org/association_basics.html – DVG Mar 04 '14 at 12:26
  • This answer is not valid for Rails 4 and I highly doubt it was ever valid. – Mike Szyndel Aug 12 '14 at 13:45
  • You are correct that it is not valid for Rails 4. However, [counter cache was a valid option on a singular association in Rails 3, which is when this question was asked](https://github.com/rails/rails/blob/3-2-stable/activerecord/lib/active_record/associations/builder/singular_association.rb#L3) – DVG Aug 12 '14 at 17:55