0

我有一个具有多个类变量的模块。我正在寻找一个类级别的 getter 实现,它只会在类尝试访问它时实例化 @@ 变量,如下所示

    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

只需使用||=运算符。nil只有当正确的部分是或时,它才会评估正确的表达式false

def foo
  @@any ||= some_value
end

第一次调用该方法时,它将使用 的结果初始化变量some_value,随后的调用将返回该@@any值而无需重新计算some_value

更新

这是一个小脚本,向您展示如何做到这一点。如果您执行它,您会看到该方法complex_function被调用一次,因为两个打印语句都返回 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模型未存储在数据库中(可能是 ActiveResource),请忽略我之前的评论。

您还可以查看mattr_accessor和这个 SO question Difference between mattr_accessor and cattr_accessor in ActiveSupport?

最后还要看看这篇文章,它解释了上述称为 memoization 的技术

于 2011-09-22T22:32:04.617 回答
0

最好不要使用类变量——它们有非常奇怪的行为。见 http://www.oreillynet.com/ruby/blog/2007/01/nubygems_dont_use_class_variab_1.html

在每种情况下,您都可以使用 civars(类实例变量):

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