mirror of
https://github.com/rails/rails.git
synced 2022-11-09 12:12:34 -05:00
a03e2b356c
rake doc:guides The rake task will generate guides inside doc/guides directory of your application. Open index.html to browse.
577 lines
30 KiB
HTML
577 lines
30 KiB
HTML
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
|
|
<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">
|
|
<head>
|
|
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
|
|
<title>Caching with Rails: An overview</title>
|
|
<!--[if lt IE 8]>
|
|
<script src="http://ie7-js.googlecode.com/svn/version/2.0(beta3)/IE8.js" type="text/javascript"></script>
|
|
<![endif]-->
|
|
<link href="stylesheets/base.css" media="screen" rel="Stylesheet" type="text/css" />
|
|
<link href="stylesheets/forms.css" media="screen" rel="Stylesheet" type="text/css" />
|
|
<link href="stylesheets/more.css" media="screen" rel="Stylesheet" type="text/css" />
|
|
<style type="text/css">
|
|
div#container {
|
|
max-width: 900px;
|
|
padding-bottom: 3em;
|
|
}
|
|
|
|
div#content {
|
|
margin-left: 200px;
|
|
}
|
|
|
|
div#container.notoc {
|
|
max-width: 600px;
|
|
}
|
|
|
|
.notoc div#content {
|
|
margin-left: 0;
|
|
}
|
|
|
|
pre {
|
|
line-height: 1.4em;
|
|
}
|
|
|
|
#content p tt {
|
|
background: #eeeeee;
|
|
border: solid 1px #cccccc;
|
|
padding: 3px;
|
|
}
|
|
|
|
dt {
|
|
font-weight: bold;
|
|
}
|
|
|
|
#content dt tt {
|
|
font-size: 10pt;
|
|
}
|
|
|
|
dd {
|
|
margin-left: 3em;
|
|
}
|
|
|
|
#content dt tt, #content pre tt {
|
|
background: none;
|
|
padding: 0;
|
|
border: 0;
|
|
}
|
|
|
|
#content .olist ol {
|
|
margin-left: 2em;
|
|
}
|
|
|
|
#header {
|
|
position: relative;
|
|
max-width: 840px;
|
|
margin-left: auto;
|
|
margin-right: auto;
|
|
}
|
|
|
|
#header.notoc {
|
|
max-width: 580px;
|
|
}
|
|
|
|
#logo {
|
|
position: absolute;
|
|
left: 10px;
|
|
top: 10px;
|
|
width: 110px;
|
|
height: 140px;
|
|
}
|
|
|
|
div#header h1#site_title {
|
|
background: url('images/ruby_on_rails_by_mike_rundle2.gif') top left no-repeat;
|
|
position: absolute;
|
|
width: 392px;
|
|
height: 55px;
|
|
left: 145px;
|
|
top: 20px;
|
|
margin: 0;
|
|
padding: 0;
|
|
}
|
|
|
|
#site_title span {
|
|
display: none;
|
|
}
|
|
|
|
#site_title_tagline {
|
|
display: none;
|
|
}
|
|
|
|
ul#navMain {
|
|
position: absolute;
|
|
margin: 0;
|
|
padding: 0;
|
|
top: 97px;
|
|
left: 145px;
|
|
}
|
|
|
|
.left-floaty, .right-floaty {
|
|
padding: 15px;
|
|
}
|
|
|
|
.admonitionblock,
|
|
.tableblock {
|
|
margin-left: 1em;
|
|
margin-right: 1em;
|
|
margin-top: 0.25em;
|
|
margin-bottom: 1em;
|
|
}
|
|
|
|
.admonitionblock .icon {
|
|
padding-right: 8px;
|
|
}
|
|
|
|
.admonitionblock .content {
|
|
border: solid 1px #ffda78;
|
|
background: #fffebd;
|
|
padding: 10px;
|
|
padding-top: 8px;
|
|
padding-bottom: 8px;
|
|
}
|
|
|
|
.admonitionblock .title {
|
|
font-size: 140%;
|
|
margin-bottom: 0.5em;
|
|
}
|
|
|
|
.tableblock table {
|
|
border: solid 1px #aaaaff;
|
|
background: #f0f0ff;
|
|
}
|
|
|
|
.tableblock th {
|
|
background: #e0e0e0;
|
|
}
|
|
|
|
.tableblock th,
|
|
.tableblock td {
|
|
padding: 3px;
|
|
padding-left: 5px;
|
|
padding-right: 5px;
|
|
}
|
|
|
|
.sidebarblock {
|
|
margin-top: 0.25em;
|
|
margin: 1em;
|
|
border: solid 1px #ccccbb;
|
|
padding: 8px;
|
|
background: #ffffe0;
|
|
}
|
|
|
|
.sidebarblock .sidebar-title {
|
|
font-size: 140%;
|
|
font-weight: 600;
|
|
margin-bottom: 0.3em;
|
|
}
|
|
|
|
.sidebarblock .sidebar-content > .para:last-child > p {
|
|
margin-bottom: 0;
|
|
}
|
|
|
|
.sidebarblock .sidebar-title a {
|
|
text-decoration: none;
|
|
}
|
|
|
|
.sidebarblock .sidebar-title a:hover {
|
|
text-decoration: underline;
|
|
}
|
|
|
|
</style>
|
|
</head>
|
|
<body>
|
|
<div id="header" >
|
|
<div id="logo">
|
|
<a href="index.html" title="Ruby on Rails"><img src="images/rails_logo_remix.gif" alt="Rails" height="140" width="110" /></a>
|
|
</div>
|
|
|
|
<h1 id="site_title"><span>Ruby on Rails</span></h1>
|
|
<h2 id="site_title_tagline">Sustainable productivity for web-application development</h2>
|
|
|
|
<ul id="navMain">
|
|
<li class="first-child"><a href="http://www.rubyonrails.org/" title="Ruby on Rails" class="ruby_on_rails">Ruby on Rails</a></li>
|
|
<li><a class="manuals" href="index.html" title="Manuals Index">Guides Index</a></li>
|
|
</ul>
|
|
</div>
|
|
|
|
<div id="container">
|
|
|
|
<div id="sidebar">
|
|
<h2>Chapters</h2>
|
|
<ol>
|
|
<li>
|
|
<a href="#_basic_caching">Basic Caching</a>
|
|
<ul>
|
|
|
|
<li><a href="#_page_caching">Page Caching</a></li>
|
|
|
|
<li><a href="#_action_caching">Action Caching</a></li>
|
|
|
|
<li><a href="#_fragment_caching">Fragment Caching</a></li>
|
|
|
|
<li><a href="#_sweepers">Sweepers</a></li>
|
|
|
|
<li><a href="#_sql_caching">SQL Caching</a></li>
|
|
|
|
<li><a href="#_cache_stores">Cache stores</a></li>
|
|
|
|
</ul>
|
|
</li>
|
|
<li>
|
|
<a href="#_advanced_caching">Advanced Caching</a>
|
|
</li>
|
|
</ol>
|
|
</div>
|
|
|
|
<div id="content">
|
|
<h1>Caching with Rails: An overview</h1>
|
|
<div id="preamble">
|
|
<div class="sectionbody">
|
|
<div class="para"><p>Everyone caches. This guide will teach you what you need to know about
|
|
avoiding that expensive round-trip to your database and returning what you
|
|
need to return to those hungry web clients in the shortest time possible.</p></div>
|
|
</div>
|
|
</div>
|
|
<h2 id="_basic_caching">1. Basic Caching</h2>
|
|
<div class="sectionbody">
|
|
<div class="para"><p>This is an introduction to the three types of caching techniques that Rails
|
|
provides by default without the use of any third party plugins.</p></div>
|
|
<div class="para"><p>To get started make sure Base.perform_caching is set to true for your
|
|
environment.</p></div>
|
|
<div class="listingblock">
|
|
<div class="content"><!-- Generator: GNU source-highlight 2.9
|
|
by Lorenzo Bettini
|
|
http://www.lorenzobettini.it
|
|
http://www.gnu.org/software/src-highlite -->
|
|
<pre><tt>Base<span style="color: #990000">.</span>perform_caching <span style="color: #990000">=</span> <span style="font-weight: bold"><span style="color: #0000FF">true</span></span>
|
|
</tt></pre></div></div>
|
|
<h3 id="_page_caching">1.1. Page Caching</h3>
|
|
<div class="para"><p>Page caching is a Rails mechanism which allows the request for a generated
|
|
page to be fulfilled by the webserver, without ever having to go through the
|
|
Rails stack at all. Obviously, this is super fast. Unfortunately, it can't be
|
|
applied to every situation (such as pages that need authentication) and since
|
|
the webserver is literally just serving a file from the filesystem, cache
|
|
expiration is an issue that needs to be dealt with.</p></div>
|
|
<div class="para"><p>So, how do you enable this super-fast cache behavior? Simple, let's say you
|
|
have a controller called ProductController and a <em>list</em> action that lists all
|
|
the products</p></div>
|
|
<div class="listingblock">
|
|
<div class="content"><!-- Generator: GNU source-highlight 2.9
|
|
by Lorenzo Bettini
|
|
http://www.lorenzobettini.it
|
|
http://www.gnu.org/software/src-highlite -->
|
|
<pre><tt><span style="font-weight: bold"><span style="color: #0000FF">class</span></span> ProductController <span style="color: #990000"><</span> ActionController
|
|
|
|
cache_page <span style="color: #990000">:</span>list
|
|
|
|
<span style="font-weight: bold"><span style="color: #0000FF">def</span></span> list<span style="color: #990000">;</span> <span style="font-weight: bold"><span style="color: #0000FF">end</span></span>
|
|
|
|
<span style="font-weight: bold"><span style="color: #0000FF">end</span></span>
|
|
</tt></pre></div></div>
|
|
<div class="para"><p>The first time anyone requestsion products/list, Rails will generate a file
|
|
called list.html and the webserver will then look for that file before it
|
|
passes the next request for products/list to your Rails application.</p></div>
|
|
<div class="para"><p>By default, the page cache directory is set to Rails.public_path (which is
|
|
usually set to RAILS_ROOT + "/public") and this can be configured by changing
|
|
the configuration setting Base.cache_public_directory</p></div>
|
|
<div class="para"><p>The page caching mechanism will automatically add a .html exxtension to
|
|
requests for pages that do not have an extension to make it easy for the
|
|
webserver to find those pages and this can be configured by changing the
|
|
configuration setting Base.page_cache_extension</p></div>
|
|
<div class="para"><p>In order to expire this page when a new product is added we could extend our
|
|
example controler like this:</p></div>
|
|
<div class="listingblock">
|
|
<div class="content"><!-- Generator: GNU source-highlight 2.9
|
|
by Lorenzo Bettini
|
|
http://www.lorenzobettini.it
|
|
http://www.gnu.org/software/src-highlite -->
|
|
<pre><tt><span style="font-weight: bold"><span style="color: #0000FF">class</span></span> ProductController <span style="color: #990000"><</span> ActionController
|
|
|
|
cache_page <span style="color: #990000">:</span>list
|
|
|
|
<span style="font-weight: bold"><span style="color: #0000FF">def</span></span> list<span style="color: #990000">;</span> <span style="font-weight: bold"><span style="color: #0000FF">end</span></span>
|
|
|
|
<span style="font-weight: bold"><span style="color: #0000FF">def</span></span> create
|
|
expire_page <span style="color: #990000">:</span>action <span style="color: #990000">=></span> <span style="color: #990000">:</span>list
|
|
<span style="font-weight: bold"><span style="color: #0000FF">end</span></span>
|
|
|
|
<span style="font-weight: bold"><span style="color: #0000FF">end</span></span>
|
|
</tt></pre></div></div>
|
|
<div class="para"><p>If you want a more complicated expiration scheme, you can use cache sweepers
|
|
to expire cached objects when things change. This is covered in the section on Sweepers.</p></div>
|
|
<h3 id="_action_caching">1.2. Action Caching</h3>
|
|
<div class="para"><p>One of the issues with page caching is that you cannot use it for pages that
|
|
require to restrict access somehow. This is where Action Caching comes in.
|
|
Action Caching works like Page Caching except for the fact that the incoming
|
|
web request does go from the webserver to the Rails stack and Action Pack so
|
|
that before_filters can be run on it before the cache is served, so that
|
|
authentication and other restrictions can be used while still serving the
|
|
result of the output from a cached copy.</p></div>
|
|
<div class="para"><p>Clearing the cache works in the exact same way as with Page Caching.</p></div>
|
|
<div class="para"><p>Let's say you only wanted authenticated users to edit or create a Product
|
|
object, but still cache those pages:</p></div>
|
|
<div class="listingblock">
|
|
<div class="content"><!-- Generator: GNU source-highlight 2.9
|
|
by Lorenzo Bettini
|
|
http://www.lorenzobettini.it
|
|
http://www.gnu.org/software/src-highlite -->
|
|
<pre><tt><span style="font-weight: bold"><span style="color: #0000FF">class</span></span> ProductController <span style="color: #990000"><</span> ActionController
|
|
|
|
before_filter <span style="color: #990000">:</span>authenticate<span style="color: #990000">,</span> <span style="color: #990000">:</span>only <span style="color: #990000">=></span> <span style="color: #990000">[</span> <span style="color: #990000">:</span>edit<span style="color: #990000">,</span> <span style="color: #990000">:</span>create <span style="color: #990000">]</span>
|
|
cache_page <span style="color: #990000">:</span>list
|
|
caches_action <span style="color: #990000">:</span>edit
|
|
|
|
<span style="font-weight: bold"><span style="color: #0000FF">def</span></span> list<span style="color: #990000">;</span> <span style="font-weight: bold"><span style="color: #0000FF">end</span></span>
|
|
|
|
<span style="font-weight: bold"><span style="color: #0000FF">def</span></span> create
|
|
expire_page <span style="color: #990000">:</span>action <span style="color: #990000">=></span> <span style="color: #990000">:</span>list
|
|
expire_action <span style="color: #990000">:</span>action <span style="color: #990000">=></span> <span style="color: #990000">:</span>edit
|
|
<span style="font-weight: bold"><span style="color: #0000FF">end</span></span>
|
|
|
|
<span style="font-weight: bold"><span style="color: #0000FF">def</span></span> edit<span style="color: #990000">;</span> <span style="font-weight: bold"><span style="color: #0000FF">end</span></span>
|
|
|
|
<span style="font-weight: bold"><span style="color: #0000FF">end</span></span>
|
|
</tt></pre></div></div>
|
|
<div class="para"><p>And you can also use :if (or :unless) to pass a Proc that specifies when the
|
|
action should be cached. Also, you can use :layout ⇒ false to cache without
|
|
layout so that dynamic information in the layout such as logged in user info
|
|
or the number of items in the cart can be left uncached. This feature is
|
|
available as of Rails 2.2.</p></div>
|
|
<div class="para"><p>[More: more examples? Walk-through of action caching from request to response?
|
|
Description of Rake tasks to clear cached files? Show example of
|
|
subdomain caching? Talk about :cache_path, :if and assing blocks/Procs
|
|
to expire_action?]</p></div>
|
|
<h3 id="_fragment_caching">1.3. Fragment Caching</h3>
|
|
<div class="para"><p>Life would be perfect if we could get away with caching the entire contents of
|
|
a page or action and serving it out to the world. Unfortunately, dynamic web
|
|
applications usually build pages with a variety of components not all of which
|
|
have the same caching characteristics. In order to address such a dynamically
|
|
created page where different parts of the page need to be cached and expired
|
|
differently Rails provides a mechanism called Fragment caching.</p></div>
|
|
<div class="para"><p>Fragment caching allows a fragment of view logic to be wrapped in a cache
|
|
block and served out of the cache store when the next request comes in.</p></div>
|
|
<div class="para"><p>As an example, if you wanted to show all the orders placed on your website in
|
|
real time and didn't want to cache that part of the page, but did want to
|
|
cache the part of the page which lists all products available, you could use
|
|
this piece of code:</p></div>
|
|
<div class="listingblock">
|
|
<div class="content"><!-- Generator: GNU source-highlight 2.9
|
|
by Lorenzo Bettini
|
|
http://www.lorenzobettini.it
|
|
http://www.gnu.org/software/src-highlite -->
|
|
<pre><tt><span style="color: #FF0000"><% Order.find_recent.each do |o| %></span>
|
|
<span style="color: #FF0000"><%= o.buyer.name %></span> bought <span style="color: #FF0000"><% o.product.name %></span>
|
|
<span style="color: #FF0000"><% end %></span>
|
|
|
|
<span style="color: #FF0000"><% cache do %></span>
|
|
All available products<span style="color: #990000">:</span>
|
|
<span style="color: #FF0000"><% Product.find(:all).each do |p| %></span>
|
|
<span style="color: #FF0000"><%= link_to p.name, product_url(p) %></span>
|
|
<span style="color: #FF0000"><% end %></span>
|
|
<span style="color: #FF0000"><% end %></span>
|
|
</tt></pre></div></div>
|
|
<div class="para"><p>The cache block in our example will bind to the action that called it and is
|
|
written out to the same place as the Action Cache, which means that if you
|
|
want to cache multiple fragments per action, you should provide an action_path to the cache call:</p></div>
|
|
<div class="listingblock">
|
|
<div class="content"><!-- Generator: GNU source-highlight 2.9
|
|
by Lorenzo Bettini
|
|
http://www.lorenzobettini.it
|
|
http://www.gnu.org/software/src-highlite -->
|
|
<pre><tt><span style="color: #FF0000"><% cache(:action =></span> <span style="color: #FF0000">'recent'</span><span style="color: #990000">,</span> <span style="color: #990000">:</span>action_suffix <span style="color: #990000">=></span> <span style="color: #FF0000">'all_products'</span><span style="color: #990000">)</span> <span style="font-weight: bold"><span style="color: #0000FF">do</span></span> <span style="color: #990000">%></span>
|
|
All available products<span style="color: #990000">:</span>
|
|
</tt></pre></div></div>
|
|
<div class="para"><p>and you can expire it using the expire_fragment method, like so:</p></div>
|
|
<div class="listingblock">
|
|
<div class="content"><!-- Generator: GNU source-highlight 2.9
|
|
by Lorenzo Bettini
|
|
http://www.lorenzobettini.it
|
|
http://www.gnu.org/software/src-highlite -->
|
|
<pre><tt>expire_fragment<span style="color: #990000">(:</span>controller <span style="color: #990000">=></span> <span style="color: #FF0000">'producst'</span><span style="color: #990000">,</span> <span style="color: #990000">:</span>action <span style="color: #990000">=></span> <span style="color: #FF0000">'recent'</span><span style="color: #990000">,</span> <span style="color: #990000">:</span>action_suffix <span style="color: #990000">=></span> 'all_products<span style="color: #990000">)</span>
|
|
</tt></pre></div></div>
|
|
<h3 id="_sweepers">1.4. Sweepers</h3>
|
|
<div class="para"><p>Cache sweeping is a mechanism which allows you to get around having a ton of
|
|
expire_{page,action,fragment} calls in your code by moving all the work
|
|
required to expire cached content into a ActionController::Caching::Sweeper
|
|
class that is an Observer and looks for changes to an object via callbacks,
|
|
and when a change occurs it expires the caches associated with that object n
|
|
an around or after filter.</p></div>
|
|
<div class="para"><p>Continuing with our Product controller example, we could rewrite it with a
|
|
sweeper such as the following:</p></div>
|
|
<div class="listingblock">
|
|
<div class="content"><!-- Generator: GNU source-highlight 2.9
|
|
by Lorenzo Bettini
|
|
http://www.lorenzobettini.it
|
|
http://www.gnu.org/software/src-highlite -->
|
|
<pre><tt><span style="font-weight: bold"><span style="color: #0000FF">class</span></span> StoreSweeper <span style="color: #990000"><</span> ActionController<span style="color: #990000">::</span>Caching<span style="color: #990000">::</span>Sweeper
|
|
observe Product <span style="font-style: italic"><span style="color: #9A1900"># This sweeper is going to keep an eye on the Post model</span></span>
|
|
|
|
<span style="font-style: italic"><span style="color: #9A1900"># If our sweeper detects that a Post was created call this</span></span>
|
|
<span style="font-weight: bold"><span style="color: #0000FF">def</span></span> after_create<span style="color: #990000">(</span>product<span style="color: #990000">)</span>
|
|
expire_cache_for<span style="color: #990000">(</span>product<span style="color: #990000">)</span>
|
|
<span style="font-weight: bold"><span style="color: #0000FF">end</span></span>
|
|
|
|
<span style="font-style: italic"><span style="color: #9A1900"># If our sweeper detects that a Post was updated call this</span></span>
|
|
<span style="font-weight: bold"><span style="color: #0000FF">def</span></span> after_update<span style="color: #990000">(</span>product<span style="color: #990000">)</span>
|
|
expire_cache_for<span style="color: #990000">(</span>product<span style="color: #990000">)</span>
|
|
<span style="font-weight: bold"><span style="color: #0000FF">end</span></span>
|
|
|
|
<span style="font-style: italic"><span style="color: #9A1900"># If our sweeper detects that a Post was deleted call this</span></span>
|
|
<span style="font-weight: bold"><span style="color: #0000FF">def</span></span> after_destroy<span style="color: #990000">(</span>product<span style="color: #990000">)</span>
|
|
expire_cache_for<span style="color: #990000">(</span>product<span style="color: #990000">)</span>
|
|
<span style="font-weight: bold"><span style="color: #0000FF">end</span></span>
|
|
|
|
private
|
|
<span style="font-weight: bold"><span style="color: #0000FF">def</span></span> expire_cache_for<span style="color: #990000">(</span>record<span style="color: #990000">)</span>
|
|
<span style="font-style: italic"><span style="color: #9A1900"># Expire the list page now that we added a new product</span></span>
|
|
expire_page<span style="color: #990000">(:</span>controller <span style="color: #990000">=></span> <span style="color: #FF0000">'#{record}'</span><span style="color: #990000">,</span> <span style="color: #990000">:</span>action <span style="color: #990000">=></span> <span style="color: #FF0000">'list'</span><span style="color: #990000">)</span>
|
|
|
|
<span style="font-style: italic"><span style="color: #9A1900"># Expire a fragment</span></span>
|
|
expire_fragment<span style="color: #990000">(:</span>controller <span style="color: #990000">=></span> <span style="color: #FF0000">'#{record}'</span><span style="color: #990000">,</span> <span style="color: #990000">:</span>action <span style="color: #990000">=></span> <span style="color: #FF0000">'recent'</span><span style="color: #990000">,</span> <span style="color: #990000">:</span>action_suffix <span style="color: #990000">=></span> <span style="color: #FF0000">'all_products'</span><span style="color: #990000">)</span>
|
|
<span style="font-weight: bold"><span style="color: #0000FF">end</span></span>
|
|
<span style="font-weight: bold"><span style="color: #0000FF">end</span></span>
|
|
</tt></pre></div></div>
|
|
<div class="para"><p>Then we add it to our controller to tell it to call the sweeper when certain
|
|
actions are called. So, if we wanted to expire the cached content for the
|
|
list and edit actions when the create action was called, we could do the
|
|
following:</p></div>
|
|
<div class="listingblock">
|
|
<div class="content"><!-- Generator: GNU source-highlight 2.9
|
|
by Lorenzo Bettini
|
|
http://www.lorenzobettini.it
|
|
http://www.gnu.org/software/src-highlite -->
|
|
<pre><tt><span style="font-weight: bold"><span style="color: #0000FF">class</span></span> ProductController <span style="color: #990000"><</span> ActionController
|
|
|
|
before_filter <span style="color: #990000">:</span>authenticate<span style="color: #990000">,</span> <span style="color: #990000">:</span>only <span style="color: #990000">=></span> <span style="color: #990000">[</span> <span style="color: #990000">:</span>edit<span style="color: #990000">,</span> <span style="color: #990000">:</span>create <span style="color: #990000">]</span>
|
|
cache_page <span style="color: #990000">:</span>list
|
|
caches_action <span style="color: #990000">:</span>edit
|
|
cache_sweeper <span style="color: #990000">:</span>store_sweeper<span style="color: #990000">,</span> <span style="color: #990000">:</span>only <span style="color: #990000">=></span> <span style="color: #990000">[</span> <span style="color: #990000">:</span>create <span style="color: #990000">]</span>
|
|
|
|
<span style="font-weight: bold"><span style="color: #0000FF">def</span></span> list<span style="color: #990000">;</span> <span style="font-weight: bold"><span style="color: #0000FF">end</span></span>
|
|
|
|
<span style="font-weight: bold"><span style="color: #0000FF">def</span></span> create
|
|
expire_page <span style="color: #990000">:</span>action <span style="color: #990000">=></span> <span style="color: #990000">:</span>list
|
|
expire_action <span style="color: #990000">:</span>action <span style="color: #990000">=></span> <span style="color: #990000">:</span>edit
|
|
<span style="font-weight: bold"><span style="color: #0000FF">end</span></span>
|
|
|
|
<span style="font-weight: bold"><span style="color: #0000FF">def</span></span> edit<span style="color: #990000">;</span> <span style="font-weight: bold"><span style="color: #0000FF">end</span></span>
|
|
|
|
<span style="font-weight: bold"><span style="color: #0000FF">end</span></span>
|
|
</tt></pre></div></div>
|
|
<h3 id="_sql_caching">1.5. SQL Caching</h3>
|
|
<div class="para"><p>Query caching is a Rails feature that caches the result set returned by each
|
|
query so that if Rails encounters the same query again for that request, it
|
|
will used the cached result set as opposed to running the query against the
|
|
database again.</p></div>
|
|
<div class="para"><p>For example:</p></div>
|
|
<div class="listingblock">
|
|
<div class="content"><!-- Generator: GNU source-highlight 2.9
|
|
by Lorenzo Bettini
|
|
http://www.lorenzobettini.it
|
|
http://www.gnu.org/software/src-highlite -->
|
|
<pre><tt><span style="font-weight: bold"><span style="color: #0000FF">class</span></span> ProductController <span style="color: #990000"><</span> ActionController
|
|
|
|
before_filter <span style="color: #990000">:</span>authenticate<span style="color: #990000">,</span> <span style="color: #990000">:</span>only <span style="color: #990000">=></span> <span style="color: #990000">[</span> <span style="color: #990000">:</span>edit<span style="color: #990000">,</span> <span style="color: #990000">:</span>create <span style="color: #990000">]</span>
|
|
cache_page <span style="color: #990000">:</span>list
|
|
caches_action <span style="color: #990000">:</span>edit
|
|
cache_sweeper <span style="color: #990000">:</span>store_sweeper<span style="color: #990000">,</span> <span style="color: #990000">:</span>only <span style="color: #990000">=></span> <span style="color: #990000">[</span> <span style="color: #990000">:</span>create <span style="color: #990000">]</span>
|
|
|
|
<span style="font-weight: bold"><span style="color: #0000FF">def</span></span> list
|
|
<span style="font-style: italic"><span style="color: #9A1900"># Run a find query</span></span>
|
|
Product<span style="color: #990000">.</span>find<span style="color: #990000">(:</span>all<span style="color: #990000">)</span>
|
|
|
|
<span style="color: #990000">...</span>
|
|
|
|
<span style="font-style: italic"><span style="color: #9A1900"># Run the same query again</span></span>
|
|
Product<span style="color: #990000">.</span>find<span style="color: #990000">(:</span>all<span style="color: #990000">)</span>
|
|
<span style="font-weight: bold"><span style="color: #0000FF">end</span></span>
|
|
|
|
<span style="font-weight: bold"><span style="color: #0000FF">def</span></span> create
|
|
expire_page <span style="color: #990000">:</span>action <span style="color: #990000">=></span> <span style="color: #990000">:</span>list
|
|
expire_action <span style="color: #990000">:</span>action <span style="color: #990000">=></span> <span style="color: #990000">:</span>edit
|
|
<span style="font-weight: bold"><span style="color: #0000FF">end</span></span>
|
|
|
|
<span style="font-weight: bold"><span style="color: #0000FF">def</span></span> edit<span style="color: #990000">;</span> <span style="font-weight: bold"><span style="color: #0000FF">end</span></span>
|
|
|
|
<span style="font-weight: bold"><span style="color: #0000FF">end</span></span>
|
|
</tt></pre></div></div>
|
|
<div class="para"><p>In the <em>list</em> action above, the result set returned by the first
|
|
Product.find(:all) will be cached and will be used to avoid querying the
|
|
database again the second time that finder is called.</p></div>
|
|
<div class="para"><p>Query caches are created at the start of an action and destroyed at the end of
|
|
that action and thus persist only for the duration of the action.</p></div>
|
|
<h3 id="_cache_stores">1.6. Cache stores</h3>
|
|
<div class="para"><p>Rails provides different stores for the cached data for action and fragment
|
|
caches. Page caches are always stored on disk.</p></div>
|
|
<div class="para"><p>The cache stores provided include:</p></div>
|
|
<div class="para"><p>1) Memory store: Cached data is stored in the memory allocated to the Rails
|
|
process, which is fine for WEBrick and for FCGI (if you
|
|
don't care that each FCGI process holds its own fragment
|
|
store). It's not suitable for CGI as the process is thrown
|
|
away at the end of each request. It can potentially also
|
|
take up a lot of memory since each process keeps all the
|
|
caches in memory.</p></div>
|
|
<div class="listingblock">
|
|
<div class="content"><!-- Generator: GNU source-highlight 2.9
|
|
by Lorenzo Bettini
|
|
http://www.lorenzobettini.it
|
|
http://www.gnu.org/software/src-highlite -->
|
|
<pre><tt>ActionController<span style="color: #990000">::</span>Base<span style="color: #990000">.</span>cache_store <span style="color: #990000">=</span> <span style="color: #990000">:</span>memory_store
|
|
</tt></pre></div></div>
|
|
<div class="para"><p>2) File store: Cached data is stored on the disk, this is the default store
|
|
and the default path for this store is: /tmp/cache. Works
|
|
well for all types of environments and allows all processes
|
|
running from the same application directory to access the
|
|
cached content.</p></div>
|
|
<div class="listingblock">
|
|
<div class="content"><!-- Generator: GNU source-highlight 2.9
|
|
by Lorenzo Bettini
|
|
http://www.lorenzobettini.it
|
|
http://www.gnu.org/software/src-highlite -->
|
|
<pre><tt>ActionController<span style="color: #990000">::</span>Base<span style="color: #990000">.</span>cache_store <span style="color: #990000">=</span> <span style="color: #990000">:</span>file_store<span style="color: #990000">,</span> <span style="color: #FF0000">"/path/to/cache/directory"</span>
|
|
</tt></pre></div></div>
|
|
<div class="para"><p>3) DRb store: Cached data is stored in a separate shared DRb process that all
|
|
servers communicate with. This works for all environments and
|
|
only keeps one cache around for all processes, but requires
|
|
that you run and manage a separate DRb process.</p></div>
|
|
<div class="listingblock">
|
|
<div class="content"><!-- Generator: GNU source-highlight 2.9
|
|
by Lorenzo Bettini
|
|
http://www.lorenzobettini.it
|
|
http://www.gnu.org/software/src-highlite -->
|
|
<pre><tt>ActionController<span style="color: #990000">::</span>Base<span style="color: #990000">.</span>cache_store <span style="color: #990000">=</span> <span style="color: #990000">:</span>drb_store<span style="color: #990000">,</span> <span style="color: #FF0000">"druby://localhost:9192"</span>
|
|
</tt></pre></div></div>
|
|
<div class="para"><p>4) MemCached store: Works like DRbStore, but uses Danga's MemCache instead.
|
|
Requires the ruby-memcache library:
|
|
gem install ruby-memcache.</p></div>
|
|
<div class="listingblock">
|
|
<div class="content"><!-- Generator: GNU source-highlight 2.9
|
|
by Lorenzo Bettini
|
|
http://www.lorenzobettini.it
|
|
http://www.gnu.org/software/src-highlite -->
|
|
<pre><tt>ActionController<span style="color: #990000">::</span>Base<span style="color: #990000">.</span>cache_store <span style="color: #990000">=</span> <span style="color: #990000">:</span>mem_cache_store<span style="color: #990000">,</span> <span style="color: #FF0000">"localhost"</span>
|
|
</tt></pre></div></div>
|
|
<div class="para"><p>5) Custom store: You can define your own cache store (new in Rails 2.1)</p></div>
|
|
<div class="listingblock">
|
|
<div class="content"><!-- Generator: GNU source-highlight 2.9
|
|
by Lorenzo Bettini
|
|
http://www.lorenzobettini.it
|
|
http://www.gnu.org/software/src-highlite -->
|
|
<pre><tt>ActionController<span style="color: #990000">::</span>Base<span style="color: #990000">.</span>cache_store <span style="color: #990000">=</span> MyOwnStore<span style="color: #990000">.</span>new<span style="color: #990000">(</span><span style="color: #FF0000">"parameter"</span><span style="color: #990000">)</span>
|
|
</tt></pre></div></div>
|
|
</div>
|
|
<h2 id="_advanced_caching">2. Advanced Caching</h2>
|
|
<div class="sectionbody">
|
|
<div class="para"><p>Along with the built-in mechanisms outlined above, a number of excellent
|
|
plugins exist to help with finer grained control over caching. These include
|
|
Chris Wanstrath's excellent cache_fu plugin (more info here:
|
|
<a href="http://errtheblog.com/posts/57-kickin-ass-w-cachefu">http://errtheblog.com/posts/57-kickin-ass-w-cachefu</a>) and Evan Weaver's
|
|
interlock plugin (more info here:
|
|
<a href="http://blog.evanweaver.com/articles/2007/12/13/better-rails-caching/">http://blog.evanweaver.com/articles/2007/12/13/better-rails-caching/</a>). Both
|
|
of these plugins play nice with memcached and are a must-see for anyone
|
|
seriously considering optimizing their caching needs.</p></div>
|
|
</div>
|
|
|
|
</div>
|
|
</div>
|
|
</body>
|
|
</html>
|