В Rails Sweeper не вызывается при настройке только для модели.

StackOverflow https://stackoverflow.com/questions/1463714

Вопрос

Я работаю над приложением Rails, где использую кэширование страниц для хранения статического вывода HTML.Кэширование работает нормально.Однако у меня возникли проблемы с истечением срока действия кешей.

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

В моем файле Environment.rb я вызываю

config.load_paths += %W( #{RAILS_ROOT}/app/sweepers )

И у меня в папке /sweepers есть файл LinkSweeper:

class LinkSweeper < ActionController::Caching::Sweeper
  observe Link

  def after_update(link)
    clear_links_cache(link)
  end

  def clear_links_cache(link)
  # expire_page :controller => 'links', :action => 'show', :md5 => link.md5
    expire_page '/l/'+ link.md5 + '.html'
  end
end

Так ... почему он не удаляет кешированную страницу при обновлении модели? (Процесс:используя скрипт/консоль, я выбираю элементы из базы данных и сохраняю их, но соответствующие им страницы не удаляются из кеша), а также вызываю определенный метод в модели Link, который обычно вызывает очиститель.Ни то, ни другое не работает.

Если это имеет значение, кешированный файл представляет собой хэш md5 значения ключа в таблице ссылок.Кэшированная страница сохраняется как-то вроде /l/45ed4aade64d427...99919cba2bd90f.html.

По сути, создается впечатление, что Подметальная машина на самом деле не наблюдает за Связью.я тоже читал(здесь), что можно было бы просто добавить очиститель в config.active_record.observers в Environment.rb, но, похоже, этого не произошло (и я не был уверен, что путь загрузки приложения/чистильщиков в Environment.rb обходится стороной). что).

Это было полезно?

Решение

Просто примечание:вы можете использовать cache_sweeper в Контроллере приложений.

class ApplicationController < ActionController::Base
  cache_sweeper :my_sweeper
end

class MySweeper < ActionController::Caching::Sweeper
  observe MyModel

  def after_update(my_model)
    expire_page(...)
  end
end

Другие советы

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

Еще раз подведу итог ситуации: Моя цель — истечь срок действия кэшированных страниц при обновлении объекта, но истечь, не полагаясь на действие контроллера. Обычные подметальные машины используют линию в контроллере для уведомления подметальной машины о необходимости ее работы.В данном случае я не могу использовать строку в контроллере, так как обновление происходит внутри модели.Обычные руководства по очистке не работают, поскольку предполагают, что основное взаимодействие с объектом базы данных осуществляется через контроллер.

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

Во-первых, давайте посмотрим на то, что ДЕЙСТВИТЕЛЬНО работает, на случай, если вы тоже застряли в этом и вам понадобится помощь.

Из всего, что я пробовал, единственное, что действительно сработало, — это объявить команду after_update в Observer для модели.В этой команде я использовал явную команду для действия expire_page и включил путь, объявленный в Routes.rb.

Так.Это работает:

В config/routes.rb:

map.link 'l/:md5.:format',  :controller => 'links', :action => 'show'

В приложении/модели/link_observer.rb:

def after_update(link)
  ActionController::Base.expire_page(app.link_path(:md5 => link.md5))
end

Обратите внимание, что «md5» относится только к моему приложению.Возможно, вы захотите использовать :id или какой-либо другой уникальный идентификатор.

Я также обнаружил, что объявление ActionController::Base...строка из метода в модели, которая выполняет обновление, сработала.То есть в Link.rb, в методе, который фактически обновляет базу данных, если я просто вставил всю эту строку, это сработало.Но поскольку в будущем мне может потребоваться истечь срок действия этого кэша страниц другими методами, я бы предпочел извлечь его в Observer.

Теперь давайте посмотрим на некоторые вещи, которые НЕ сработали, на случай, если вы ищете это в Google.

