#172 Touch and Cache
- Download:
- source codeProject Files in Zip (92.8 KB)
- mp4Full Size H.264 Video (12.3 MB)
- m4vSmaller H.264 Video (7.72 MB)
- webmFull Size VP8 Video (18.7 MB)
- ogvFull Size Theora Video (16.4 MB)
Rails近期升级到了2.3.3版。尽管这次只是一次较小的升级,主要是对之前版本的一些错误修正(bug fixes), 这个新版本还是给我们提供了一些新的特性(features)。Touch就是其中的一个。我们将在这集为大家展现如何使用touch
去改进你的应用程序中的缓存。
如果你还没有升级rails到2.3.3,你可以在命令行运行:
sudo gem update rails
升级到新版本. 然后你可以在任何你想升级的应用程序里面修改/config/environment.rb
文件的最上面一行:
# Specifies gem version of Rails to use when vendor/rails is not present RAILS_GEM_VERSION = '2.3.3' unless defined? RAILS_GEM_VERSION
如果你准备升级一个应用程序,请确保该应用程序有个优秀的测试套件(test suite)。 这样你可以保证该升级不会对破坏你原有的应用程序。
与片段缓存(Fragment Caching)一起使用touch
以下显示的是一个博客应用程序的article页面。这个页面的流量很大,所以我们想要改进他的性能。
我们可以添加片段缓存(Fragment Caching)去缩短页面的相应时间。这个可能不是最理想的解决方案,但它却能让我们快速的解决问题。我们先对这个页面应用片段缓存(Fragment Caching)看看回是怎么样。
在开发模式下,缓存(caching)是默认被禁用的。应此我们先要打开缓存。我们需要修改/config/environments/default.rb
文件:
config.action_controller.perform_caching = true
另一种方式是创建一个临时环境(staging environment). 如果你想了解更多关于如何创建临时环境(staging envrionment),你可以查看第72集. 如果你创建了一个临时环境(staging environment),你就不需要在你的开发环境里面激活或禁用缓存(caching)。
片段缓存(fragment caching)将会添加在article的show
视图内。视图代码如下:
<% title @article.name %> <p class="author"><em>from <%=h @article.author_name %></em></p> <%= simple_format @article.content %> <p><%= link_to "Back to Articles", articles_path %></p> <% unless @article.comments.empty? %> <h2><%= pluralize(@article.comments.size, 'comment') %></h2> <div id="comments"> <% for comment in @article.comments %> <div id="comment"> <strong><%= link_to_unless comment.site_url.blank?, h(comment.author_name), h(comment.site_url) %></strong> <em>on <%= comment.created_at.strftime('%b %d, %Y at %H:%M') %></em> <%= simple_format comment.content %> </div> <% end %> </div> <% end %> <h3>Add your comment:</h3> <%= render :partial => 'comments/form' %>
我们调用cache
方法并把要缓存的片段包含在缓存块内:
<% title @article.name %> <% cache @article do %> <p class="author"><em>from <%=h @article.author_name %></em></p> <!-- Rest of code omitted --> <% end %> <h3>Add your comment:</h3> <%= render :partial => 'comments/form' %>
cache
方法接受一个可选参数。这个参数被用作缓存的key(默认情况下,页面的URL会被作为缓存的key)。如果我们把模型(model)当作参数,那么模型的cache_key
属性将被作为这个key。这就是说,当article更新的时候这个缓存片段就会过期。我们可以在控制台(console)里面演示:
>> a = Article.first => #<Article id: 1, name: "The Piano, a Marvellous Instrument", content: "The piano is a musical instrument played by means o...", author_name: "Billy Belmer", created_at: "2009-06-14 19:39:40", updated_at: "2009-07-29 19:14:17"> >> a.cache_key => "articles/1-20090729191417"
cache_key
由模型(model)名,模型的id
和updated_at
属性组成。key的最后一段非常有用,因为这一段组成部分,这个key每次都会应为模型的更新而改变。这样每次模型的任意属性有更改,这个缓存片段都会过期。
我们通过刷新2次我们的article页面来演示缓存。在development.log里面我们可以看到:
Processing ArticlesController#show (for 127.0.0.1 at 2009-07-30 20:22:30) [GET] Parameters: {"id"=>"1"} Article Load (0.2ms) SELECT * FROM "articles" WHERE ("articles"."id" = 1) Rendering /Users/eifion/rails/apps_for_asciicasts/ep172/app/views/articles/show.html.erb Cached fragment hit: views/articles/1-20090729225258 (0.0ms) SQL (0.2ms) SELECT count(*) AS count_all FROM "comments" WHERE ("comments".article_id = 1) CACHE (0.0ms) SELECT count(*) AS count_all FROM "comments" WHERE ("comments".article_id = 1) Comment Load (0.3ms) SELECT * FROM "comments" WHERE ("comments".article_id = 1) Cached fragment miss: views/articles/1-20090729225258 (0.0ms) Processing ArticlesController#show (for 127.0.0.1 at 2009-07-30 20:22:45) [GET] Parameters: {"id"=>"1"} Article Load (0.2ms) SELECT * FROM "articles" WHERE ("articles"."id" = 1) Rendering /Users/eifion/rails/apps_for_asciicasts/ep172/app/views/articles/show.html.erb Cached fragment hit: views/articles/1-20090729225258 (0.0ms)
第一次加载页面的时候,因为缓存内没有该key对应的缓存片段,所以找不到对应的缓存片段(cached fragment)。这时数据就会从数据库里面取出来,并创建缓存。第二次加载页面的时候对应该key的缓存片段被找到,这时我们就不需要从数据库里面读取数据。
如果我们编辑article,比如修改标题,这个缓存片段会自动失效并且页面被更新。这时因为当我们更新article的时候,模型(model)的updated_at
属性也被修改,模型的cache_key
也应此而更新。
使用Touch
我们现在所有的改动都应该能在早期版本的rails上面工作。那么touch
是怎么工作的呢?我们将从touch
如何在控制台(console) 下面工作开始讲起:
我们首先取得第一个article并找到它的updated_at
属性。
>> a = Article.first => #<Article id: 1, name: "The Piano, a Beautiful Instrument.", content: "The piano is a musical instrument played by means o...", author_name: "Billy Belmer", created_at: "2009-06-14 19:39:40", updated_at: "2009-07-29 20:27:34"> >> a.updated_at => Wed, 29 Jul 2009 22:27:34 UTC +00:00
如果我们对article调用touch
方法,那么它的updated_at
属性也会被修改。
>> a.touch => true >> a.updated_at => Wed, 29 Jul 2009 22:27:53 UTC +00:00
这就是touch
。当model调用touch方法,model就会修改它的updated_at
属性值为现在的时间。这看起来不像个特别有用的方法,但当用在associations时touch方法就会显示出它的价值。
在我们的应用程序里一个Article
可能有很多Comments
。如果我们使用article页面的表单对article添加一条comment,这条comment将不会作为article页面的一部分被显示。这是因为article已经被缓存了,article页面只会显示缓存里面的comments。当一条comment被添加时article的时间戳未被修改,所以缓存片段不会过期。
要想实现当添加或修改comment时article页面显示新的comment,我们仅仅需要对comment
模型(model)做一点点修改:
class Comment < ActiveRecord::Base belongs_to :article, :touch => true end
给belongs_to
关系添加 :touch => true
意味着当创建,更新或者删除一条comment的时候,该comment属于(belongs_to)的article被touched。现在我们添加一条comment,缓存会失效并且页面会更新而且显示刚添加的comment。
这项技术不仅限在片段缓存(fragment caching)上使用。touch也能很好的和Memcached工作,当新缓存创建时Memcached会自动清除旧缓存。不需要使用sweepers更不需要去写一堆sweepers需要的多余代码。