문제

가장 최근의 게시물을 표시하는 페이지 조각이 있고 30 분 안에 만료됩니다. 여기에 레일을 사용하고 있습니다.

<% cache("recent_posts", :expires_in => 30.minutes) do %>
  ...
<% end %>

분명히 조각이 존재하는 경우 가장 최근의 게시물을 얻기 위해 데이터베이스 조회를 수행 할 필요는 없으므로 오버 헤드도 피할 수 있어야합니다.

내가 지금하고있는 일은 작동하는 것처럼 보이는 컨트롤러에서 이와 같은 것입니다.

unless Rails.cache.exist? "views/recent_posts"
  @posts = Post.find(:all, :limit=>20, :order=>"updated_at DESC")
end

이것이 가장 좋은 방법입니까? 안전 해요?

내가 이해하지 못하는 한 가지는 키가 왜 "recent_posts"조각을 위해"views/recent_posts"나중에 확인할 때, 그러나 나는 본 후에 이것을 생각해 냈습니다. memcached -vv 사용중인 것을보기 위해. 또한 수동으로 들어가는 복제가 마음에 들지 않습니다. "recent_posts", 그것을 한 곳에 유지하는 것이 좋습니다.

아이디어?

도움이 되었습니까?

해결책

에반 위버 연동 플러그인 이 문제를 해결합니다.

더 미세한 통제와 같은 다른 행동이 필요한 경우 이와 같은 것을 쉽게 구현할 수 있습니다. 기본 아이디어는 컨트롤러 코드를 뷰에 해당 데이터가 필요한 경우에만 실행되는 블록으로 래핑하는 것입니다.

# in FooController#show
@foo_finder = lambda{ Foo.find_slow_stuff }

# in foo/show.html.erb
cache 'foo_slow_stuff' do
  @foo_finder.call.each do 
    ...
  end
end

Ruby Meta 프로그래밍의 기본 사항에 익숙하다면 더 깨끗한 API로 마무리하는 것이 쉽습니다.

이것은 파인더 코드를보기에 직접 배치하는 것보다 우수합니다.

  • 개발자가 컨벤션별로 기대하는 파인더 코드를 유지합니다.
  • 모형 이름/메소드를 무지하게 유지하여 더 많은 뷰 재사용을 허용합니다.

CACHE_FU는 버전/포크 중 하나에서 비슷한 기능을 가질 수 있지만 구체적으로 기억할 수는 없습니다.

Memcached에서 얻는 이점은 캐시 적중률과 직접 관련이 있습니다. 동일한 콘텐츠를 여러 번 캐싱하여 캐시 용량을 낭비하지 말고 불필요한 누락을 유발하십시오. 예를 들어, 레코드 객체 세트와 HTML 조각을 동시에 캐시하지 마십시오. 일반적으로 Fragment Caching은 최고의 성능을 제공하지만 실제로 응용 프로그램의 세부 사항에 따라 다릅니다.

다른 팁

캐시가 컨트롤러에서 확인하는 시간과 뷰 렌더링에서 꿀벌을 확인한 시간 사이에 만료되면 어떻게됩니까?

모델에서 새로운 방법을 만들었습니다.

  class Post
    def self.recent(count)
      find(:all, :limit=> count, :order=>"updated_at DESC")
    end
  end

그런 다음보기에서 사용하십시오.

<% cache("recent_posts", :expires_in => 30.minutes) do %>
  <% Post.recent(20).each do |post| %>
     ...
  <% end %>
<% end %>

명확성을 위해, 최근 게시물의 렌더링을 자체 부분으로 옮기는 것을 고려할 수도 있습니다.

<% cache("recent_posts", :expires_in => 30.minutes) do %>
  <%= render :partial => "recent_post", :collection => Post.recent(20) %>
<% end %>

당신은 또한 조사하고 싶을 수도 있습니다

파편 캐시 문서

이를 수행 할 수 있습니다.

<% cache("recent_posts", :expires_in => 30.minutes) do %>
  ...
<% end %>

제어 장치

unless fragment_exist?("recent_posts")
  @posts = Post.find(:all, :limit=>20, :order=>"updated_at DESC")
end

나는 Dry의 문제를 인정하지만 여전히 두 곳에서 열쇠의 이름이 필요한 머리를 양육합니다. 나는 보통 Lars가 제안한 방식과 비슷하지만 실제로 맛에 달려 있습니다. 내가 아는 다른 개발자들은 조각을 확인하는 데 고집되어 있습니다.

업데이트:

파편 문서를 보면보기 접두사가 어떻게 필요한지 알 수 있습니다.

# File vendor/rails/actionpack/lib/action_controller/caching/fragments.rb, line 33
def fragment_cache_key(key)
  ActiveSupport::Cache.expand_cache_key(key.is_a?(Hash) ? url_for(key).split("://").last : key, :views)
end

LARS는 다음을 사용하여 약간의 실패 가능성이 있다는 점에 대해 정말 좋은 지적을합니다.

unless fragment_exist?("recent_posts")

캐시를 확인할 때와 캐시를 사용할 때 사이에 간격이 있기 때문입니다.

Jason이 언급 한 플러그인 (인터록)은 조각의 존재를 확인하는 경우 조각을 사용하여 콘텐츠를 로컬로 캐시 할 것이라고 가정하여 매우 우아하게 처리합니다. 나는 바로 이러한 이유로 인터록을 사용합니다.

생각의 한 조각으로 :

응용 프로그램 컨트롤러에서 정의합니다

def when_fragment_expired( name, time_options = nil )
        # idea of avoiding race conditions
        # downside: needs 2 cache lookups
        # in view we actually cache indefinetely 
        # but we expire with a 2nd fragment in the controller which is expired time based
        return if ActionController::Base.cache_store.exist?( 'fragments/' + name ) && ActionController::Base.cache_store.exist?( fragment_cache_key( name ) )

        # the time_fraqgment_cache uses different time options
        time_options = time_options - Time.now if time_options.is_a?( Time )

        # set an artificial fragment which expires after given time
        ActionController::Base.cache_store.write("fragments/" + name, 1, :expires_in => time_options )

        ActionController::Base.cache_store.delete( "views/"+name )        
        yield    
  end

그런 다음 모든 조치 사용에서

    def index
when_fragment_expired "cache_key", 5.minutes
@object = YourObject.expensive_operations
end
end

관점에서

cache "cache_key" do
view_code
end
라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top