Rails 4.0 expire_fragment/cache expiration не работает
Я пытаюсь использовать возможности кэширования рельсов, но я не могу закончить некоторые фрагменты кеша, хотя они, похоже, истекли. Используя "Russian Caching Caching", как указано на сайте руководства по рельсам, я использую эту конфигурацию
<% 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.rb, где я использую expire_fragment ( "all_available_releases" ) для истечения срока действия фрагмента. Я использую его в каждом методе контроллера, который обновляет или удаляет или добавляет запись.
Это журнал WEBrick, где, хотя фрагмент expire регистрируется, 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, кеширование прекратится и истекает всякий раз, когда это необходимо.
Ответы
Ответ 1
Я считаю, что проблема заключается в том, что при кэшировании фрагмента в вашем представлении кэш-ключ добавляется кэш файл (views/all_available_releases/ 41cb0a928326986f35f41c52bb3d8352), но expire_fragment не использует дайджест (просмотров/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%>
Сборники кэша предназначены только для использования с автоматическим истечением срока действия кеша. Если вам нужно вручную истечь ключей кеша, вы не можете использовать дайджесты кэша.
Ответ 2
Jbuilder не поддерживает skip_digest. После многих неудачных подходов я решил поделиться своими ответами здесь, поскольку он очень связан, хотя и не с просмотром рельсов, как это было выше.
Вот связанный вопрос Q/, в котором DHH по существу говорит парню, что он не может истекать явно. 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
то вы можете явно истечь в любом месте, как в наблюдателе
class MenuCacheObserver < ActiveRecord::Observer
observe :menu, :menuitem, :menusubnavigation
def after_save obj
Rails.cache.delete(:clients)
end
end
В некоторых случаях это может иметь смысл. В общем случае, в большинстве случаев вы должны использовать объект во входном кэше, например json.cache! @my_object do
, обертывающий представление jbuilder. Таким образом, это приведет к недействительности при изменении update_at на объекте.
Ответ 3
Просто наткнулся на эту проблему сам и способ, которым я обращался к этому, заключался в регулярных выражениях. Это может быть не самое элегантное решение, но оно отлично работает.
ActionController::Base.new.expire_fragment(%r{offer_#{@offer.id}/*})
Добавление skip_digest намного приятнее.
Ответ 4
В 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
.