Do cache sweepers observe the controller and not the model?

I’m (finally) looking into caching, and it seems kind of strange to
me. If I cache a page, and then create a sweeper to expire that page,
the sweeper appears to “observe” controller actions rather than the
model.

For example, say I’ve got the following sweeper:

class StylesheetSweeper < ActionController::Caching::Sweeper
observe Stylesheet

def after_save(stylesheet)
expire_stylesheet_page stylesheet.id
end

def after_destroy(stylesheet)
expire_stylesheet_page stylesheet.id
end

private
def expire_stylesheet_page(stylesheet_id)
expire_page hash_for_stylesheet_path(stylesheet_id)
end
end

If I open the console and make a change to a Stylesheet object, the
cache doesn’t get expired. That seems wrong to me. Editing records
through the console would lead to a stale cache.

What am I missing?

Pat

i think we are missing some key documentation. i would like to call a
sweeper method (after_save) that is observing my model. in essence i
need to get around the model update method. i would like to know how
to see the observers of a model. too much to ask?

On 10/23/07, Gone S. [email protected] wrote:

Cache sweepers are invoked from the controller, not the model. It’d
be nice if my_model.update automatically invoked the sweeper, but
afaik that doesn’t currently happen. You set up the cache expiration
when my_controller#update gets called, etc.

Pat

Pat M. wrote:

On 10/23/07, Gone S. [email protected] wrote:

Cache sweepers are invoked from the controller, not the model. It’d
be nice if my_model.update automatically invoked the sweeper, but
afaik that doesn’t currently happen. You set up the cache expiration
when my_controller#update gets called, etc.

Pat

but they ARE invoked on a save from the model. why do you say invoked
from controller?

You must put your sweeper inside the controller that’d trigger the
sweeper.
The sweeper is triggered on change in models.
but when you step into any expire_* method in a debugger, you’d see
that a controller is needed!

http://trac.extendviget.com/tyrant/browser/branches/edge-conversion/vendor/rails/actionpack/lib/action_controller/caching/sweeping.rb?rev=160

      def method_missing(method, *arguments)
        return if @controller.nil?
        @controller.send(method, *arguments)
      end

Gone S. wrote:

Pat M. wrote:

On 10/23/07, Gone S. [email protected] wrote:

Cache sweepers are invoked from the controller, not the model. It’d
be nice if my_model.update automatically invoked the sweeper, but
afaik that doesn’t currently happen. You set up the cache expiration
when my_controller#update gets called, etc.

Pat

but they ARE invoked on a save from the model. why do you say invoked
from controller?

OK on your logic Yaxm. So now what do we do if the controller (for
reasons which I do not know) is nil ?? the model sweeper is trying to
expire the fragment as it was intended but now rails is preventing it !!
what a pain. help.

Yaxm Y. wrote:

You must put your sweeper inside the controller that’d trigger the
sweeper.
The sweeper is triggered on change in models.
but when you step into any expire_* method in a debugger, you’d see
that a controller is needed!

http://trac.extendviget.com/tyrant/browser/branches/edge-conversion/vendor/rails/actionpack/lib/action_controller/caching/sweeping.rb?rev=160

      def method_missing(method, *arguments)
        return if @controller.nil?
        @controller.send(method, *arguments)
      end

can anybody respond to this? @controller is nil so expire_fragment does
NOT get called even though the model was updated which is exactly how it
should be done. is there a work around? a way to set the controller? i
think this is a bug. any answers out there in the community? thanks.

      def method_missing(method, *arguments)
        return if @controller.nil?
        @controller.send(method, *arguments)
      end

I don’t get it. How is your model being “updated” if not through a
controller. The whole point is that models are updated through
controller actions. You then add sweepers to those actions which are
invoked when the model is altered through those actions. Why would the
controller “be nil”? There should always be a controller that is
responsible for the actions which modify the state of your models…

Nathan E. wrote:

I don’t get it. How is your model being “updated” if not through a
controller. The whole point is that models are updated through
controller actions. You then add sweepers to those actions which are
invoked when the model is altered through those actions. Why would the
controller “be nil”? There should always be a controller that is
responsible for the actions which modify the state of your models…

i didn’t say it was not going thru a controller. the thing is that the
model is being instantiated via classify.constantize. the model name is
not the same as the controller name but i am still doing a model.save
therefore this should clear the cache correctly but it fails in
caching.rb Sweeping module in the method_missing method because
@controller is nil. i did not write this code i am just trying to fix
it. the method that is missing is expire_fragment.

def method_missing(method, *arguments)
return if @controller.nil?
@controller.send!(method, *arguments)
end

the controller shouldn’t be nil if you are editing the model via a rails
action instigated by a controller. in your controller you should have

cache_sweeper :foo_sweeper

and in yr sweeper do you have

observe Foo

right? if so, then controller should not be nil. if not, try adding
those
things [obviously taking into account the actual names of the sweeper
and
model] and see if it solves yr problem. if not, please include the code
you
use in your reply so we can see what is happening exactly. :slight_smile:

RSL

On Fri, Mar 14, 2008 at 8:57 AM, Gone S.
[email protected]

Are you modifying your model via script/console or runner? How often
will
you be doing this? You could prolly instantiate a controller here or
something but if it’s a really rare instance, you might just want to do
something cheap and easy like sweep the whole cache [via FileUtils.rm_rf
or
something]. The problem with instantiating a controller is that it’s
gonna
need a CGI request to generate the urls when it is trying to expire_page
IIRC. And that may be more trouble than it’s worth.

RSL

On Thu, Mar 13, 2008 at 6:09 PM, Gone S.
[email protected]