Spec-Zone.ru › Ruby on Rails 7.0

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

Открытые методы экземпляра

cache(name = {}, options = {}) { || ... } Показать исходный код
# File actionview/lib/action_view/helpers/cache_helper.rb, line 168
def cache(name = {}, options = {}, &block)
  if controller.respond_to?(:perform_caching) && controller.perform_caching
    CachingRegistry.track_caching do
      name_options = options.slice(:skip_digest)
      safe_concat(fragment_for(cache_fragment_name(name, **name_options), options, &block))
    end
  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 Digest умеет декодировать:

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 240
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 215
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 %>
cache_unless(condition, name = {}, options = {}, &block) Показать исходный код
# File actionview/lib/action_view/helpers/cache_helper.rb, line 231
def cache_unless(condition, name = {}, options = {}, &block)
  cache_if !condition, name, options, &block
end

Кэширует фрагменты представления, если condition не равно true.

<% cache_unless admin?, project do %>
  <b>All the topics on this project</b>
  <%= render project.topics %>
<% end %>
caching?() Показать исходный код
# File actionview/lib/action_view/helpers/cache_helper.rb, line 188
def caching?
  CachingRegistry.caching?
end

Возвращает значение true, если текущий фрагмент представления находится внутри блока cache.

Полезно, когда определённые фрагменты не могут быть кэшированы:

<% cache project do %>
  <% raise StandardError, "Caching private data!" if caching? %>
<% end %>
uncacheable!() Показать исходный код
# File actionview/lib/action_view/helpers/cache_helper.rb, line 205
def uncacheable!
  raise UncacheableFragmentError, "can't be fragment cached" if caching?
end

Вызывает исключение UncacheableFragmentError, когда вызывается внутри блока cache.

Полезно для обозначения методов помощников, которые не могут участвовать в кэшировании фрагментов:

def project_name_with_time(project)
  uncacheable!
  "#{project.name} - #{Time.now}"
end

# Which will then raise if used within a +cache+ block:
<% cache project do %>
  <%= project_name_with_time(project) %>
<% end %>

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

Spec-Zone.ru

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