2013-04-21 18 views
9

私は、1回のリクエストにつき何度も呼び出す計算量が多いクラスメソッドを持つモデルを持っています。クラスメソッドをRailsでメモする方法は?

理想的には、1回のリクエストの間、結果をキャッシュしたいと思っています。

この状況では、レールのベストプラクティスは何ですか?

例:ヘルパーで次に

class MyClass < ActiveRecord::Base 
    def self.heavy_method; ... ; end 
end 

def helper 
    MyClass.heavy_method 
end 

このヘルパーは、あなただけの結果を変数に固執することはできません多くのビュー

+0

どのような種類のクラスですか?言い換えれば、それはどこに住んでいますか?クラスメソッド(インスタンスとは対照的に)であることが合理的ですか?どのように呼び出されますか?それは複数のオブジェクトにまたがっていますか? –

答えて

11

これは非常に一般的な解決策です。

class Klass 
    def self.memoized_expensive_method 
    @memoized_expensive_method_result ||= expensive_method 
    end 

    def self.expensive_method 
    # ... 
    end 
end 

次に、要求ごとにコードが再実行されるようにするには、コントローラでフィルタを使用できます。

class Klass 
    def self.reset_expensive_method_cache! 
    @memoized_expensive_method_result = nil 
    end 
end 

class ApplicationController 
    before_filter :reset_klass_expensive_method_cache 

    def reset_klass_expensive_method_cache 
    Klass.reset_expensive_method_cache! 
    end 
end 

キャッシュされた結果は、スレッド間で共有されるため、クラス変数で何かを格納するスレッド安全性の問題につながる可能性があることに注意してください。

アプリケーションで問題が発生する可能性がある場合は、クラス変数を使用する代わりに、スレッドにデータを格納することをお勧めします。それはおそらく代わりに、メモリ内の値を保つのRails.cache.fetchを使用するより良いソリューションです

:@unixcharlesへ

+0

偉大な答え。しかし、より偽のリセットは、すべてのクラスインスタンス変数に対処するでしょう。 'self.instance_variables.each {| v | instance_variable_set(v、nil)} ' – steel

+0

複数のスレッドを持つWebサーバーを使用する可能性が高いことに注意してください。異なるスレッドで同時に2つの要求が競合し、キャッシュを競合します。リクエストごとにキャッシュするには、このソリューションを使用することはお勧めできません。 [RequestStore](https://github.com/steveklabnik/request_store)の宝石はスレッドセーフです – JustinBull

1

に使用されていますか?汎用キャッシュの場合、memcacheが適切です。

より良い、より完全な回答を受け取るために、問題の詳細をご記入ください。

2

おかげで、ここで私が編集

class SomeClass 
    @lock = Mutex.new 

    after_save :clear_cached_calculation 

    class << self 
    def some_calculation 
     @lock.synchronize do 
     @calc ||= heavy_operation 
     end 
    end 

    def clear_calculation 
     @lock.synchronize do 
     @calc = nil 
     end 
    end 

    end 

private 

    def clear_cached_caculation 
    SomeClass.clear_calculation 
    end 
end 

をやって終わったものです。

関連する問題