# Strange behavior of expire\_fragment

**URL:** <https://www.ruby-forum.com/t/strange-behavior-of-expire-fragment/196846>\
**Category:** Rails\
**Created:** [November 24, 2008, 6:10am UTC](https://www.ruby-forum.com/t/strange-behavior-of-expire-fragment/196846 "2008-11-24T06:10:56Z")\
**Posts on this page:** 6\
**Page:** 1

<div class="post-metadata">

**Author:** ![indigoi](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/i/b3f665/32.png) [@indigoi](https://www.ruby-forum.com/u/indigoi)\
**Post date:** [November 24, 2008, 6:10am UTC](https://www.ruby-forum.com/t/strange-behavior-of-expire-fragment/196846/1 "2008-11-24T06:10:56Z")

</div>

I’m following railscasts tutorial on fragment caching, everything works  
great except for the sweepers. When i put expire\_fragment(%r{.\*})  
directly in my controller, i can expire my fragments with wonderful  
ease. Yet when i write a nice little sweeper like this code block,  
nothing gets expired (the puts have been added in for troubleshooting):

class PhraseSweeper \< ActionController::Caching::Sweeper  
observe Phrase

def after\_update(phrase)  
expire\_cache(phrase)  
end

def expire\_cache(phrase)  
puts "=====This Is Activated Via expire\_cache(phrase) "  
puts expire\_fragment(%r{._}).class  
expire\_fragment(%r{._})  
end  
end

I put this put it in apps/sweepers, and initialize the folder under  
environment.rb. When i update my phrase model I get this in my console:

=====This Is Activated Via expire\_cache(phrase)  
NilClass  
=====This Is Activated Via expire\_cache(phrase)  
NilClass

Yet when i have the expire\_fragment called via my controller i get this  
in the console:

======This is called via the controller======  
Hash

So, my sweeper folder is getting initialized, and the code is running on  
update, but for some reason the puts are called twice, and the  
expire\_fragment doesn’t work at all. Rails 2.1.0 Ruby 1.8.6. Any  
suggestions??

---

<div class="post-metadata">

**Author:** ![indigoi](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/i/b3f665/32.png) [@indigoi](https://www.ruby-forum.com/u/indigoi)\
**Post date:** [November 24, 2008, 6:46pm UTC](https://www.ruby-forum.com/t/strange-behavior-of-expire-fragment/196846/2 "2008-11-24T18:46:31Z")

</div>

Have you determined what

%r{.\*}

evaluates to in the context of your Sweeper?

---

<div class="post-metadata">

**Author:** ![indigoi](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/i/b3f665/32.png) [@indigoi](https://www.ruby-forum.com/u/indigoi)\
**Post date:** [November 24, 2008, 8:23pm UTC](https://www.ruby-forum.com/t/strange-behavior-of-expire-fragment/196846/3 "2008-11-24T20:23:26Z")

</div>

Ar Chron wrote:

> Have you determined what
> 
> %r{.\*}
> 
> evaluates to in the context of your Sweeper?

%r{.\*} will delete absoloutly everything in my cache, i think i found my  
error after reading this forum thread  
[http://www.ruby-forum.com/topic/145163#643061](http://www.ruby-forum.com/topic/145163#643061) .

In my controller i had:  
phrase\_sweeper :phrase\_sweeper, :only =\> [:create, :update, :destroy]

when i was actually using an action called :rank\_up, for some reason i  
just assumed if i was updating a model, the :update action would cover  
it, although i wasn’t using :update in my controller. I’ve yet to try  
the changes, but i’ll let you know the outcome. The confusing part was  
that the sweeper gets called no mater what, but the expire\_fragment only  
works on the specified actions.

---

<div class="post-metadata">

**Author:** ![indigoi](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/i/b3f665/32.png) [@indigoi](https://www.ruby-forum.com/u/indigoi)\
**Post date:** [November 24, 2008, 8:59pm UTC](https://www.ruby-forum.com/t/strange-behavior-of-expire-fragment/196846/4 "2008-11-24T20:59:57Z")

</div>

Richard S. wrote:

> The confusing part was  
> that the sweeper gets called no mater what, but the expire\_fragment only  
> works on the specified actions.

I actually gave up on the sweepers in my app, as they were far too  
general, and expired more than was necessary in some cases, and given  
the filters and sorting that can be done, it’s all fragment caching.

Now the models decide which of their own fragments to expire (via  
Rails.cache.delete) depending on what was changed.

---

<div class="post-metadata">

**Author:** ![indigoi](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/i/b3f665/32.png) [@indigoi](https://www.ruby-forum.com/u/indigoi)\
**Post date:** [November 24, 2008, 9:14pm UTC](https://www.ruby-forum.com/t/strange-behavior-of-expire-fragment/196846/5 "2008-11-24T21:14:13Z")

</div>

> Now the models decide which of their own fragments to expire (via  
> Rails.cache.delete) depending on what was changed.

Sounds interesting do you have a code snippet or tutorial you can point  
me to, before i get too entrenched in this sweeper mess??

---

<div class="post-metadata">

**Author:** ![indigoi](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/i/b3f665/32.png) [@indigoi](https://www.ruby-forum.com/u/indigoi)\
**Post date:** [November 24, 2008, 11:48pm UTC](https://www.ruby-forum.com/t/strange-behavior-of-expire-fragment/196846/6 "2008-11-24T23:48:36Z")

</div>

Basically, all my controllers inherit from GenericController, all my  
models from GenericModel, so I can single source stuff like these  
behaviors, but override if necessary…

GenericController:

def create  
model = params[:controller].singularize.downcase  
@object =  
params[:controller].singularize.camelcase.constantize.new(params[model])  
if @object.save  
# expire caches invalidated by the creation of this object  
@object.expire\_caches ‘create’  
end  
end

def update  
model = params[:controller].singularize.downcase  
@object =  
params[:controller].singularize.camelcase.constantize.find(params[:id])  
orig\_name = @object.name  
if @object.update\_attributes(params[model])  
expire\_type = (@object.name == orig\_name ? ‘update’ : ‘rename’)  
# expire caches invalidated by just an update, or an update  
# including a name change  
@object.expire\_caches expire\_type  
end  
end

Generic Model:

# models have fragments in basically

# modelname.id.row,

# modelname.id.show,

# modelname.id.related, and a bunch of other ‘sub-fragments’

# that make up the ‘related’ items navigation sidebar

def expire\_caches(method)  
model = self.class.table\_name.singularize  
case method  
when ‘update’  
# just expire the ‘show’ fragment for this model  
expire\_base\_fragment model, self.id  
when ‘destroy’  
# destroy all the fragments for this model, and all other  
# fragments that include this model - this is driven by  
# an attribute of each model, which tells what the related  
# models are  
destroy\_caches model, self.id  
when ‘rename’  
# just like destroy  
destroy\_caches model, self.id  
when ‘create’  
# this case looks at models related to the current  
# one to see if those caches should be invalidated. i.e.,  
# creating this model as a child of another invalidates  
# that models “children” cache  
… ugly code omitted…  
else  
# there are other actions that can cause different fragments  
# to be expired - relating 2 models will cause 4 fragments to  
# be expired:  
# this model’s list of that related type,  
# that model’s list of this related type,  
# and both model’s aggregate ‘related’ fragment  
… ugly code omitted…  
end  
end

The various “expire” or “destroy” methods are all variants of:

def expire\_base\_fragment(model, id)  
Rails.cache.delete(‘views/’+model+’/’+id.to\_s+’/show’)  
end
