# Expiring cache from a rake task

**URL:** <https://discuss.rubyonrails.org/t/expiring-cache-from-a-rake-task/39267>\
**Category:** rubyonrails-talk\
**Created:** [February 11, 2009, 10:14am UTC](https://discuss.rubyonrails.org/t/expiring-cache-from-a-rake-task/39267 "2009-02-11T10:14:15Z")\
**Posts on this page:** 4\
**Page:** 1

<div class="post-metadata">

**Author:** ![Levy\_Carneiro\_Jr](https://avatars.discourse-cdn.com/v4/letter/l/7ab992/32.png) [@Levy\_Carneiro\_Jr](https://discuss.rubyonrails.org/u/Levy_Carneiro_Jr)\
**Post date:** [February 11, 2009, 10:14am UTC](https://discuss.rubyonrails.org/t/expiring-cache-from-a-rake-task/39267/1 "2009-02-11T10:14:15Z")

</div>

Hello,

I have a question on cache expiration only working from the web, and not from the console or from a rake task.

I have 2 models, Post e Comments. I have this page /archives where I list all old posts.

I created a controller ‘archives’, where I have a page cache (caches\_page :index). I need to expire this page cache, every time a Post or Comment is created/updated/destroyed.

Using sweepers, this works 100%. ([http://www.railsenvy.com/2007/2/28/rails-caching-tutorial#sweepers](http://www.railsenvy.com/2007/2/28/rails-caching-tutorial#sweepers))

The problem is that, now, I implemented spam moderation by Akismet. So when a new comment is created in the database, it gets a ‘pending’ status. And there’s a rake task that runs every x minutes, in order to check all ‘pending’ comments against the Akismet database, and only then comments earn an ‘approved’ or ‘spam’ status. And it’s only then that I should expire the /archives page.

So I need to expire a cached page, from something that happens outsite a controller. And it seems the only situation a sweeper works is when the event is triggered by the web.

If I open the console, add a new comment to a post, nothing happens (ok!). And now I run the Akismet check, and assuming it gives the comment an ‘approved’ status, the cache is not expired, when it should be.

I tried to use Observers, from the Rails docs ([http://www.railsbrain.com/api/rails-2.2.2/doc/index.html?a=M001871&name=observe](http://www.railsbrain.com/api/rails-2.2.2/doc/index.html?a=M001871&name=observe)).

In environment.rb I added the line: config.active\_record.observers = :archives\_observer I created the file app/models/archives\_observer.rb with:

class ArchivesObserver \< ActiveRecord::Observer observe :post, :comment

def after\_save(record) expire\_page(:controller =\> ‘archives’, :action =\> ‘index’)

end end

But I get an error: NoMethodError: undefined method `expire\_page’ for #ArchivesObserver:0x247eddc

I tried this also:

class ArchivesObserver \< ActionController::Caching::Sweeper

(…)

In this case, there’s no error, and it does nothing at all. The public/archives.html just stays there.

I’m trying my best to avoid hacking it, using a simple File.delete 🙂

Like the code below:

```ruby
# File rails/actionpack/lib/action_controller/caching/pages.rb, line 65
65: def expire_page(path)

66: return unless perform_caching
67:
68: benchmark "Expired page: #{page_cache_file(path)}" do

69: File.delete(page_cache_path(path)) if File.exist?(page_cache_path(path))

70: end
71: end

```

Is there a way to expire pages without having to hack it?

Thanks a lot, Levy

---

<div class="post-metadata">

**Author:** ![Wincent\_Colaiuta](https://avatars.discourse-cdn.com/v4/letter/w/e79b87/32.png) [@Wincent\_Colaiuta](https://discuss.rubyonrails.org/u/Wincent_Colaiuta)\
**Post date:** [February 22, 2009, 5:09pm UTC](https://discuss.rubyonrails.org/t/expiring-cache-from-a-rake-task/39267/2 "2009-02-22T17:09:25Z")

</div>

I ran into a similar issue a few days ago. If I remember correctly, if you look at what Rails is doing under the covers, you'll see that ActionController::Caching::Sweeper subclasses will only work when called from inside a controller. Basically the "expire\_page" message ends up getting intercepted by "method\_missing", which tries to forward it on to a controller stored in the @controller instance variable. So if you invoke your Sweeper subclass from somewhere else (like a Rake task), that @controller variable will be nil and nothing will happen.

My workaround was just to fall back to File.delete and friends. Ugly, but it works.

Cheers, Wincent

---

<div class="post-metadata">

**Author:** ![Levy\_Carneiro\_Jr](https://avatars.discourse-cdn.com/v4/letter/l/7ab992/32.png) [@Levy\_Carneiro\_Jr](https://discuss.rubyonrails.org/u/Levy_Carneiro_Jr)\
**Post date:** [March 1, 2009, 3:31am UTC](https://discuss.rubyonrails.org/t/expiring-cache-from-a-rake-task/39267/3 "2009-03-01T03:31:03Z")

</div>

Thanks, Vincent.

I just wanted to know if there was something better. I guess I’ll resort to the File.delete and friends as you mentioned 🙂

Regards, Levy

---

<div class="post-metadata">

**Author:** ![Philip\_Hallstrom](https://avatars.discourse-cdn.com/v4/letter/p/bbe5ce/32.png) [@Philip\_Hallstrom](https://discuss.rubyonrails.org/u/Philip_Hallstrom)\
**Post date:** [March 1, 2009, 4:32am UTC](https://discuss.rubyonrails.org/t/expiring-cache-from-a-rake-task/39267/4 "2009-03-01T04:32:00Z")

</div>

Coming in late, but this might be helpful... I've used this from ./ script/runner... not quite rake, but...

... require 'lib/console\_app' ... ActionController::Base.expire\_page(app.user\_profile\_path(:id =\>  
user.username)) ...

(where 'user\_profile' is a named route)
