Thursday, October 18, 2012

Page Caching and selectively preventing it

I was told this joke from my brother:

There are three problems in programming -- First is counting.  Second is expiring caches.

Me being the idiot that I am asked, what's the third one?

Sigh.

So page caching in Rails is *simple*.
go to Controller, add:

  caches_page :show  


Clearing the cache was an entirely different proposition, but I'll talk about that later.

So here's the scenario.  I have a simple CMS system in place for my project.  it allows the user to create, edit the content for their website.  It also has special editable content pages that are secured using Devise (an awesome gem btw).

The problem was that the secure pages were being cached as well.  Having a html file created in the public directory is a double edged sword.  Having it there meant that the Rails stack (which is slow) never gets called, Yay!  But it also meant that the secure information was now accessible in the public if anyone knew the path to the file.

The only way to authorize those pages was to have it run through the Rails stack.  So I needed to not cache those pages.

On Apidock I found an interesting little snippet using a Proc to prevent caching based on the response type.  Not quite what I needed, but it was on the right track.

1:  # cache the index action  
2:  caches_page :index  
3:  # cache the index action except for JSON requests  
4:  caches_page :index, :if => Proc.new { |c| !c.request.format.json? }  
5:  # don't gzip images  
6:  caches_page :image, :gzip => false  

My standard learning/exploration tool is the debugger tool.  I toss a debugger in the code and see what is available in that specific scope.  Inspecting c was unmanageable as page after page of code screamed past.  What I needed was a way to walk through it in smaller steps.  Google to the rescue!  I found that I could list the params of the object [ c.params].  Ah hah!  Now, I could determine which page was being shown based on the id and from that it was a relatively simple matter of creating an array to check against.

  caches_page :show, :unless => Proc.new { |c|
    secure_pages = Page.find_by_path("secure").pages.map { |page| page.id }
    secure_pages.include? c.params["id"]
  }


To my eyes, it looks simple and clean.  But as a novice, I'm still always worried that I'm doing things the hard way, or worse, the wrong way.


---------------------------

So, I ran into a little glitch.

Having it find_by_path returns a nil when there are no secure pages but a .where('path = ?', 'secure') return an []

The former blows up when I don't have a secure page, the latter gracefully just doesn't find anything.

Gotta love those subtle differences.






1 comment:

  1. Among different things, Ignition ensures you've got got} the best possible|the absolute best|the very best} expertise by offering you amazing cellular compatibility. There won't be a particular application for Ignition users, however it does provide net site|a internet site} that works flawlessly on all cellular gadgets. Our group of professional gamblers went above and past search out|to search out} the top websites obtainable on the market free of charge excessive RTP slots. After benefit of|benefiting from|profiting from} the welcome bonus, 점보카지노 you'll be able to|you possibly can} get pleasure from numerous perks by joining the Loyalty Program.

    ReplyDelete