04 Jun 2015
Rails中的常用cache
ETag
ETag是浏览器和服务器验证页面是否修改的工具。
一般流程是: 浏览器发起请求,rails渲染界面,生成Etag,并放入headers[‘ETag’],浏览器接到header并把ETag值存下,下次请求相同页面url时会在请求header中把之前存下来的值放入头部headers[‘If-None-Match’]中,Rails渲染页面,生成ETag比对浏览器传入的headers[‘If-None-Match’]是否与新生成的ETag相同,如果相同直接返回状态码 304 Not Modified。
- 默认的ETag
headers['ETag'] = Digest::MD5.hexdigest(body)
- 自定义刷新ETag
class ItemsController < ApplicationController def show @item = Item.find(params[:id]) fresh_when(@item) end end
以上fresh_when方法相当于设置ETag如下
headers['ETag'] = Digest::MD5.hexdigest(@item.cache_key) # => item/2-2014224150000 # cach_key 为 <model name>/<id>-<updated_at>
- 当ETag依赖多个因素时
class ItemsController < ApplicationController def show @item = Item.find(params[:id]) fresh_when([@item, current_user.id, current_user.age]) end def edit @item = Item.find(params[:id]) fresh_when([@item, current_user.id, current_user.age]) end def most_recent @item = Item.find(params[:id]) fresh_when([@item, current_user.id, current_user.age]) end end
可以写成如下
class ItemsController < ApplicationController etag { current_user.id } etag { current_user.age } def show @item = Item.find(params[:id]) fresh_when(@item) end def edit @item = Item.find(params[:id]) fresh_when(@item) end def most_recent @item = Item.find(params[:id]) fresh_when(@item) end end
Memcached && Dalli
使用memecached作为rails缓存一般使用dalli为client。
# Gemfile
gem 'dalli'
# config/environments/production.rb
config.action_controller.perform_caching = true
config.cache_store = :dalli_store, 'mem-server:11211', 'mem-server:11211', {:expires_in => 30.day, :compress => true }
Rails.cache.read('key')
Rails.cache.write('key', value)
Rails.cache.fetch('key') { value }
Digest Cache
片段缓存用于页面级的缓存很简单方便。
# app/models/comment.rb
class Comment < ApplicationRecord
belongs_to :document
end
<!-- app/views/projects/show.html.erb -->
<%= render @project.documents %>
<!-- app/views/documents/_document.html.erb -->
<article>
<h3><%= document.title %></h3>
<ul>
<%= render document.comments %>
</ul>
<%= link_to 'View details', document %>
</article>
<!-- app/views/comments/_comment.html.erb -->
<li><%= comment %></li>
为comment添加cache
<!-- app/views/comments/_comment.html.erb -->
<% cache comment do %>
<li><%= comment %></li>
<% end %>
缓存的key默认是comment.cache_key
comment.cache_key
# => comment/5-2014224150000
# <model name>/<id>-<updated_at>
为document添加cache
<!-- app/views/documents/_document.html.erb -->
<% cache document do %>
<article>
<h3><%= document.title %></h3>
<ul>
<%= render document.comments %>
</ul>
<%= link_to 'View details', document %>
</article>
<!-- app/views/comments/_comment.html.erb -->
<li><%= comment %></li>
<% end %>
这样在document下新增或者删除comment,时需要刷新document的cache_key
# app/models/comment.rb
class Comment < ApplicationRecord
belongs_to :document, touch: true
end
手动添加版本号
<!-- app/views/documents/_document.html.erb -->
<% cache [document, 'v2'] do %>
<article>
<h3><%= document.title %></h3>
<ul>
<%= render document.comments %>
</ul>
<%= link_to 'View details', document %>
</article>
<!-- app/views/comments/_comment.html.erb -->
<li><%= comment %></li>
<% end %>
Rails.cache
缓存购物车总价
class ShoppingCart < ApplicationRecord
has_many :items
def total_price
Rails.cache.fetch "#{cache_key/total_price}", expires_in: 6.hours do
# loop item sum price
end
end
end
class Item < ApplicationRecord
belongs_to :shopping_cart, touch: true
def price
# cal price and return
end
end
Til next time,
Jason Heylon
at 12:00