10

私はページキャッシュを使用して静的なhtml出力を保存しているRailsアプリに取り組んでいます。キャッシングは正常に機能します。ただし、キャッシュの有効期限が切れるのに問題があります。

私の問題の一部は、コントローラーからキャッシュを期限切れにしないためだと思います。これに必要なすべてのアクションは、モデル内で処理されています。これは実行可能であるように思われますが、私が見つけたモデルベースのキャッシュの有効期限への言及はすべて古くなっているように見えるか、そうでなければ機能していません。

私の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 モデルの特定のメソッドも呼び出しています。スイーパー。どちらも機能しません。

問題がある場合、キャッシュされたファイルは Links テーブルのキー値から md5 ハッシュされたものです。キャッシュされたページは、/l/45ed4aade64d427...99919cba2bd90f.html のような形式で保存されます。

基本的に、スイーパーは実際にはリンクを監視していないように見えます。また、environment.rb の config.active_record.observers にスイーパーを単純に追加することもできるかもしれないと読みました (こちら) が、それではうまくいかなかったようです (そして、app/sweepers の load_path がenvironment.rb でそれを回避しました)。

4

7 に答える 7

11

そのため、何が機能し、何が機能しないかを確認するために、さまざまなアプローチを試しました。

繰り返しますが、状況を要約すると、私の目標は、オブジェクトが更新されたときにキャッシュされたページを期限切れにすることですが、コントローラーのアクションに依存せずにページを期限切れにすることです。従来のスイーパーは、コントローラー内のラインを使用して、機能する必要があることをスイーパーに通知します。この場合、モデル内で更新が行われているため、コントローラーでラインを使用することはできません。通常のスイーパー チュートリアルは、データベース オブジェクトとの主なやり取りがコントローラーを介して行われると想定しているため、機能しません。

これを読んで、私のコードを引き締める方法を見つけたら、コメントして教えてください。

まず、これで行き詰まって助けが必要な場合に備えて、実際に機能するものを見てみましょう。

私が試したすべてのことの中で、実際に機能しているように見えた唯一のことは、モデルのオブザーバーで after_update コマンドを宣言することでした。そのコマンドでは、expire_page アクションに明示的なコマンドを使用し、routes.rb で宣言されたパスを含めました。

そう。これは機能します:

config/routes.rb:

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

app/models/link_observer.rb:

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

「md5」は私のアプリに固有のものであることに注意してください。:id またはその他の一意の識別子を使用したい場合があります。

また、更新を行っているモデルのメソッドから ActionController::Base... 行を宣言すると、機能することもわかりました。つまり、Link.rb 内で、実際にデータベースを更新しているメソッドで、その行全体を差し込むだけで機能しました。しかし、将来、他の方法でそのページ キャッシュを期限切れにする可能性があるため、オブザーバーに抽出することをお勧めします。

さて、これについてグーグルで検索している場合に備えて、うまくいかなかったいくつかのことを見てみましょう。

link_observer.rb 内の after_update(link) メソッド内で「expire_page(...)」を呼び出すと、「undefined method `expire_page'」エラーが返されたため、機能しませんでした。

モデルを監視する Sweeper ファイルの作成が機能しませんでした。エラーコードは見つかりませんでしたが、やるべき仕事があることさえ認識していないようでした. これは、environment.rb 内で明示的に「config.load_paths += %W( #{RAILS_ROOT}/app/sweepers )」を呼び出した後でした。念のため、そのコードで何かを指で示しました。これは次のとおりです。

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

上記の例では、ディレクトリ /app/sweepers に link_sweeper.rb ファイルがありました。また、link_sweeper.rb を app/models ディレクトリに配置して、environment.rb の config.active_record.observers コマンドで呼び出してみました。

config.active_record.observers = :link_observer, :link_sweeper

しかし、それもうまくいきませんでした。

それで、ええ。これらの方法のいずれかが機能する可能性は十分にあり、コードで何かを台無しにしてしまった可能性もあります。しかし、私は本ですべてをやったと思います。

最終的に要約すると、Sweeper を使用してページ キャッシュを期限切れにするのではなく、モデルのオブザーバーで after_ コールバックを設定する必要があります。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

うまくいけば、これは将来誰かを助けるでしょう。繰り返しますが、動作しないコードのどこかに別の方法をとるべきだった箇所があれば、お知らせください。私の作業コードにもっときついものがある場合は、それもお知らせください。

于 2009-09-23T13:10:37.477 に答える
5

注意: cache_sweeperApplicationController で使用できます。

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
于 2010-06-07T08:07:14.777 に答える
3

フラグメントキャッシングを行おうとしたときに同じ問題が発生していました (レール 3)。スイーパーを観察させることができなかったので、上記のように AR オブザーバーにして を呼び出すという解決策に落ち着きましたApplicationController.new.expire_fragment(...)

于 2011-01-07T12:46:13.983 に答える
2

私はこれを機能させました。私のセットアップにおける唯一のわずかな違いは、スイーパーが Rails エンジンの一部であることです。これはわずかな違いを考慮しています (environment.rb のロード パスに追加するのではなく、エンジンの init で require を使用してスイーパー ファイルをロードするなど)。

そのため、スイーパーは次のようにエンジンの 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

とにかく、これが役立つことを願っています。

アンドレス・モンタノ

于 2010-06-16T16:52:12.220 に答える
0

このトピックについて少し書いた:Rails CacheSweeperConfusion。ご意見をお聞かせください。

于 2010-12-14T17:34:58.433 に答える
0

@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
于 2012-01-13T09:06:21.313 に答える
0

追加することで、動作させることができました

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

データベースを更新しているモデル自体のメソッドに。ただし、これはややハッキリしているように感じます。通常のスイーパーのセットアップで機能しない理由を誰かが説明できるかどうか、またこれを処理するためのよりエレガントな方法があるかどうかを知りたいです。

このコード スニペット (自分のアプリ用に行ったカスタマイズは別として) は、ruby-forum.com のこの投稿から取得しました。

于 2009-09-23T03:00:22.107 に答える