unorganized.net directly from the brain of Eike Bernhardt

28Oct/110

Mongoid Cache Sweeper

I just needed to add a Cache Sweeper in a Rails 3.1 app for a Mongoid model.

Using a ActionController::Caching::Sweeper didn’t run for updates on the models (even though it should work for non-Mongoid-models), so I ended up using a Mongoid::Observer to invalidate the cache when a model was updated.

To seperate the observers from the models, I created a app/observers directory and used the following code to automatically load the observers:

# mongoid observers/sweepers
config.mongoid.observers = Dir["#{config.root}/app/observers/*.rb"].collect do |full_name|
  File.basename(full_name,'.rb').to_sym
end

This is the app/observers/city_observer.rb file:

class CityObserver < Mongoid::Observer
  def after_create(city)
    expire_cache_for(city)
  end

  def after_update(city)
    expire_cache_for(city)
  end

  def after_destroy(city)
    expire_cache_for(city)
  end

  private

  def expire_cache_for(city)
    # expire fragments/pages for city
    @c ||= ActionController::Base.new

    @c.expire_fragment("city_#{city.id.to_s}")
    if city.state.present?
      @c.expire_fragment("state_#{city.state.id.to_s}")
    end
    if city.country.present?
      @c.expire_fragment("country_#{city.country.id.to_s}")
    end

    # and expire the continent page cache
    @c.expire_page("/continents/#{city.country.continent.slug}")
  end
end

Since the expire_fragment/expire_page functions are not defined in the observer, I create a ActionController::Base object to call them on that.

With this, a model update expires cached pages