модуль ActionView::Helpers::CacheHelper
Публичные методы экземпляров
# File actionview/lib/action_view/helpers/cache_helper.rb, line 166
def cache(name = {}, options = {}, &block)
if controller.respond_to?(:perform_caching) && controller.perform_caching
name_options = options.slice(:skip_digest, :virtual_path)
safe_concat(fragment_for(cache_fragment_name(name, name_options), options, &block))
else
yield
end
nil
end Этот помощник предоставляет метод для кэширования фрагментов представления, а не всего действия или страницы. Эта техника полезна для кэширования таких элементов, как меню, списки новых тем, статические фрагменты HTML и так далее. Этот метод принимает блок, содержащий контент, который вы хотите кэшировать.
Лучший способ использования — это реализация кэширования с истеканием срока действия на основе ключей, работающая поверх хранилища кэша, такого как Memcached или Redis, что автоматически удалит старые записи.
При использовании этого метода вы указываете зависимость кэша как имя кэша, например:
<% cache project do %> <b>All the topics on this project</b> <%= render project.topics %> <% end %>
Этот подход предполагает, что при добавлении новой темы вы будете обновлять проект. Ключ кэша, сгенерированный по этому вызову, будет выглядеть примерно так:
views/template/action.html.erb:7a1156131a6928cb0026877f8b749ac9/projects/123
^template path ^template tree digest ^class ^id Этот ключ кэша стабилен, но он комбинируется с версией кэша, полученной из записи проекта. При обновлении поля updated_at проекта, версия кэша изменяется, даже если сам ключ остается стабильным. Это означает, что в отличие от традиционного подхода к кэшированию на основе ключей, вы не будете генерировать мусор кэша, неиспользуемые ключи, просто потому, что обновляется зависимая запись.
Если кэш вашего шаблона зависит от нескольких источников (старайтесь избегать этого, чтобы всё было просто), вы можете указать все эти зависимости в массиве:
<% cache [ project, current_user ] do %> <b>All the topics on this project</b> <%= render project.topics %> <% end %>
Это включит обе записи в ключ кэша, и обновление любой из них приведёт к истечению срока действия кэша.
Хеш-код шаблона
Хеш-код шаблона, который добавляется в ключ кэша, вычисляется путём взятия MD5 от содержимого всего файла шаблона. Это гарантирует, что ваши кэши автоматически истекут, когда вы измените файл шаблона.
Обратите внимание, что MD5 вычисляется для всего файла шаблона, а не только для содержимого внутри вызова cache do/end. Поэтому возможно, что изменение чего-либо за пределами этого вызова всё ещё приведёт к истечению срока действия кэша.
Кроме того, дигеститор автоматически просматривает ваш файл шаблона в поисках явных и неявных зависимостей и включает их в хеш-код.
Дигеститор можно пропустить, передав skip_digest: true в качестве параметра вызову cache:
<% cache project, skip_digest: true do %> <b>All the topics on this project</b> <%= render project.topics %> <% end %>
Неявные зависимости
Большинство зависимостей шаблонов можно получить из вызовов render в самом шаблоне. Вот несколько примеров вызовов render, которые Cache Digests умеет декодировать:
render partial: "comments/comment", collection: commentable.comments
render "comments/comments"
render 'comments/comments'
render('comments/comments')
render "header" translates to render("comments/header")
render(@topic) translates to render("topics/topic")
render(topics) translates to render("topics/topic")
render(message.topics) translates to render("topics/topic") Однако, получить все вызовы render таким образом не представляется возможным. Вот несколько примеров того, что не может быть получено:
render group_of_attachments
render @project.documents.where(published: true).order('created_at')
Вам придётся переписать их в явном виде:
render partial: 'attachments/attachment', collection: group_of_attachments
render partial: 'documents/document', collection: @project.documents.where(published: true).order('created_at')
Явные зависимости
Иногда у вас будут зависимости шаблонов, которые вообще нельзя получить. Такая ситуация обычно возникает, когда вы имеете рендеринг шаблонов в помощниках. Вот пример:
<%= render_sortable_todolists @project.todolists %>
Вам нужно будет использовать специальный формат комментариев для указания этих зависимостей:
<%# Template Dependency: todolists/todolist %> <%= render_sortable_todolists @project.todolists %>
В некоторых случаях, например, при настройке единого наследования таблиц, у вас может быть множество явных зависимостей. Вместо того, чтобы указывать каждый шаблон, вы можете использовать подстановку для соответствия любому шаблону в каталоге:
<%# Template Dependency: events/* %> <%= render_categorizable_events @person.events %>
Это помечает каждый шаблон в каталоге как зависимость. Для поиска этих шаблонов путь с подстановкой должен быть абсолютно определён из app/views или путей, добавленных другими способами с помощью prepend_view_path или append_view_path. Таким образом, подстановка для app/views/recordings/events будет recordings/events/* и так далее.
Шаблон, используемый для соответствия явным зависимостям, это /# Template
Dependency: (\S+)/, поэтому важно вводить его именно так. Вы можете объявлять только одну зависимость шаблона в строке.
Внешние зависимости
Если вы используете метод помощника, например, внутри кэшируемого блока, и затем обновляете этот помощник, вам также придётся обновить кэш. На самом деле, это не имеет значения, как вы это делаете, но MD5 файла шаблона должен измениться. Одно из рекомендаций — просто быть явным в комментарии, например:
<%# Helper Dependency Updated: May 6, 2012 at 6pm %> <%= some_helper_method(person) %>
Теперь всё, что вам нужно сделать, это изменить эту метку времени, когда изменится метод помощника.
Кэширование коллекций
При отображении коллекции объектов, каждый из которых использует один и тот же фрагмент, можно передать опцию :cached.
Для коллекций, отображаемых так:
<%= render partial: 'projects/project', collection: @projects, cached: true %>
Опция cached: true заставит рендеринг Action View читать несколько шаблонов из кэша одновременно, а не по одному вызову на шаблон.
Шаблоны в коллекции, которые ещё не кэшированы, записываются в кэш.
Отлично работает с кэшированием отдельных фрагментов шаблонов. Например, если шаблон, который отображает коллекцию, кэшируется так:
# projects/_project.html.erb <% cache project do %> <%# ... %> <% end %>
Любые отображения коллекций найдут эти кэшированные шаблоны при попытке одновременного чтения нескольких шаблонов.
Если ваш кэш коллекций зависит от нескольких источников (старайтесь избегать этого, чтобы всё было просто), вы можете указать все эти зависимости как часть блока, возвращающего массив:
<%= render partial: 'projects/project', collection: @projects, cached: -> project { [ project, current_user ] } %> Это включит обе записи в ключ кэша, и обновление любой из них приведёт к истечению срока действия кэша.
# File actionview/lib/action_view/helpers/cache_helper.rb, line 211
def cache_fragment_name(name = {}, skip_digest: nil, virtual_path: nil)
if skip_digest
name
else
fragment_name_with_digest(name, virtual_path)
end
end Этот помощник возвращает имя ключа кэша для данного вызова кэширования фрагмента. Передав skip_digest: значение true для cache, можно вручную пропустить вычисление хеш-кода фрагментов кэша. Это полезно, когда фрагменты кэша нельзя вручную истечь, если вы не знаете точный ключ, что происходит при использовании memcached.
Хеш-код будет сгенерирован с использованием virtual_path: если он предоставлен.
# File actionview/lib/action_view/helpers/cache_helper.rb, line 183
def cache_if(condition, name = {}, options = {}, &block)
if condition
cache(name, options, &block)
else
yield
end
nil
end Кэшировать фрагменты представления, если condition имеет значение true
<% cache_if admin?, project do %> <b>All the topics on this project</b> <%= render project.topics %> <% end %>
# File actionview/lib/action_view/helpers/cache_helper.rb, line 199
def cache_unless(condition, name = {}, options = {}, &block)
cache_if !condition, name, options, &block
end Кэшировать фрагменты представления, если condition имеет значение false
<% cache_unless admin?, project do %> <b>All the topics on this project</b> <%= render project.topics %> <% end %>
© 2004–2018 David Heinemeier Hansson
Licensed under the MIT License.