README in interlock-1.0 vs README in interlock-1.1

- old
+ new

@@ -1,26 +1,29 @@ Interlock -An optimal-efficiency caching plugin for Rails. +A Rails plugin for maintainable and high-efficiency caching. == License Copyright 2007 Cloudburst, LLC. Licensed under the AFL 3; see the included LICENSE file. Portions copyright 2006 Chris Wanstrath and used with permission. The public certificate for the gem is at http://rubyforge.org/frs/download.php/25331/evan_weaver-original-public_cert.pem. == Requirements -* Memcached (http://www.danga.com/memcached) +* memcached (http://www.danga.com/memcached) * memcache-client gem +* Rails 1.2.6 +Note that Rails 2.0.2 is required for caching <tt>content_for</tt> or nesting <tt>view_cache</tt> blocks. + == What it does Interlock makes your view fragments and associated controller blocks march along together. If a fragment is fresh, the controller behavior won't run. This eliminates duplicate effort from your request cycle. Your controller blocks run so infrequently that you can use regular ActiveRecord finders and not worry about object caching at all. -Interlock automatically tracks invalidation dependencies based on the model lifecyle, and supports arbitrary levels of scoping per-block. +Interlock automatically tracks invalidation dependencies based on the model lifecyle, and supports arbitrary levels of scoping per-block. It also caches <tt>content_for</tt> calls, unlike regular Rails. == Installation First, compile and install memcached itself. Get a memcached server running. @@ -45,11 +48,11 @@ Now you're ready to go. == Usage -Interlock provides two similar caching methods: <tt>behavior_cache</tt> for controllers and <tt>view_cache</tt> for views. The both accept an optional list or hash of model dependencies, and an optional <tt>:tag</tt> keypair. <tt>view_cache</tt> also accepts a <tt>ttl</tt>. +Interlock provides two similar caching methods: <tt>behavior_cache</tt> for controllers and <tt>view_cache</tt> for views. They both accept an optional list or hash of model dependencies, and an optional <tt>:tag</tt> keypair. <tt>view_cache</tt> also accepts a <tt>:ttl</tt> keypair. The simplest usage doesn't require any parameters. In the controller: class ItemsController < ActionController::Base @@ -59,11 +62,11 @@ end end end -Now, in the view, wrap the largest section of ERB you can find that uses data from <tt>@items</tt> (but not from any other instance variables) in a <tt>view_cache</tt> block. +Now, in the view, wrap the largest section of ERB you can find that uses data from <tt>@items</tt> in a <tt>view_cache</tt> block. No other part of the view can refer to <tt>@items</tt>, because <tt>@items</tt> won't get set unless the cache is stale. <% @title = "My Sweet Items" %> <% view_cache do %> <% @items.each do |item| %> @@ -75,79 +78,14 @@ This automatically registers a caching dependency on Item for <tt>slow_action</tt>. The controller block won't run if the <tt>slow_action</tt> view fragment is fresh, and the view fragment will only get invalidated when an Item is changed. You can use multiple instance variables in one block, of course. Just make sure the <tt>behavior_cache</tt> provides whatever the <tt>view_cache</tt> uses. -== Declaring dependencies +See ActionController::Base and ActionView::Helpers::CacheHelper for more details. -You can declare non-default invalidation dependencies by passing models to <tt>behavior_cache</tt> (you can also pass them to <tt>view_cache</tt>, but you should only do that if you are caching a fragment without an associated behavior block in the controller). +== Notes -<b>No dependencies (cache never invalidates):</b> - behavior_cache nil do - end - -<b>Invalidate on any Media change:</b> - behavior_cache Media do - end - -<b>Invalidate on any Media or Item change:</b> - behavior_cache Media, Item do - end - -<b>Invalidate on Item changes if the Item <tt>id</tt> matches the current <tt>params[:id]</tt> value:</b> - behavior_cache Item => :id do - end - -You do not have to pass the same dependencies to <tt>behavior_cache</tt> and <tt>view_cache</tt> even for the same action. The set union of both dependency lists will be used. - -== Narrowing scope and caching multiple blocks - -Sometimes you need to cache multiple blocks in a controller, or otherwise get a more fine-grained scope. Interlock provides the <tt>:tag</tt> key for this purpose. <tt>:tag</tt> accepts either an array of symbols, which are mapped to <tt>params</tt> values, or an arbitrary object, which is converted to a string identifier. <b>Your corresponding behavior caches and view caches must have identical <tt>:tag</tt> values for the interlocking to take effect.</b> - -Note that <tt>:tag</tt> can be used to scope caches. You can simultaneously cache different versions of the same block, differentiating based on params or other logic. This is great for caching per-user, for example: - - def profile - @user = current_user - behavior_cache :tag => @user do - @items = Item.find(:all, :conditions => "be slow") - end - end - -In the view, use the same <tt>:tag</tt> value (<tt>@user</tt>). Note that <tt>@user</tt> must be set outside of the behavior block in the controller, because its contents are used to decide whether to run the block in the first place. - -This way each user will see only their own cache. Pretty neat. - -== Broadening scope - -Sometimes the default scope (<tt>controller</tt>, <tt>action</tt>, <tt>params[:id]</tt>) is too narrow. For example, you might share a partial across actions, and set up its data via a filter. By default, Interlock will cache a separate version of it for each action. To avoid this, you can use the <tt>:ignore</tt> key, which lets you list parts of the default scope to ignore: - - before_filter :recent - - private - - def recent - behavior_cache :ignore => :action do - @recent = Item.find(:all, :limit => 5, :order => 'updated_at DESC') - end - end - -Valid values for <tt>:ignore</tt> are <tt>:controller</tt>, <tt>:action</tt>, <tt>:id</tt>, and <tt>:all</tt>. You can pass an array of multiple values. <b>Just like with <tt>:tag</tt>, your corresponding behavior caches and view caches must have identical <tt>:ignore</tt> values.</b> Note that cache blocks with <tt>:ignore</tt> values still obey the regular invalidation rules. - -A good way to get started is to just use the default scope. Then <tt>grep</tt> in the production log for <tt>interlock</tt> and see what keys are being set and read. If you see lots of different keys go by for data that you know is the same, then set some <tt>:ignore</tt> values. - -== View-only caching - -It's fine to use a <tt>view_cache</tt> block without a <tt>behavior_cache</tt> block. For example, to mimic regular fragment cache behavior, but take advantage of Memcached's <tt>:ttl</tt> support, call: - - <% view_cache nil, :ignore => :all, :tag => 'sidebar', :ttl => 5.minutes %> - <h1>On the side</h1> - <% end %> - -Remember that <tt>nil</tt> disables invalidation rules. This is a nice trick for keeping your caching strategy unified. - -== Gotchas - You will not see any actual cache reuse in development mode unless you set <tt>config.action_controller.perform_caching = true</tt> in <tt>config/environments/development.rb</tt>. <b>If you have custom <tt>render</tt> calls in the controller, they must be outside the <tt>behavior_cache</tt> blocks.</b> No exceptions. For example: def profile @@ -159,10 +97,15 @@ You can write custom invalidation rules if you really want to, but try hard to avoid it; it has a significant cost in long-term maintainability. Also, Interlock obeys the <tt>ENV['RAILS_ASSET_ID']</tt> setting, so if you need to blanket-invalidate all your caches, just change <tt>RAILS_ASSET_ID</tt> (for example, you could have it increment on every deploy). +== Further resources + +* http://blog.evanweaver.com/articles/2007/12/13/better-rails-caching/ +* http://www.socialtext.net/memcached/index.cgi?faq + == Reporting problems -* http://rubyforge.org/forum/forum.php?forum_id=18926 +* http://rubyforge.org/forum/forum.php?forum_id=19835 Patches and contributions are very welcome. Please note that contributors are required to assign copyright for their additions to Cloudburst, LLC.