Topic: Page Caching/Action Caching. What do do and where?

So I need to implement caching on a site.

So far I was working with page caching and saw that I ran into some pretty big problems.  The page caching was originally going to be used for when a person is logged out but there was also a login bar at the top.  The login bar is apparently also page cached which is very bad when authentication tokens become invalid which I just ran into a moment ago so I decided to check in with the pros first before deciding to completely throw out page caching and go with action caching.

Another problem I had was when a page was previously https and I went to a cached page from a link that needed to be http the https stayed in the URL causing a few problems. Is there a way to make a page cached page always have the correct protocol?

Basically, it looks like I will need to use action caching for the logged out pages but keep the header fully dynamic.  So the header will be loaded, then the action that shows a certain static page should be action cached I guess.  In the header, I'm also thinking of doing fragment caching on the navigation buttons since those are always the same no matter what.  It's only the login button area that changes.

And there's a static footer on every page so I guess I should fragment cache that since it's not part of an action.  I see no way it could be action cached.


I'm just starting with caching so I could use some tips and if the things I'm planning on doing are good ideas.  i'm worried my caching might slow the site down rather than speed it up since I read that fragment caching is the slowest and I'm not sure if it'll provide any speed up at all if it's for little things like a navbar.  The navbar itself does take some processing with ruby though when not cached.

I read a pretty useful article here although it's from 2007 so it may be dated:
http://railsenvy.com/2007/2/28/rails-caching-tutorial

Last edited by ill (2009-07-27 23:46:20)

Re: Page Caching/Action Caching. What do do and where?

Here are a couple of thoughts based on your posting:

1) Have you looked at the layout option for action caching in Rails 2.2? 

That would allow you to have a layout that includes a login bar which can be rendered dynamically, the rest of the page would be cached. You wouldn't need to deal with fragment caching.

2) Is fragment caching faster than not using it at all?

If you do any significant ruby processing it will likely be faster.  We use it extensively on our site.  However it will likely introduce a minor delay if you cache static HTML.  The best way to confirm its effects is by testing the performance of the pages.

Here's another good link with more recent information:

http://guides.rubyonrails.org/caching_with_rails.html

Play postseason fantasy sports at Fantasy Postseason - Written in RoR

Re: Page Caching/Action Caching. What do do and where?

Hmm OK read that and got a bunch of stuff working.

Now I'm trying to use a sweeper to expire the cached items that get modified, except it's not working.  First of all, when I use :controller => <controller name goes here> that gets appended to the end of the expired URL which makes absolutely no sense.

I can see this in the log when it says Expired fragment: <URL goes here>

When I type the expire_page function without :controller it still has no effect.

So basically I'm doing action caching.

Here's the sweeper code, and I can see that it gets executed in the logs when I update the coupon.

#----------------------------------
#sweeps for new and modified coupons to update the cached coupon and stores page on the home page

class CouponSweeper < ActionController::Caching::Sweeper

  #observe coupons
  observe Coupon
 
  #after created or updated
  def after_save(record)   
    expire_cache_for(record)   
  end
 
  def after_destroy(record)   
    expire_cache_for(record)   
  end
 
  def expire_cache_for(record)
       
    #expire coupon display
    expire_action(:action => 'show', :id => record.id)
 
  end

end


This is what it says in the logs
Expired fragment: views/localhost/coupons/<correct id goes here which it does>

The actual URL that is used to show that in the browser is completely different though.

Then when I write expire_action(:controller => 'coupons', :action => 'show', :id => record.id)
It does this:

Expired fragment: views/localhost/coupons/101?contoller=coupons

I've tried this with page caching and it does the same thing.  Or is it in fact supposed to append controller as a URL parameter?

It still doesn't work either way.  My action cache doesn't seem to expire.




Another thing I've noticed is that different URLs leading to the same action cache separately.  So if I say  coupons/101.html, that's cached.  But then when I go to coupons/101 it leads to the exact same output from the controller but that's cached separately.  Is there a way to get all those different formats of the URL to cache as one?  This might be the reason why my sweeper isn't working either.  It's probably expiring some other URL that isn't the one that is actually linked to on the page.  I've tried many forms of the URL to lead to the same output and none of them appear to have expired after changing an object's data.

Last edited by ill (2009-07-30 23:00:41)

Re: Page Caching/Action Caching. What do do and where?

Anyone have any tips on this?  I'm still stuck...

Re: Page Caching/Action Caching. What do do and where?

OK I got my caching working better now by completely rewriting it from scratch fixing that weird controller bug where it was appended as a URL parameter and manualyl telling it to store the cache in a certain path so I can actually see the files.  I know exactly what's causing the needed fragment to not expire now but don't know how to fix it.

The path being expired is different from the path being cached.

When a page is cached it does it to this location:

views/localhost/coupons/show/<action name thing goes here>

When it expires it does this path which is the path in the browser URL.  We have routing code that makes it so when you type coupons/<coupon id> it does the show method and shows the coupon for that id instead of having the url be coupons/show/<coupon id>.
views/localhost/coupons/<action name thing goes here>

How does rails get these two paths confused?  Why is it that when it caches a certain URL it adds the controller method but when it expires that action it omits the method name in the path?  Is this a bug?  Is there a way to override it?  I can't even figure it out...  I can't even logically figure out why it works a certain way in one situation and differently in another.  They both work with the same URL.

Here's the sweeper code now:

class CouponSweeper < ActionController::Caching::Sweeper
  observe Coupon

  def after_save(coupon)
    expire_cache_for(coupon)
  end
 
  def after_destroy(coupon)
    expire_cache_for(coupon)
  end
         
  private
  def expire_cache_for(record)
   
    expire_action(:controller => 'coupons', :action => 'show', :id => record)
   
  end
end


I've seen that it does expire the cache when the path to expire matches what is there.  As an experiment I copied the cache files from where they are stored to where the expire method cleans them from and I see the cache files are deleted properly.  There are just path mismatches that I can't figure out how to fix.


Also we are using to_param on the URL so when a link to a coupon is created it's not just the id like coupons/55.  It's made like this: coupons/55-Socks-50-off-at-Walmart.  The problem is that when someone types coupons/55 it takes them to the same place but cached separately which is pretty undesirable.  This means if someone goes back to coupons/55 the cache for that item isn't expired.  Better yet, if someone goes to coupons/55.html that is cached separately from coupons/55 so now there are all these different URLs cached for the same thing.  Is there some way to automatically change the URL to the one that needs to be cached?  Sure I could try to expire all versions of that URL but that's unreliable since I might miss something, also it defeats the purpose of caching if the page is cached but the URL is typed differently and as a result the same cached page has to be reloaded.

I tried to see if it can be done through routing but haven't found anything yet.

Last edited by ill (2009-08-04 17:12:20)