Вызов «expire_page(...)» в методе after_update(link) внутри link_observer.rb не работало, так как возвращалось ошибка «неопределенный метод `expire_page'»

Создание файла Sweeper заметил, что Модель не работает.Я не смог найти никаких кодов ошибок, но, похоже, он даже не осознавал, что ему предстоит выполнить свою работу.Это произошло после явного вызова «config.load_paths += %W(#{RAILS_ROOT}/app/sweepers)» в файле Environment.rb.На всякий случай я что-то напутал в этом коде, вот оно:

class LinkSweeper < ActionController::Caching::Sweeper
  observe Link

  def after_update(link)
    clear_links_cache(link)
  end

  def clear_links_cache(link)
    # DID NOT WORK    expire_page :controller => 'links', :action => 'show', :md5 => link.md5
    # DID NOT WORK    expire_page '/l/'+ link.md5 + '.html'
    # DID NOT WORK    ActionController::Base.expire_page(app.link_path(:md5 => link.md5))
  end
end

В приведенном выше примере файл link_sweeper.rb находился в каталоге /app/sweepers.Я также попытался поместить link_sweeper.rb в каталог app/models и попытался вызвать его с помощью команды config.active_record.observers в Environment.rb:

config.active_record.observers = :link_observer, :link_sweeper

Но это тоже не сработало.

Так что да.Вполне возможно, что один из этих способов сработает, и я что-то напутал в коде.Но я думаю, что я сделал все по инструкции.

В конечном итоге, подведем итог:Вместо использования Sweeper для прекращения кэширования страниц вы хотите настроить обратный вызов after_ в Observer модели.Вы захотите использовать явный путь к методу Base.expire_page:

def after_update(<model>) # where <model> is the name of the model you're observing
  ActionController::Base.expire_page(app.<model>_path(:id => <model>.id)) # where <model> is the name of the model you're observing
end

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

У меня возникла та же проблема при попытке кэширования фрагментов (rails 3).Не удалось заставить подметальную машину наблюдать, поэтому я решил сделать ее наблюдателем AR, как описано выше, и вызвать ApplicationController.new.expire_fragment(...).

У меня это сработало.Единственное небольшое отличие в моей настройке состоит в том, что очиститель является частью движка Rails;что объясняет небольшие различия (загрузка файла очистки с помощью запроса в инициализации движка вместо добавления его в путь загрузки в Environment.rb и т. д.).

Итак, свипер загружается в init.rb движка вот так:

require File.join(File.dirname(__FILE__), 'app', 'sweepers', cached_category_count_sweeper')

Я назвал его очистителем, потому что он «очищает» кэш, но я думаю, это просто наблюдатель на модели:

class CachedCategoryCountSweeper < ActiveRecord::Observer
  observe CategoryFeature

  def before_save(cf)
    expire_cache(cf.category_id_was) if cf.category_id_changed?
  end

  def after_save(cf)
    expire_cache(cf.category_id)
  end

  def after_destroy(cf)
    expire_cache(cf.category_id)
  end

  def expire_cache(c)
    ApplicationController.expire_page("/categories/#{c}/counts.xml") if !c.nil?
  end
end

Честно говоря, мне не нравится жестко прописывать путь, но я попробовал добавить:

include ActionController:UrlWriter

а затем использовать метод пути, но у меня это работало только в разработке.Это не сработало в рабочей среде, поскольку мой рабочий сервер использует относительный корень URL-адреса (вместо виртуальных хостов), а внутренний метод «page_cache_path» постоянно неправильно определял путь к файлу, поэтому срок его действия не мог истечь.

Поскольку это наблюдатель, я добавил в Environment.rb:

config.active_record.observers = :cached_category_count_sweeper

Наконец, контроллер, который использует кеш (не истекает срок его действия, это делается через наблюдателя модели):

class CachedCategoryCountsController < ApplicationController
  caches_page :index

  # GET /cached_category_counts.xml
  def index
    ...
  end
end

В любом случае, надеюсь, это поможет.

Андрес Монтано

Мне удалось заставить его работать, добавив

ActionController::Base.expire_page(app.link_path(:md5 => @link.md5))

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

Этот фрагмент кода (не считая настроек, которые я внес в свое приложение) взят из этот пост на Ruby-Forum.com.

Я немного писал на эту тему здесь: Путаница с очисткой кэша Rails.Хотелось бы услышать ваше мнение.

Основываясь на ответах @moiristo и @ZoogieZork, я предполагаю, что это сработает (непроверено).

class LinkSweeper < ActiveRecord::Observer
  include ActionController::Caching::Pages
  # or if you want to expire fragments
  #include ActionController::Caching::Fragments

  observe Link

  def after_update(link)
    expire_page( ... )
    #expire_fragment( ... )
  end
end
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top