0

複数のクラス変数を持つモジュールがあります。クラスが次のようにアクセスしようとしたときにのみ @@ 変数をインスタンス化するクラスレベルのゲッター実装を探しています

    module MyProducts
      @@products = nil

      def self.get_product(id)
        # i'm looking for a way that the first call on @@products does a find via AR                 like the following
        # @@products = Product.all
        # this module is in the lib directory of a Rails 2.3.5 app
        @@products.find do |prod|
          prod.id.eql?(id)
        end
      end
    end

モジュール全体を変更する必要がないように、これが透過的であることを探しています。同様の関数を持つ約 10 個のクラス レベル変数があり、すべて ActiveRecord .find 呼び出しの結果です。

4

2 に答える 2

0

クラス変数を使用しないのが最善です - それらは非常に奇妙な振る舞いをします。http://www.oreillynet.com/ruby/blog/2007/01/nubygems_dont_use_class_variab_1.htmlを参照して ください。

いずれの場合も、civar (クラス インスタンス変数) を使用できます。

module MyProducts
  class << self
    @products = nil
  end
end
于 2011-09-22T23:29:13.683 に答える
0

||=演算子を使用するだけです。nil右側の部分がorの場合にのみ、右側の式を評価します。false

def foo
  @@any ||= some_value
end

メソッドを初めて呼び出すと、 の結果で変数が初期化され、some_valueその後の呼び出しでは@@any、再計算する必要なく値が返されますsome_value

アップデート

これは、その方法を示す小さなスクリプトです。それを実行するとcomplex_function、2 つの print ステートメントが両方とも 1 を返すため、メソッドが 1 回呼び出されることがわかります。しかし、あなたのコメントから、あなたProductはアクティブなレコードであることがわかります。非常に非効率的になります(私の答えの最後の部分を読んでください)

#!/usr/bin/env ruby

module Foo
  def self.products
    @@products ||=complex_function
  end

  @@a = 0

  def self.complex_function
    @@a += 1
  end
end

p Foo.products
p Foo.products

更新終了

ただし、保存するアプローチProduct.allはかなり非効率的です。

  • 最初に、データベース内のすべての製品をフェッチします。これは、多くの製品がある場合に多くのメモリを消費する可能性があります
  • 次に、多くの製品がある場合、反復コードはデータベースよりもはるかに遅くなります

Product.find(id)メソッド全体を呼び出しに置き換えます。

Productモデルが db (おそらく ActiveResource) に保存されていない場合は、以前のコメントを無視してください。

また、 mattr_accessorとこの SO の質問ActiveSupport での mattr_accessor と cattr_accessor の違いを確認することもできますか?

最後に、メモ化と呼ばれる上記の手法について説明しているこの記事もご覧ください。

于 2011-09-22T22:32:04.617 に答える