29

私はほとんどすべてを試しましたが、モデルから expire_fragment を使用することは不可能に思えますか? 私はあなたが想定されていないことを知っています.MVCではありませんが、確かにそれを行う方法がたくさんあります.

lib/cache_helper.rb にモジュールを作成し、すべての有効期限ヘルパーを使用しました。それぞれの中に、expire_fragment 呼び出しがたくさんあります。すべてのキャッシュ スイーパーを /app/sweepers の下にセットアップし、アプリケーション コントローラーに「include CacheHelper」を設定しているため、コントローラー経由で呼び出されたときにアプリ内のキャッシュを期限切れにしても問題なく動作します。

次に、いくつかの外部デーモンと、特に特定のメソッドを呼び出す rake タスクを呼び出すいくつかの定期的な cron タスクがあります。このメソッドはいくつかの処理を行い、エントリをモデルに入力します。その後、キャッシュを期限切れにする必要があります。

モデル内でキャッシュ スイーパーを指定できないため、これを行う最善の方法は何ですか。まっすぐなオブザーバーが最善の解決策のようですが、expire_fragment が未定義であるなどについて不平を言います。ActionController キャッシング クラスをオブザーバーに含めようとしましたが、うまくいきませんでした。これに対する解決策を作成する方法についていくつかのアイデアが欲しいです。ありがとう。

4

8 に答える 8

43

免責事項:私のレールは少し錆びていますが、これまたはそのようなものはうまくいくはずです

ActionController::Base.new.expire_fragment(key, options = nil) 
于 2009-02-19T21:14:04.440 に答える
13

Orion が提供するソリューションは完璧に機能します。機能強化と利便性のために、次のコードをconfig/initializers/active_record_expire_fragment.rb

class ActiveRecord::Base
  def expire_fragment(*args)
    ActionController::Base.new.expire_fragment(*args)
  end
end

これで、ActiveRecord::Base のすべてのインスタンスで expire_fragment を使用できます。User.first.expire_fragment('user-stats')

于 2010-01-05T14:45:03.467 に答える
8

これは非常に簡単です。Orionの提案を実装できますが、以下に示すより広範な手法を実装することもできます。これにより、任意のモデルから現在のコントローラーにアクセスでき、MVC分離を解除することを決定した目的(フラグメントキャッシュの操作、アクセスcurrent_user、生成など)が可能になります。パス/URLなど)

任意のモデルから現在のリクエストのコントローラー(存在する場合)にアクセスするには、次を新しいプラグインに追加するenvironment.rbか、できれば新しいプラグインに追加します(たとえばvendor/plugins/controller_from_model/init.rb、以下のコードを含むcreate)。

module ActiveRecord
  class Base
    protected
      def self.thread_safe_current_controller #:nodoc:
        Thread.current[:current_controller]
      end

      def self.thread_safe_current_controller=(controller) #:nodoc:
        Thread.current[:current_controller] = controller
      end

      # pick up the correct current_controller version
      #  from @@allow_concurrency
      if @@allow_concurrency
        alias_method :current_controller,  :thread_safe_current_controller
        alias_method :current_controller=, :thread_safe_current_controller=
      else
        cattr_accessor :current_controller
      end
  end
end

次に、でapp/controllers/application.rb

class ApplicationController < ActionController::Base
  before_filter { |controller|
    # all models in this thread/process refer to this controller
    #  while processing this request
    ActiveRecord::Base.current_controller = controller
  }

  ...

次に、任意のモデルから

if controller = ActiveRecord::Base.current_controller
  # called from within a user request
else
  # no controller is available, didn't get here from a request - maybe irb?
fi

とにかく、特定のケースでは、関連するコントローラークラスがロードされたときにさまざまな子孫にコードを挿入しActiveRecord::Baseて、実際のコントローラー対応コードがまだ存在するapp/controllers/*.rbようにすることができますが、何かを機能させるためにそうする必要はありません(醜くて維持するのは難しいですが。)

楽しむ!

于 2009-03-03T23:36:30.700 に答える
6

私のスクリプトの 1 つで、次のハックを使用します。

  require 'action_controller/test_process'

  sweepers = [ApartmentSweeper]

  ActiveRecord::Base.observers = sweepers
  ActiveRecord::Base.instantiate_observers

  controller = ActionController::Base.new
  controller.request = ActionController::TestRequest.new
  controller.instance_eval do
    @url = ActionController::UrlRewriter.new(request, {})
  end

  sweepers.each do |sweeper|
    sweeper.instance.controller = controller
  end

次に、ActiveRecord コールバックが呼び出されると、スイーパーは expire_fragment を呼び出すことができます。

于 2008-12-26T02:55:39.247 に答える
2

私は少しレール初心者なので、これは正しくないか、役に立たないかもしれませんが、モデル内からコントローラーのアクションを呼び出そうとするのは間違っているようです。

コントローラー内で目的のアクションを記述し、rake タスク内からコントローラー アクションを呼び出すことはできませんか?

于 2009-02-27T08:59:46.333 に答える
2

現在のコントローラを引数としてモデル メソッド呼び出しに渡すだけの方が簡単でクリーンではないでしょうか? 次のように:

def delete_cascade(controller)

  self.categories.each do |c|
    c.delete_cascade(controller)
    controller.expire_fragment(%r{article_manager/list/#{c.id}.*})                
  end
  PtSection.delete(self.id)
  controller.expire_fragment(%r{category_manager/list/#{self.id}.*})        
end

モデル内からコントローラーのすべてのパブリック メソッドとプロパティにアクセスできます。コントローラーの状態を変更しない限り、問題ありません。

于 2009-06-01T18:22:20.460 に答える
2

外部の rake タスクでコントローラーの expiry メソッドを呼び出さないのはなぜですか。その後、あなたはまだMVCに準拠しており、スコーピングハックなどに依存して構築していません.

さらに言えば、すべてのデーモン/外部機能をコントローラーに配置して、rake/cronにそれを呼び出させてみませんか。メンテナンスがはるかに簡単になります。

-- マーカスQ

于 2009-03-02T05:08:30.357 に答える