Forum: Ruby on Rails Expiring cache from a rake task

Announcement (2017-05-07): www.ruby-forum.com is now read-only since I unfortunately do not have the time to support and maintain the forum any more. Please see rubyonrails.org/community and ruby-lang.org/en/community for other Rails- und Ruby-related community platforms.
Levy Carneiro Jr. (Guest)
on 2009-02-11 12:14
(Received via mailing list)
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-t...)

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/inde...
).

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:

    # 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
Wincent C. (Guest)
on 2009-02-22 19:10
(Received via mailing list)
On Feb 11, 11:14 am, "Levy Carneiro Jr." <removed_email_address@domain.invalid>
wrote:

>
> Is there a way to expire pages without having to hack it?
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
Levy Carneiro Jr. (Guest)
on 2009-03-01 05:32
(Received via mailing list)
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
Philip H. (Guest)
on 2009-03-01 06:33
(Received via mailing list)
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)
This topic is locked and can not be replied to.