Spec-Zone.ru › Ruby on Rails 6.1

модуль ActionView::Helpers::CacheHelper

Публичные методы экземпляра

cache(name = {}, options = {}) { || ... } Показать исходный код
# 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)
    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: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 вычисляется от всего файла шаблона, а не только от содержимого внутри вызова 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 ] } %>

Это включит обе записи в качестве части ключа кэша, и обновление любой из них приведет к истечению срока действия кэша.

cache_fragment_name(name = {}, skip_digest: nil, digest_path: nil) Показать исходный код
# File actionview/lib/action_view/helpers/cache_helper.rb, line 208
def cache_fragment_name(name = {}, skip_digest: nil, digest_path: nil)
  if skip_digest
    name
  else
    fragment_name_with_digest(name, digest_path)
  end
end

Этот помощник возвращает имя ключа кэша для заданного вызова кэширования фрагмента. Передавая skip_digest: true в cache, можно вручную пропустить вычисление хеша фрагментов кэша. Это полезно, когда фрагменты кэша нельзя вручную истечь, если вы не знаете точного ключа, что актуально при использовании memcached.

cache_if(condition, name = {}, options = {}) { || ... } Показать исходный код
# 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 истинно

<% cache_if admin?, project do %>
  <b>All the topics on this project</b>
  <%= render project.topics %>
<% end %>
cache_unless(condition, name = {}, options = {}, &block) Показать исходный код
# 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 ложно

<% cache_unless admin?, project do %>
  <b>All the topics on this project</b>
  <%= render project.topics %>
<% end %>

© 2004–2020 David Heinemeier Hansson
Licensed under the MIT License.

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API