Skip to content

Instantly share code, notes, and snippets.

@O-I
Last active August 29, 2015 14:27
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save O-I/3a9b57159089239e4003 to your computer and use it in GitHub Desktop.
Save O-I/3a9b57159089239e4003 to your computer and use it in GitHub Desktop.
Counter caching on a has_many :through association in Rails 3.2

I'm trying to figure out if using counter_cache on a has_many :through association is still considered kosher in Rails 3.2. I've read several posts that distill the steps for setting this up (e.g., see 1 and 2). On the other hand, it seems like counter_cache on has_many :through was an unintended side effect that was never a supported feature of Rails and was ultimately removed.

Here's my specific scenario:

# Event model
has_many :event_attendees, dependent: :destroy
has_many :attendees, through: :event_attendees, source: :user

# EventAttendee model
belongs_to :user
belongs_to :event

Assuming using counter_cache is an acceptable solution, I tried this:

# Add an attendees_count column to events
class AddAttendeesCountToEvents < ActiveRecord::Migration
  def change
    add_column :events, :attendees_count, :integer, default: 0
  end
end

# Update the EventAttendee model
belongs_to :user
belongs_to :event, counter_cache: :attendees_count

# Update the event_attendees cache with the correct counts for each event
class CacheEventAttendeesCount < ActiveRecord::Migration
  def up
    Event.find_each do |event|
      attendees_count = EventAttendee.where(event_id: event.id).size
      event.update_attributes(attendees_count: attendees_count)
    end
  end

  def down
  end
end

The CacheEventAttendeesCount migration seems to have no effect. I am trying to figure out whether this is because (1) this particular migration is incorrect, (2) my counter_cache migration is incorrect (can Rails infer what attendees_count is supposed to count?), or (3) I'm just entirely going about this the wrong way.

If using counter_cache isn't the way to go for this, what is the accepted way of caching a count on a has_many :through association? If it is acceptable, can you help me understand what I am doing wrong?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment