Mechanizm cachowania w RoR

by Nazgul

Cache w Ruby on Rails

Cza­sami two­rząc apli­ka­cje inter­ne­towe, wyma­ga­jące dużej wydaj­no­ści, oka­zuje się, że wyko­ny­wa­nie jakie­goś kodu od nowa dla każ­dego odwie­dza­ją­cego jest nie­eko­no­miczne. Można temu zara­dzić umiesz­cza­jąc taki kod w cache (pliku, pamięci ram, bazie danych).

W RoR ist­nieją trzy tryby bufo­ro­wa­nia zawartości:

  1. Bufo­ro­wa­nie całej strony — page cachcing
  2. Bufo­ro­wa­nie akcji — action caching
  3. Bufo­ro­wa­nie frag­men­tów — frag­ments caching

Page caching

Bufo­ro­wa­nie strony polega na doda­niu do swo­jego kon­tro­lera fil­tra caches_page, w naj­prost­szym wypadku wygląda to tak:

class MainController < ApplicationController
  caches_page :index, :about
end

Strony index i about zostaną umiesz­czone w bufo­rze, i z tam­tąd będą ser­wo­wane użyt­kow­ni­kom.
Tam metoda jest bar­dzo pro­sta, lecz jeśli masz na niej jakieś ele­menty np. zależne od użyt­kow­nika, to nie­stety musisz z niej zrezygnować.

Action caching

Ta metoda keszo­wa­nia, nie różni sie zna­cząco od poprzed­niej. Do bufora łado­wany jest wynik prze­twa­rza­nia akcji, a sza­blon jest prze­twa­rzany za każ­dym razem, więc możemy ser­wo­wać treść cacho­waną i dyna­miczną na raz.

caches_action :akcja1, :akcja2

Frag­ment caching

Jeśli nasza apli­ka­cja używa nie tylko con­tentu bazu­ją­cego na URLach (np. zwią­za­nego z sesjami), musimy użyć trze­ciego spo­sobu bufo­ro­wa­nia danych. Ten spo­sób ma jedną zaletę — jest bar­dzo ela­styczny, możemy pre­cy­zyj­nie zazna­czyć co chcemy bufo­ro­wać, a czego nie, za pomocą znacz­ni­ków szablonów:

# non-buffered content
< % cache( :action => 'show_post',:id => @post_id) do %>
       # buffered content
< % end %>
# non-buffered content

Tak infor­mu­jemy fra­me­work, że wer­sja ske­szo­wana jest już nie­po­trzebna (doty­czy wszyst­kich try­bów cachcingu):

expire_page :controller => 'blog', :action => 'show_post', :id => post_id

Swe­eper

Swe­eper jest to kod, odpo­wie­dzialny za auto­ma­tyczne czysz­cze­nie bufora.

class BlogSweeper < ActionController::Caching::Sweeper #klasa sweepera
  observe Blog #Będziemy obserwować kontroler Blog

  #jeśli stworzymy posta, usuń cache
  def after_create(post)
          expire_cache_for(post)
  end

  # jeśli zmodyfikujemy posta, usuń cache
  def after_update(post)
          expire_cache_for(post)
  end

  # ... i to samo jeśli usuniemy
  def after_destroy(post)
          expire_cache_for(post)
  end

  private
  def expire_cache_for(record)
    expire_page(:controller => 'blog', :action => 'show_post', :id => record.id)
    expire_page(:controller => 'blog', :action => 'show_posts')
  end
end

I teraz aby uży­wać naszej klasy dodamy filtr:

cache_sweeper :blog_sweeper, :only => [:create, :update, :destroy]

Na koniec

Po wię­cej infor­ma­cji odsy­łam do doku­men­ta­cji RoR: frag­ment caching, action caching, page caching, swe­eping

Pole­cam jeszce przej­rze­nie tego postu, który poka­zuje inne podej­scie do bufo­ro­wa­nia w Rubym: Jar​mark​.org — Wygodny Cache