ProblemYou want to improve application performance by cashing entire pages that are static or that containing changes that don't need to be shown in real time. SolutionYou can instruct Rails to cache entire pages using the caches_page class method of Action Controller. You call caches_page in your controllers and pass it a list of actions whose rendered output is to be cached; for example: app/controllers/articles_controller.rb: class ArticlesController < ApplicationController caches_page :show def show @article = Article.find(params[:id]) end # ... end Now, start your server in production mode, visit the site, and invoke the show action of the Articles Controller in a browser with: http://tupleshop.com/articles/show/2 In addition to displaying the second article (id = 2), page caching writes the show action's output to a cache directory as a static HTML file. The following is the HTML file that's created under your application's public directory: public/articles/show/2.html: <html> <head> <title>Articles: show</title> <link href="/stylesheets/scaffold.css?1156567340" media="screen" rel="Stylesheet" type="text/css" /> </head> <body> <p style="color: green"></p> <p> <b>Title:</b> Article Number Two </p> <p> <b>Body:</b> This would be the body of the second article... </p> <a href="/articles/edit/2">Edit</a> | <a href="/articles/list">Back</a> </body> </html> The file is the result of what was rendered by the show action along with the following articles.rhtml layout file: app/views/layouts/articles.rhtml: <html> <head> <title>Articles: <%= controller.action_name %></title> <%= stylesheet_link_tag 'scaffold' %> </head> <body> <p style="color: green"><%= flash[:notice] %></p> <%= yield %> </body> </html> DiscussionUsing caches_page :show in your controller class definition instructs Rails to cache all pages rendered by the show action by writing the output to disk the first time a specific URL is requested. The files in the cache directory are named after the components of the requested URL. The cache directory in the solution is called articles (named after the controller) and contains a subdirectory named show, (named after the action). Each file in the cache is named using the id from the request and a .html file extension. On subsequent requests, these cached HTML pages are served straight from disk by your web server, and Rails is bypassed entirely. This produces tremendous performance gains. As the solution demonstrates, enabling Rails page caching is relatively simple. What is more complex is getting your web server to recognize that there are static HTML pages it should render instead of invoking the Rails framework. The following VirtualHost definition demonstrates how this can be set up in Apache, using the mod_rewrite module: apache2.2.3/conf/httpd.conf: <Proxy balancer://blogcluster> # cluster member(s) BalancerMember http://127.0.0.1:7171 </Proxy> <VirtualHost *:81> ServerName blog DocumentRoot /var/www/cache/public <Directory /var/www/cache/public> Options Indexes FollowSymLinks MultiViews AllowOverride None Order allow,deny allow from all </Directory> RewriteEngine On RewriteRule ^$ index.html [QSA] RewriteRule ^([^.]+)$ $1.html [QSA] RewriteCond %{DOCUMENT_ROOT}/%{REQUEST_FILENAME} !-f RewriteRule ^/(.*)$ balancer://blogcluster%{REQUEST_URI} [P,QSA,L] </VirtualHost> After turning the rewrite engine on, two rewrite rules are defined. These rules translate both requests for the application root and requests in the typical Rails format (controller/action/ID) into requests for HTML files that may exist in a cache directory. The rewrite condition builds a system file path out of the request string and checks whether the HTML file actually exists. If an HTML file corresponds to the incoming request, it's served directly by the web server, bypassing Rails. If no HTML file is found in the cache (i.e., the rewrite condition passes), a rewrite rule passes the request on to mod_proxy_balancer, which has Rails handle the page via a Mongrel process. It may seem like things could get complicated with Rails creating subdirectories in your application's public directory that you may not have anticipated, possibly conflicting with a directory that already exists. This situation is easily avoided by changing the default base directory for the cache store. To do this, add the following line to your config/environment.rb: config.action_controller.page_cache_directory = \ RAILS_ROOT+"/public/cache/" With the cache directory changed, you'll have to modify the rewrite rules accordingly. Replace them with the following: RewriteRule ^$ cache/index.html [QSA] RewriteRule ^([^.]+)$ cache/$1.html [QSA] mod_rewrite is a powerful and complex module. If you get into trouble and need to see more of what's happening behind the scenes, enable debugging by adding the following to your virtual host definition: RewriteLog logs/myapp_rewrite_log RewriteLogLevel 9 See the Apache documentation for more information. See Also
|