Is it possible to expire cache items (page, action, or fragment) from
within a model? I know that sweepers let you trigger cache expiration
on model changes, but they have to be activated in the controller.
I want to cache some things that can be potentially modified from many
different controllers. It seems like it would be too easy to forget to
activate the sweeper from some controller and then end up with a stale
cache.
Expiring things by using just a plain after_save hook in the model seems
like it would be much safer to me, but I haven't found a way to get to
the expire_ calls from within a model.
Is this possible? Or am I overlooking a reason why things shouldn't be
done this way?
ActionController::Base.fragment_cache_store.delete(name, nil)
Is there anything wrong with this approach?
Yes, many things. You're breaking MVC priciples that will lead to ugly
ugly results down the road.
USE SWEEPERS
if you think your going to forget them some were stick them all in
application_controller in a before filter on everything until you
familiarize your self with the code base.
ActionController::Base.fragment_cache_store.delete(name, nil)
Is there anything wrong with this approach?
Yes, many things. You're breaking MVC priciples that will lead to ugly
ugly results down the road.
USE SWEEPERS
if you think your going to forget them some were stick them all in
application_controller in a before filter on everything until you
familiarize your self with the code base.
I understand that it is breaking MVC a bit, but I'm still having trouble
seeing why it's so bad. It's probably just my inexperience in this
particular area, but could you give me a little bit more concrete
example of why putting it in the model leads to ugly results?
Thanks for the tip on using the sweeper on the application controller.
I hadn't thought of that. But I guess I don't really see how it's that
different from putting it right in the model. I mean, it will run every
time, just as if it were in the model (or a regular observer on the
model).
It doesn't seem in keeping with DRY to have to remember to put a call to
the sweeper on every new controller that could possibly affect the model
that causes my fragments to become stale.
Sorry for all these questions, but I really do want to understand the
reasoning behind this approach.
Its the controllers Job to handle business logic. The model should only
be responsible for data going to and from the database.
No this doesn't violate DRY principles. You're not duplicating the code
for clearing the cache and preferably not duplicating the code that
initializes the sweeper. You're only duplicating a before filter because
you're giving it different actions to act before.
I am curious however why your model is getting modified by so many
controllers?
Its the controllers Job to handle business logic. The model should only
be responsible for data going to and from the database.
No this doesn't violate DRY principles. You're not duplicating the code
for clearing the cache and preferably not duplicating the code that
initializes the sweeper. You're only duplicating a before filter because
you're giving it different actions to act before.
I am curious however why your model is getting modified by so many
controllers?
Well, right now it's only being modified by two controllers. One for
normal editing of items and one for a bulk import of items. But in the
future, we want to add one for bulk editing existing items, or we might
want to expand the functionality of another controller to modify the
items as a side effect of another operation.
But if the point is that every time the model changes, I know that this
particular cache needs to be expired, why not define that behavior at a
higher level? Even putting it at the application controller level
doesn't cover the case of modifying something at the console or
modifying objects during a migration.
Anyway, I think attaching the sweeper to the application controller will
do the trick for me for now.