キャッシュ機能

  • Railsのキャッシュは、以下の3種類があるんだねー
    • ページキャッシュ(caches_pageメソッド)は、アクションを丸ごとキャッシュ
    • アクションキャッシュ(caches_actionメソッド)は、フィルタだけは実行して、ページ全体をキャッシュ
    • フラグメントキャッシュ(chcheヘルパー)は、ページの断片(フラグメント)単位でキャッシュ
  • まずは、事前設定として、config/environments/development.rbの、以下の2か所のキャッシュ設定を有効にする
    #  config.cache_classes = false
      config.cache_classes = true
    ---- 中略 ----------------------------
    #  config.action_controller.perform_caching = false
      config.action_controller.perform_caching = true
    

ページキャッシュ

  • ページキャッシュ(caches_pageメソッド)は、コントローラに定義ね
    • こんな感じで、app/controllers/cache_controller.rbに書くと、キャッシュできる
      class CacheController < ApplicationController
       caches_page :p_cache
       def p_cache
         render :text => Time.now
       end
      end
      
    • これで、http://localhost:3000/cache/p_cache にアクセスすると、一回表示された時刻が、リロードしても変わらない、と。
      • んー、変わっちゃうなー。キャッシュ効いてない…。なんじゃろ?
      • あ、判った。以下の設定もいるんだ。この辺は、3.0と3.1の差かなー。
        #  config.action_controller.perform_caching = false
          config.action_controller.perform_caching = true
        
      • うーん、これやっちゃうと、アクションもキャッシュされちゃうんだよなー。いちいち再起動って面倒だし、なんでこれいるんだろ?
  • で、キャッシュされたページは、public/cache/ 以下にURLに準じて保存されるんだねー。
    • だから、簡単にキャッシュの削除をする場合は、ここのファイルを削除する、と。
    • ちなみに、ページキャッシュではクエリ(URLの?以降ね)は認識しないので、GETを使う時は注意ね!
  • お!キャッシュ時の判定も書けるんだ!
    • こんな感じで書けば、XMLの場合だけキャッシュされるのねー
       caches_page :p_cache_xml_only, :if => Proc.new { |c| c.request.format.xml? }
       def p_cache_xml_only
         respond_to do |format|
           format.html { render :text => Time.now }
           format.xml { render :text => "<data>"  + Time.now.to_s + "</data>" }
         end
       end
      
    • URL的には、HTML(http://localhost:3000/cache/p_cache_xml_only/1.html)だとキャッシュされなくて、xml(http://localhost:3000/cache/p_cache_xml_only/1.xml)だとキャッシュされる感じね。
    • ま、当然:ifだけじゃなくて、:unlessもOKってことで。
    • んー。ログを見ると、キャッシュを参照した時、下みたいに「miss」って出るけど、キャッシュされるんだよねー。なんか変?
      cache: [GET /cache/p_cache_xml_only/1.xml] miss
      

アクションキャッシュ

  • アクションキャッシュは、ページキャッシュとほとんど一緒だけど、フィルタが実行されるトコだけ違うんだねー
    • こんな感じでapp/controllers/cache_controller.rbに書くと、basic認証が2回目以降、p_cacheは動かないけど、a_cacheは動くんだね。
       before_filter :auth,:only => ['p_cache','a_cache'] # p_cacheとa_cacheにauthフィルタを設定
       caches_page :p_cache
       caches_action :a_cache
       ---- 中略 ------------
       def p_cache
         render :text => Time.now
       end
       def a_cache
         render :text => Time.now
       end
       private
       def auth
         ---- BASIC認証するトコ -----
       end
      
  • あ、アクションキャッシュは、保存場所が[tmp/cache]に変わるんだ!へー。

フラグメントキャッシュ

  • フラグメントキャッシュは、部分的にキャッシュする場合に使うんだねー。
    • こんな感じで、view側(views/cache/f_cache.html.erb)に書いて、/cache/f_cacheにアクセスすれば、一部だけキャッシュされる、と。
      現在時刻(キャッシュなし):<%= Time.now %><br />
      <% cache(:suffix => 'footer') do %>
      現在時刻(キャッシュあり):<%= Time.now %><br />
      <% end %>
      
      • 「:suffix => 'footer'」のトコで、キャッシュキーを指定してるんだが、これはURLと無関係だから注意が必要らしい。
      • 動くことは動くんだが、development環境のせいか、何回かアクセスすると、Ruby自体が落ちる…。まあ、いっか…。
      • どーも、JavaScript系が悪さをしてるっぽいなー。エラーも起きずにいきなりRubyが落ちるんでなんとも言えないけど…。
  • まあ、この辺の「部分的に」キャッシュするって、「判定」をどっかしらで書き始めると、いろいろと面倒なんだけど、書けることは書けるみたい
    • アクション側でキャッシュの有無を判定する場合は、fragment_exist?メソッド(キャッシュキーは必須)が使えるよー
    • 当然、上記の例みたいにView側で書くこともできるけど、基本は部分テンプレート化して、ロジックはViewに書かないが吉。

キャッシュクリア他

  • キャッシュの破棄は、expire_***で!
    • 要するに、データ更新とかのタイミングで、キャッシュを削除しないとまずいからね!
    • こんな感じで書くのかな?
      expire_action :action => 'index'
      
  • とはいえ、いちいちexpireで書いてると漏れが出てくるから、スイーパーでキャッシュ処理をまとめられるよ!
    • やり方は、スイーパー用のモデルを作成して、コントローラに登録するだけ!
      • 以下の例だと、bookモデル用のスイーパーね!
      • やってみたら、どーにもアクションキャッシュだとRubyが落ちちゃうから、とりあえずページキャッシュにしてみた
    • まずはスイーパー用モデルだけど、こんな感じで[app/models/book_sweeper.rb]を、自分で作る感じ
      class BookSweeper < ActionController::Caching::Sweeper
       observe Book # ここでobserveメソッド登録。
       def after_create(book)
         gc_cache(book)
       end
       def after_update(book)
         gc_cache(book)
       end
       def after_destroy(book)
         gc_cache(book)
       end
       private
       def gc_cache(book)
         expire_page :controller => 'books', :action => 'index'
         expire_page :controller => 'books', :action => 'show', :id => book.id
       end
      end
      
      • このモデルは、ActionController::Caching::Sweeper を継承するんだねー。
      • で、この例だと、create/update/destroy時に、indexとshow/:idのキャッシュを削除って、感じね
      • へー。ここでコールバックで使ってたオブザーバが出てくるんだねー。納得。
    • で、こんな感じでコントローラ(app/controllers/books_controller.rb)に追加
      class BooksController < ApplicationController
       caches_page :index, :show
       cache_sweeper :book_sweeper
      
      • これで、ちゃんとキャッシュが削除されて画面が最新版になるんだね。良かったー。

-
最終更新:2012年02月08日 07:50