Rails 4.0 истекает срок действия фрагмента / кэша не работает

Я пытался использовать возможности кэширования rails, но я не могу истечь некоторый фрагмент кэша, хотя они, кажется, истекают. Используя "кэширование русской куклы" , как указано на сайте учебника rails, я использую эту конфигурацию

<% cache "all_available_releases" do %>
 <% @releases.each do |release| %>
  <% cache(release) do %>
   <html code with>
   <%ruby code @release.name blah blah blah%>
  <%end%>
 <%end%>
<%end%>    

я заканчиваю внешнее кэширование в release_controller.контроллер РБ, где я использую expire_fragment("all_available_releases") истекает фрагмента. Я использую его в каждом методе контроллера, который обновляет или удаляет или добавляет запись.

это журнал WEBrick, где, хотя истекающий фрагмент регистрируется, через 5 строк истекший фрагмент считывается и используется, пока он не должен. Этот пример после вызова destroy.

Processing by ReleasesController#destroy as HTML
  Parameters: {"authenticity_token"=>"***/***/********************+********=", "id"=>"2"}
  Release Load (0.1ms)  SELECT "releases".* FROM "releases" WHERE "releases"."id" = ? LIMIT 1  [["id", "2"]]
   (0.1ms)  begin transaction
  SQL (2.0ms)  DELETE FROM "releases" WHERE "releases"."id" = ?  [["id", 2]]
   (148.0ms)  commit transaction
Expire fragment views/all_available_releases (0.1ms)
Redirected to http://127.0.0.1:3000/releases
Completed 302 Found in 180ms (ActiveRecord: 150.2ms)


Started GET "/releases" for 127.0.0.1 at 2013-07-03 13:09:51 +0300
Processing by ReleasesController#index as HTML
Read fragment views/all_available_releases/41cb0a928326986f35f41c52bb3d8352 (0.1ms)
  Rendered releases/index.html.erb within layouts/application (0.6ms)
Completed 200 OK in 5ms (Views: 4.0ms | ActiveRecord: 0.0ms)

Я даже пытался использовать Rails.cache.delete("all_available_releases") и это тоже не сработало.

если я удалить <%cache "all_available_releases"%> (один <%end%>) из моего html.erb кэширование работает нормально и истекает, когда это необходимо.

4 ответов


Я считаю, что проблема в том, что когда вы кэшируете фрагмент в своем представлении, дайджест кэша добавляется в ключ кэша (views/all_available_releases/41cb0a928326986f35f41c52bb3d8352), но expire_fragment не использует дайджест (views/all_available_releases).

Если добавить skip_digest: true для вызова кэша в представлении он должен предотвратить использование дайджеста.

<% cache "all_available_releases", skip_digest: true do %>
 <% @releases.each do |release| %>
  <% cache(release) do %>
   <html code with>
   <%ruby code @release.name blah blah blah%>
  <%end%>
 <%end%>
<%end%>

кэш сборники предназначены только для использования с автоматическим кешем выдыхание. Если вам нужно вручную истечь ключи кэша, вы не можете использовать дайджесты кэша.


Jbuilder не поддерживает skip_digest. После многих неудачных подходов я решил поделиться своими ответами здесь, поскольку это очень связано, хотя и не с представлением rails, как проблема выше.

вот связанный вопрос Q/, где DHH по существу говорит парню, что он не может истекать fragment_caches явно. https://github.com/rails/cache_digests/issues/35 Все это не так вот это:

class MenuController
  def index
    json = Rails.cache.fetch('clients') do
      @items = Menu.all
      render_to_string( template: 'menu/index', locals: {items: @items})
    end
    render json: json
  end
end

тогда вы можете объяснить истекает это где угодно, как в observer

class MenuCacheObserver < ActiveRecord::Observer
  observe :menu, :menuitem, :menusubnavigation

  def after_save obj
    Rails.cache.delete(:clients)
  end
end

В некоторых случаях это может иметь смысл. В общем, в большинстве случаев вы должны использовать объект во входных данных кэша, например json.cache! @my_object do обертывание представления jbuilder. Таким образом, он будет недействителен при изменении updated_at объекта.


просто столкнулся с этой проблемой сам, и то, как я подошел к ее решению, было через регулярные выражения. Это может быть не самое элегантное решение, но работает нормально.

ActionController::Base.new.expire_fragment(%r{offer_#{@offer.id}/*})

добавление skip_digest намного приятнее.


в Rails 5 я сделал следующие шаги, чтобы разбить кэш, не прибегая к skip_digest: true. Наша проблема заключалась в том, что изменение значения строк I18n не отражается в вычисляемом дайджесте кэша, поэтому кэш не будет автоматически разорен.

вот представление, в котором определен блок кэша:

/ views/layouts/_footer.html.slim
- cache :footer do
  span= t('shared.footer')

затем в консоли rails я запускаю:

fragment = ActionController::Base.new.view_context.cache_fragment_name(:footer, virtual_path: 'layouts/_footer.html.slim')
ActionController::Base.new.expire_fragment(fragment)

cache_fragment_name выяснит дайджест на основе virtual_path аргумент сайта.