diff options
Diffstat (limited to 'railties/doc/guides/caching/caching_with_rails.txt')
-rw-r--r-- | railties/doc/guides/caching/caching_with_rails.txt | 361 |
1 files changed, 0 insertions, 361 deletions
diff --git a/railties/doc/guides/caching/caching_with_rails.txt b/railties/doc/guides/caching/caching_with_rails.txt deleted file mode 100644 index d5b8b03669..0000000000 --- a/railties/doc/guides/caching/caching_with_rails.txt +++ /dev/null @@ -1,361 +0,0 @@ -Caching with Rails: An overview -=============================== - -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. - -== Basic Caching - -This is an introduction to the three types of caching techniques that Rails -provides by default without the use of any third party plugins. - -To get started make sure Base.perform_caching is set to true for your -environment. - -[source, ruby] ------------------------------------------------------ -Base.perform_caching = true ------------------------------------------------------ - -=== Page Caching - -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. - -So, how do you enable this super-fast cache behavior? Simple, let's say you -have a controller called ProductController and a 'list' action that lists all -the products - -[source, ruby] ------------------------------------------------------ -class ProductController < ActionController - - cache_page :list - - def list; end - -end ------------------------------------------------------ - -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. - -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 - -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 - -In order to expire this page when a new product is added we could extend our -example controler like this: - -[source, ruby] ------------------------------------------------------ -class ProductController < ActionController - - cache_page :list - - def list; end - - def create - expire_page :action => :list - end - -end ------------------------------------------------------ - -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. - -[More: caching paginated results? more examples? Walk-through of page caching?] - -=== Action Caching - -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. - -Clearing the cache works in the exact same way as with Page Caching. - -Let's say you only wanted authenticated users to edit or create a Product -object, but still cache those pages: - -[source, ruby] ------------------------------------------------------ -class ProductController < ActionController - - before_filter :authenticate, :only => [ :edit, :create ] - cache_page :list - caches_action :edit - - def list; end - - def create - expire_page :action => :list - expire_action :action => :edit - end - - def edit; end - -end ------------------------------------------------------ - -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. - - -[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?] - -=== Fragment Caching - -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. - -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. - -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: - -[source, ruby] ------------------------------------------------------ -<% Order.find_recent.each do |o| %> - <%= o.buyer.name %> bought <% o.product.name %> -<% end %> - -<% cache do %> - All available products: - <% Product.find(:all).each do |p| %> - <%= link_to p.name, product_url(p) %> - <% end %> -<% end %> ------------------------------------------------------ - -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: - -[source, ruby] ------------------------------------------------------ -<% cache(:action => 'recent', :action_suffix => 'all_products') do %> - All available products: ------------------------------------------------------ - -and you can expire it using the expire_fragment method, like so: - -[source, ruby] ------------------------------------------------------ -expire_fragment(:controller => 'producst', :action => 'recent', :action_suffix => 'all_products) ------------------------------------------------------ - -[More: more examples? description of fragment keys and expiration, etc? pagination?] - -=== Sweepers - -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. - -Continuing with our Product controller example, we could rewrite it with a -sweeper such as the following: - -[source, ruby] ------------------------------------------------------ -class StoreSweeper < ActionController::Caching::Sweeper - observe Product # This sweeper is going to keep an eye on the Post model - - # If our sweeper detects that a Post was created call this - def after_create(product) - expire_cache_for(product) - end - - # If our sweeper detects that a Post was updated call this - def after_update(product) - expire_cache_for(product) - end - - # If our sweeper detects that a Post was deleted call this - def after_destroy(product) - expire_cache_for(product) - end - - private - def expire_cache_for(record) - # Expire the list page now that we added a new product - expire_page(:controller => '#{record}', :action => 'list') - - # Expire a fragment - expire_fragment(:controller => '#{record}', :action => 'recent', :action_suffix => 'all_products') - end -end ------------------------------------------------------ - -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: - -[source, ruby] ------------------------------------------------------ -class ProductController < ActionController - - before_filter :authenticate, :only => [ :edit, :create ] - cache_page :list - caches_action :edit - cache_sweeper :store_sweeper, :only => [ :create ] - - def list; end - - def create - expire_page :action => :list - expire_action :action => :edit - end - - def edit; end - -end ------------------------------------------------------ - -[More: more examples? better sweepers?] - -=== SQL Caching - -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. - -For example: - -[source, ruby] ------------------------------------------------------ -class ProductController < ActionController - - before_filter :authenticate, :only => [ :edit, :create ] - cache_page :list - caches_action :edit - cache_sweeper :store_sweeper, :only => [ :create ] - - def list - # Run a find query - Product.find(:all) - - ... - - # Run the same query again - Product.find(:all) - end - - def create - expire_page :action => :list - expire_action :action => :edit - end - - def edit; end - -end ------------------------------------------------------ - -In the 'list' 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. - -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. - -=== Cache stores - -Rails provides different stores for the cached data for action and fragment -caches. Page caches are always stored on disk. - -The cache stores provided include: - -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. - -[source, ruby] ------------------------------------------------------ -ActionController::Base.cache_store = :memory_store ------------------------------------------------------ - -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. - - -[source, ruby] ------------------------------------------------------ -ActionController::Base.cache_store = :file_store, "/path/to/cache/directory" ------------------------------------------------------ - -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. - -[source, ruby] ------------------------------------------------------ -ActionController::Base.cache_store = :drb_store, "druby://localhost:9192" ------------------------------------------------------ - -4) MemCached store: Works like DRbStore, but uses Danga's MemCache instead. - Requires the ruby-memcache library: - gem install ruby-memcache. - -[source, ruby] ------------------------------------------------------ -ActionController::Base.cache_store = :mem_cache_store, "localhost" ------------------------------------------------------ - -5) Custom store: You can define your own cache store (new in Rails 2.1) - -[source, ruby] ------------------------------------------------------ -ActionController::Base.cache_store = MyOwnStore.new("parameter") ------------------------------------------------------ - -== Advanced Caching - -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: -http://errtheblog.com/posts/57-kickin-ass-w-cachefu) and Evan Weaver's -interlock plugin (more info here: -http://blog.evanweaver.com/articles/2007/12/13/better-rails-caching/). Both -of these plugins play nice with memcached and are a must-see for anyone -seriously considering optimizing their caching needs. |